summaryrefslogtreecommitdiffstats
path: root/dom/canvas/test/webgl-conf/checkout/deqp/framework
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-04-07 19:33:14 +0000
commit36d22d82aa202bb199967e9512281e9a53db42c9 (patch)
tree105e8c98ddea1c1e4784a60a5a6410fa416be2de /dom/canvas/test/webgl-conf/checkout/deqp/framework
parentInitial commit. (diff)
downloadfirefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.tar.xz
firefox-esr-36d22d82aa202bb199967e9512281e9a53db42c9.zip
Adding upstream version 115.7.0esr.upstream/115.7.0esrupstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'dom/canvas/test/webgl-conf/checkout/deqp/framework')
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuBilinearImageCompare.js272
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuCompressedTexture.js967
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloat.js862
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloatFormat.js349
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFuzzyImageCompare.js338
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuImageCompare.js757
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuInterval.js609
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuLogImage.js163
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuMatrix.js354
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuMatrixUtil.js70
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuPixelFormat.js79
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuRGBA.js279
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuSkipList.js245
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuStringTemplate.js42
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuSurface.js184
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTestCase.js491
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexCompareVerifier.js1356
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexLookupVerifier.js2225
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexVerifierUtil.js265
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexture.js3636
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTextureUtil.js725
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deMath.js1143
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deRandom.js260
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deString.js111
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deUtil.js90
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluDrawUtil.js510
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluObjectWrapper.js117
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluPixelTransfer.js55
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderProgram.js488
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderUtil.js795
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluStrUtil.js166
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTexture.js380
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTextureUtil.js1025
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarType.js814
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarTypeUtil.js693
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/00_test_list.txt1
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/referencecontext.html32
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrGLContext.js231
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContext.js4986
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContextTest.js834
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceUtils.js317
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrShaderProgram.js336
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrDefs.js72
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrFragmentOperations.js583
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrGenericVector.js54
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrMultisamplePixelBufferAccess.js190
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrRenderState.js323
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrRenderer.js1274
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrShaders.js123
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrShadingContext.js113
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrUtil.js115
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrVertexAttrib.js641
-rw-r--r--dom/canvas/test/webgl-conf/checkout/deqp/framework/referencerenderer/rrVertexPacket.js101
53 files changed, 31241 insertions, 0 deletions
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuBilinearImageCompare.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuBilinearImageCompare.js
new file mode 100644
index 0000000000..bc23104c09
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuBilinearImageCompare.js
@@ -0,0 +1,272 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuBilinearImageCompare');
+goog.require('framework.common.tcuRGBA');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.delibs.debase.deMath');
+
+goog.scope(function() {
+
+ var tcuBilinearImageCompare = framework.common.tcuBilinearImageCompare;
+ var deMath = framework.delibs.debase.deMath;
+ var tcuTexture = framework.common.tcuTexture;
+ var tcuRGBA = framework.common.tcuRGBA;
+
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+ // for bilinear interpolation
+ /** @const {number} */ tcuBilinearImageCompare.NUM_SUBPIXEL_BITS = 8;
+
+ // Algorithm assumes that colors are packed to 32-bit values as dictated by
+ // tcu::RGBA::*_SHIFT values.
+
+ function UintRGBA8_R(color) {
+ return (color >> 24) & 0xff;
+ }
+ function UintRGBA8_G(color) {
+ return (color >> 16) & 0xff;
+ }
+ function UintRGBA8_B(color) {
+ return (color >> 8) & 0xff;
+ }
+ function UintRGBA8_A(color) {
+ return color & 0xff;
+ }
+
+ /**
+ * @param {number} fx1 deUint32
+ * @param {number} fy1 deUint32
+ * @param {number} p00 deUint8
+ * @param {number} p01 deUint8
+ * @param {number} p10 deUint8
+ * @param {number} p11 deUint8
+ * @return {number} deUint8
+ */
+ tcuBilinearImageCompare.interpolateChannel = function(fx1, fy1, p00, p01, p10, p11) {
+ /** @const {number} */ var fx0 = (1 << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS) - fx1;
+ /** @const {number} */ var fy0 = (1 << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS) - fy1;
+ /** @const {number} */
+ var half = 1 << (tcuBilinearImageCompare.NUM_SUBPIXEL_BITS * 2 - 1);
+ /** @const {number} */ var sum =
+ (fx0 * fy0 * p00) +
+ (fx1 * fy0 * p10) +
+ (fx0 * fy1 * p01) +
+ (fx1 * fy1 * p11);
+ /** @const {number} */
+ var rounded = (sum + half) >> (tcuBilinearImageCompare.NUM_SUBPIXEL_BITS * 2);
+
+ DE_ASSERT(deMath.deInRange32(rounded, 0, 0xff));
+ return rounded;
+ };
+
+ tcuBilinearImageCompare.compareUintRGBA8Threshold = function(a, b, thr) {
+ if (a == b)
+ return true;
+
+ return (Math.abs(UintRGBA8_R(a) - UintRGBA8_R(b)) <= thr.getRed() &&
+ Math.abs(UintRGBA8_G(a) - UintRGBA8_G(b)) <= thr.getGreen() &&
+ Math.abs(UintRGBA8_B(a) - UintRGBA8_B(b)) <= thr.getBlue() &&
+ Math.abs(UintRGBA8_A(a) - UintRGBA8_A(b)) <= thr.getAlpha());
+ };
+
+ /**
+ * @param {tcuTexture.RGBA8View} view
+ * @param {number} u
+ * @param {number} v
+ * @return {number}
+ */
+ tcuBilinearImageCompare.bilinearSampleUintRGBA8 = function(view, u, v) {
+ /** @type {number} */ var x0 = u >> tcuBilinearImageCompare.NUM_SUBPIXEL_BITS;
+ /** @type {number} */ var y0 = v >> tcuBilinearImageCompare.NUM_SUBPIXEL_BITS;
+ /** @type {number} */ var x1 = x0 + 1;
+ /** @type {number} */ var y1 = y0 + 1;
+
+ DE_ASSERT(x1 < view.getWidth());
+ DE_ASSERT(y1 < view.getHeight());
+
+ /** @type {number} */ var fx1 = u - (x0 << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS);
+ /** @type {number} */ var fy1 = v - (y0 << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS);
+
+ /** @type {Array<number>} */ var channelsP00 = view.readUintRGBA8(x0, y0);
+ /** @type {Array<number>} */ var channelsP10 = view.readUintRGBA8(x1, y0);
+ /** @type {Array<number>} */ var channelsP01 = view.readUintRGBA8(x0, y1);
+ /** @type {Array<number>} */ var channelsP11 = view.readUintRGBA8(x1, y1);
+
+ /** @type {number} */ var res = 0;
+
+ res = (tcuBilinearImageCompare.interpolateChannel(fx1, fy1, UintRGBA8_R(channelsP00),
+ UintRGBA8_R(channelsP01), UintRGBA8_R(channelsP10), UintRGBA8_R(channelsP11)) & 0xff) << 24;
+ res += (tcuBilinearImageCompare.interpolateChannel(fx1, fy1, UintRGBA8_G(channelsP00),
+ UintRGBA8_G(channelsP01), UintRGBA8_G(channelsP10), UintRGBA8_G(channelsP11)) & 0xff) << 16;
+ res += (tcuBilinearImageCompare.interpolateChannel(fx1, fy1, UintRGBA8_B(channelsP00),
+ UintRGBA8_B(channelsP01), UintRGBA8_B(channelsP10), UintRGBA8_B(channelsP11)) & 0xff) << 8;
+ res += tcuBilinearImageCompare.interpolateChannel(fx1, fy1, UintRGBA8_A(channelsP00),
+ UintRGBA8_A(channelsP01), UintRGBA8_A(channelsP10), UintRGBA8_A(channelsP11)) & 0xff;
+
+ return res;
+ };
+
+ /**
+ * @param {tcuTexture.RGBA8View} reference
+ * @param {tcuTexture.RGBA8View} result
+ * @param {tcuRGBA.RGBA} threshold
+ * @param {number} x
+ * @param {number} y
+ * @return {boolean}
+ */
+ tcuBilinearImageCompare.comparePixelRGBA8 = function(reference, result, threshold, x, y) {
+ /** @const {tcuRGBA.RGBA} */ var resPix = result.readUintRGBA8(x, y);
+
+ // Step 1: Compare result pixel to 3x3 neighborhood pixels in reference.
+ /** @const {number} */ var x0 = Math.max(x - 1, 0);
+ /** @const {number} */ var x1 = x;
+ /** @const {number} */
+ var x2 = Math.min(x + 1, reference.getWidth() - 1);
+ /** @const {number} */ var y0 = Math.max(y - 1, 0);
+ /** @const {number} */ var y1 = y;
+ /** @const {number} */
+ var y2 = Math.min(y + 1, reference.getHeight() - 1);
+
+ //tcuBilinearImageCompare.readRGBA8List (reference, x0, y0, x2, y2);
+
+ if (tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x1, y1), threshold) ||
+ tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x0, y1), threshold) ||
+ tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x2, y1), threshold) ||
+ tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x0, y0), threshold) ||
+ tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x1, y0), threshold) ||
+ tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x2, y0), threshold) ||
+ tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x0, y2), threshold) ||
+ tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x1, y2), threshold) ||
+ tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, reference.readUintRGBA8(x2, y2), threshold))
+ return true;
+
+ // Step 2: Compare using bilinear sampling.
+ // \todo [pyry] Optimize sample positions!
+ /** @const {Array<Array<number>>} */ var s_offsets = [
+ [226, 186],
+ [335, 235],
+ [279, 334],
+ [178, 272],
+ [112, 202],
+ [306, 117],
+ [396, 299],
+ [206, 382],
+ [146, 96],
+ [423, 155],
+ [361, 412],
+ [84, 339],
+ [48, 130],
+ [367, 43],
+ [455, 367],
+ [105, 439],
+ [83, 46],
+ [217, 24],
+ [461, 71],
+ [450, 459],
+ [239, 469],
+ [67, 267],
+ [459, 255],
+ [13, 416],
+ [10, 192],
+ [141, 502],
+ [503, 304],
+ [380, 506]
+ ];
+
+ for (var sampleNdx = 0; sampleNdx < s_offsets.length; sampleNdx++) {
+ /** @const {number} */
+ var u = ((x - 1) << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS) + s_offsets[sampleNdx][0];
+ /** @const {number} */
+ var v = ((y - 1) << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS) + s_offsets[sampleNdx][1];
+
+ if (!deMath.deInBounds32(u, 0, (reference.getWidth() - 1) << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS) ||
+ !deMath.deInBounds32(v, 0, (reference.getHeight() - 1) << tcuBilinearImageCompare.NUM_SUBPIXEL_BITS))
+ continue;
+
+ if (tcuBilinearImageCompare.compareUintRGBA8Threshold(resPix, tcuBilinearImageCompare.bilinearSampleUintRGBA8(reference, u, v), threshold))
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.RGBA8View} reference
+ * @param {tcuTexture.RGBA8View} result
+ * @param {tcuTexture.PixelBufferAccess} errorMask
+ * @param {tcuRGBA.RGBA} threshold
+ * @return {boolean}
+ */
+ tcuBilinearImageCompare.bilinearCompareRGBA8 = function(reference, result, errorMask, threshold) {
+ DE_ASSERT(reference.getFormat().isEqual(new tcuTexture.TextureFormat(
+ tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8)));
+ DE_ASSERT(result.getFormat().isEqual(new tcuTexture.TextureFormat(
+ tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8)));
+
+ // Clear error mask first to green (faster this way).
+ errorMask.clear([0.0, 1.0, 0.0, 1.0]);
+
+ /** @type {boolean} */ var allOk = true;
+
+ for (var y = 0; y < reference.getHeight(); y++) {
+ for (var x = 0; x < reference.getWidth(); x++) {
+ if (!tcuBilinearImageCompare.comparePixelRGBA8(reference, result, threshold, x, y) &&
+ !tcuBilinearImageCompare.comparePixelRGBA8(result, reference, threshold, x, y)) {
+ allOk = false;
+ errorMask.setPixel([1.0, 0.0, 0.0, 1.0], x, y);
+ }
+ }
+ }
+
+ return allOk;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {tcuTexture.PixelBufferAccess} errorMask
+ * @param {tcuRGBA.RGBA} threshold
+ * @return {boolean}
+ */
+ tcuBilinearImageCompare.bilinearCompare = function(reference, result, errorMask, threshold) {
+ assertMsgOptions(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight() && result.getDepth() == reference.getDepth(),
+ 'Reference and result images have different dimensions', false, true);
+
+ assertMsgOptions(errorMask.getWidth() == reference.getWidth() && errorMask.getHeight() == reference.getHeight() && errorMask.getDepth() == reference.getDepth(),
+ 'Reference and error mask images have different dimensions', false, true);
+
+ /** @type {boolean} */ var isEqual = reference.getFormat().isEqual(
+ new tcuTexture.TextureFormat(
+ tcuTexture.ChannelOrder.RGBA,
+ tcuTexture.ChannelType.UNORM_INT8));
+ if (isEqual) {
+ /** @type {tcuTexture.RGBA8View} */ var refView = new tcuTexture.RGBA8View(reference);
+ /** @type {tcuTexture.RGBA8View} */ var resView = new tcuTexture.RGBA8View(result);
+ return tcuBilinearImageCompare.bilinearCompareRGBA8(refView, resView, errorMask, threshold);
+ } else
+ throw new Error('Unsupported format for bilinear comparison');
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuCompressedTexture.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuCompressedTexture.js
new file mode 100644
index 0000000000..a309f81cfd
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuCompressedTexture.js
@@ -0,0 +1,967 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Map tcu::TextureFormat to GL pixel transfer format.
+ *
+ * Maps generic texture format description to GL pixel transfer format.
+ * If no mapping is found, throws tcu::InternalError.
+ *
+ * \param texFormat Generic texture format.
+ * \return GL pixel transfer format.
+ *//*--------------------------------------------------------------------*/
+'use strict';
+goog.provide('framework.common.tcuCompressedTexture');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.delibs.debase.deMath');
+
+goog.scope(function() {
+
+var tcuCompressedTexture = framework.common.tcuCompressedTexture;
+var tcuTexture = framework.common.tcuTexture;
+var deMath = framework.delibs.debase.deMath;
+
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+/**
+ * @enum
+ */
+tcuCompressedTexture.Format = {
+ ETC1_RGB8: 0,
+ EAC_R11: 1,
+ EAC_SIGNED_R11: 2,
+ EAC_RG11: 3,
+ EAC_SIGNED_RG11: 4,
+ ETC2_RGB8: 5,
+ ETC2_SRGB8: 6,
+ ETC2_RGB8_PUNCHTHROUGH_ALPHA1: 7,
+ ETC2_SRGB8_PUNCHTHROUGH_ALPHA1: 8,
+ ETC2_EAC_RGBA8: 9,
+ ETC2_EAC_SRGB8_ALPHA8: 10,
+
+ ASTC_4x4_RGBA: 11,
+ ASTC_5x4_RGBA: 12,
+ ASTC_5x5_RGBA: 13,
+ ASTC_6x5_RGBA: 14,
+ ASTC_6x6_RGBA: 15,
+ ASTC_8x5_RGBA: 16,
+ ASTC_8x6_RGBA: 17,
+ ASTC_8x8_RGBA: 18,
+ ASTC_10x5_RGBA: 19,
+ ASTC_10x6_RGBA: 20,
+ ASTC_10x8_RGBA: 21,
+ ASTC_10x10_RGBA: 22,
+ ASTC_12x10_RGBA: 23,
+ ASTC_12x12_RGBA: 24,
+ ASTC_4x4_SRGB8_ALPHA8: 25,
+ ASTC_5x4_SRGB8_ALPHA8: 26,
+ ASTC_5x5_SRGB8_ALPHA8: 27,
+ ASTC_6x5_SRGB8_ALPHA8: 28,
+ ASTC_6x6_SRGB8_ALPHA8: 29,
+ ASTC_8x5_SRGB8_ALPHA8: 30,
+ ASTC_8x6_SRGB8_ALPHA8: 31,
+ ASTC_8x8_SRGB8_ALPHA8: 32,
+ ASTC_10x5_SRGB8_ALPHA8: 33,
+ ASTC_10x6_SRGB8_ALPHA8: 34,
+ ASTC_10x8_SRGB8_ALPHA8: 35,
+ ASTC_10x10_SRGB8_ALPHA8: 36,
+ ASTC_12x10_SRGB8_ALPHA8: 37,
+ ASTC_12x12_SRGB8_ALPHA8: 38
+};
+
+tcuCompressedTexture.divRoundUp = function(a, b) {
+ return Math.floor(a / b) + ((a % b) ? 1 : 0);
+};
+
+tcuCompressedTexture.isEtcFormat = function(fmt) {
+ // WebGL2 supports ETC2 and EAC formats
+ switch (fmt) {
+ // case tcuCompressedTexture.Format.ETC1_RGB8:
+ case tcuCompressedTexture.Format.EAC_R11:
+ case tcuCompressedTexture.Format.EAC_SIGNED_R11:
+ case tcuCompressedTexture.Format.EAC_RG11:
+ case tcuCompressedTexture.Format.EAC_SIGNED_RG11:
+ case tcuCompressedTexture.Format.ETC2_RGB8:
+ case tcuCompressedTexture.Format.ETC2_SRGB8:
+ case tcuCompressedTexture.Format.ETC2_RGB8_PUNCHTHROUGH_ALPHA1:
+ case tcuCompressedTexture.Format.ETC2_SRGB8_PUNCHTHROUGH_ALPHA1:
+ case tcuCompressedTexture.Format.ETC2_EAC_RGBA8:
+ case tcuCompressedTexture.Format.ETC2_EAC_SRGB8_ALPHA8:
+ return true;
+
+ default:
+ return false;
+ }
+};
+
+tcuCompressedTexture.etcDecompressInternal = function() {
+
+var ETC2_BLOCK_WIDTH = 4;
+var ETC2_BLOCK_HEIGHT = 4;
+var ETC2_UNCOMPRESSED_PIXEL_SIZE_A8 = 1;
+var ETC2_UNCOMPRESSED_PIXEL_SIZE_R11 = 2;
+var ETC2_UNCOMPRESSED_PIXEL_SIZE_RG11 = 4;
+var ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8 = 3;
+var ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8 = 4;
+var ETC2_UNCOMPRESSED_BLOCK_SIZE_A8 = ETC2_BLOCK_WIDTH * ETC2_BLOCK_HEIGHT * ETC2_UNCOMPRESSED_PIXEL_SIZE_A8;
+var ETC2_UNCOMPRESSED_BLOCK_SIZE_R11 = ETC2_BLOCK_WIDTH * ETC2_BLOCK_HEIGHT * ETC2_UNCOMPRESSED_PIXEL_SIZE_R11;
+var ETC2_UNCOMPRESSED_BLOCK_SIZE_RG11 = ETC2_BLOCK_WIDTH * ETC2_BLOCK_HEIGHT * ETC2_UNCOMPRESSED_PIXEL_SIZE_RG11;
+var ETC2_UNCOMPRESSED_BLOCK_SIZE_RGB8 = ETC2_BLOCK_WIDTH * ETC2_BLOCK_HEIGHT * ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8;
+var ETC2_UNCOMPRESSED_BLOCK_SIZE_RGBA8 = ETC2_BLOCK_WIDTH * ETC2_BLOCK_HEIGHT * ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8;
+
+/**
+ * @param {ArrayBuffer} src Source ArrayBuffer
+ * @return {Uint8Array}
+ */
+var get64BitBlock = function(src, blockNdx) {
+ var block = new Uint8Array(src, blockNdx * 8, 8);
+ return block;
+};
+
+/**
+ * @param {ArrayBuffer} src Source ArrayBuffer
+ * Return the first 64 bits of a 128 bit block.
+ */
+var get128BitBlockStart = function(src, blockNdx) {
+ return get64BitBlock(src, 2 * blockNdx);
+};
+
+/**
+ * @param {ArrayBuffer} src Source ArrayBuffer
+ * Return the last 64 bits of a 128 bit block.
+ */
+var get128BitBlockEnd = function(src, blockNdx) {
+ return get64BitBlock(src, 2 * blockNdx + 1);
+};
+
+var mask8 = function(src, low, high) {
+ if (low > 7 || high < 0)
+ return {
+ value: 0,
+ bits: 0
+ };
+
+ var numBits = high - low + 1;
+ var mask = (1 << numBits) - 1;
+
+ return {
+ value: (src >> low) & mask,
+ bits: numBits
+ };
+};
+
+var getBits64 = function(src, low, high) {
+ var result = 0;
+ var bits = 0;
+ var lowIndex = low;
+ var highIndex = high;
+ for (var i = 7; i >= 0; i--) {
+ var v = mask8(src[i], Math.max(0, lowIndex), Math.min(7, highIndex));
+ lowIndex = lowIndex - 8;
+ highIndex = highIndex - 8;
+ result = result | (v.value << bits);
+ bits = v.bits;
+ }
+ return result;
+};
+
+var getBit64 = function(src, bit) {
+ return getBits64(src, bit, bit);
+};
+
+var extendSigned3To8 = function(src) {
+ var isNeg = (src & (1 << 2)) != 0;
+ var val = isNeg ? src - 8 : src;
+ return val;
+};
+
+var extend4To8 = function(src) {
+ return src * 255 / 15;
+};
+
+var extend5To8 = function(src) {
+ return src * 255 / 31;
+};
+
+var extend6To8 = function(src) {
+ return src * 255 / 63;
+};
+
+var extend7To8 = function(src) {
+ return src * 255 / 127;
+};
+
+var extend11To16 = function(src) {
+ return src * 32.015144;
+};
+
+var extend11To16WithSign = function(src) {
+ if (src < 0)
+ return -extend11To16(-src);
+ else
+ return extend11To16(src);
+};
+
+/**
+ * @param { (Uint16Array|Int16Array) } dst
+ * @param {Uint8Array} src
+ * @param {boolean} signedMode
+ */
+var decompressEAC11Block = function(dst, src, signedMode) {
+ var modifierTable = [
+ [-3, -6, -9, -15, 2, 5, 8, 14],
+ [-3, -7, -10, -13, 2, 6, 9, 12],
+ [-2, -5, -8, -13, 1, 4, 7, 12],
+ [-2, -4, -6, -13, 1, 3, 5, 12],
+ [-3, -6, -8, -12, 2, 5, 7, 11],
+ [-3, -7, -9, -11, 2, 6, 8, 10],
+ [-4, -7, -8, -11, 3, 6, 7, 10],
+ [-3, -5, -8, -11, 2, 4, 7, 10],
+ [-2, -6, -8, -10, 1, 5, 7, 9],
+ [-2, -5, -8, -10, 1, 4, 7, 9],
+ [-2, -4, -8, -10, 1, 3, 7, 9],
+ [-2, -5, -7, -10, 1, 4, 6, 9],
+ [-3, -4, -7, -10, 2, 3, 6, 9],
+ [-1, -2, -3, -10, 0, 1, 2, 9],
+ [-4, -6, -8, -9, 3, 5, 7, 8],
+ [-3, -5, -7, -9, 2, 4, 6, 8]
+ ];
+
+ var multiplier = getBits64(src, 52, 55);
+ var tableNdx = getBits64(src, 48, 51);
+ var baseCodeword = getBits64(src, 56, 63);
+
+ if (signedMode) {
+ if (baseCodeword > 127)
+ baseCodeword -= 256;
+ if (baseCodeword == -128)
+ baseCodeword = -127;
+ }
+
+ var pixelNdx = 0;
+ for (var x = 0; x < ETC2_BLOCK_WIDTH; x++) {
+ for (var y = 0; y < ETC2_BLOCK_HEIGHT; y++) {
+ var dstOffset = (y * ETC2_BLOCK_WIDTH + x);
+ var pixelBitNdx = 45 - 3 * pixelNdx;
+ var modifierNdx = (getBit64(src, pixelBitNdx + 2) << 2) | (getBit64(src, pixelBitNdx + 1) << 1) | getBit64(src, pixelBitNdx);
+ var modifier = modifierTable[tableNdx][modifierNdx];
+
+ if (signedMode) {
+ if (multiplier != 0)
+ dst[dstOffset] = deMath.clamp(baseCodeword * 8 + multiplier * modifier * 8, -1023, 1023);
+ else
+ dst[dstOffset] = deMath.clamp(baseCodeword * 8 + modifier, -1023, 1023);
+ } else {
+ if (multiplier != 0)
+ dst[dstOffset] = deMath.clamp(baseCodeword * 8 + 4 + multiplier * modifier * 8, 0, 2047);
+ else
+ dst[dstOffset] = deMath.clamp(baseCodeword * 8 + 4 + modifier, 0, 2047);
+ }
+ pixelNdx++;
+ }
+ }
+};
+
+var decompressEAC_R11 = function(/*const tcu::PixelBufferAccess&*/ dst, width, height, src, signedMode) {
+ /** @const */ var numBlocksX = tcuCompressedTexture.divRoundUp(width, 4);
+ /** @const */ var numBlocksY = tcuCompressedTexture.divRoundUp(height, 4);
+ var dstPtr;
+ var dstRowPitch = dst.getRowPitch();
+ var dstPixelSize = ETC2_UNCOMPRESSED_PIXEL_SIZE_R11;
+ var uncompressedBlockArray = new ArrayBuffer(ETC2_UNCOMPRESSED_BLOCK_SIZE_R11);
+ var uncompressedBlock16;
+ if (signedMode) {
+ dstPtr = new Int16Array(dst.m_data);
+ uncompressedBlock16 = new Int16Array(uncompressedBlockArray);
+ } else {
+ dstPtr = new Uint16Array(dst.m_data);
+ uncompressedBlock16 = new Uint16Array(uncompressedBlockArray);
+ }
+
+ for (var blockY = 0; blockY < numBlocksY; blockY++) {
+ for (var blockX = 0; blockX < numBlocksX; blockX++) {
+ /*const deUint64*/ var compressedBlock = get64BitBlock(src, blockY * numBlocksX + blockX);
+
+ // Decompress.
+ decompressEAC11Block(uncompressedBlock16, compressedBlock, signedMode);
+
+ // Write to dst.
+ var baseX = blockX * ETC2_BLOCK_WIDTH;
+ var baseY = blockY * ETC2_BLOCK_HEIGHT;
+ for (var y = 0; y < Math.min(ETC2_BLOCK_HEIGHT, height - baseY); y++) {
+ for (var x = 0; x < Math.min(ETC2_BLOCK_WIDTH, width - baseX); x++) {
+ DE_ASSERT(ETC2_UNCOMPRESSED_PIXEL_SIZE_R11 == 2);
+
+ if (signedMode) {
+ var srcIndex = y * ETC2_BLOCK_WIDTH + x;
+ var dstIndex = (baseY + y) * dstRowPitch / dstPixelSize + baseX + x;
+
+ dstPtr[dstIndex] = extend11To16WithSign(uncompressedBlock16[srcIndex]);
+ } else {
+ var srcIndex = y * ETC2_BLOCK_WIDTH + x;
+ var dstIndex = (baseY + y) * dstRowPitch / dstPixelSize + baseX + x;
+
+ dstPtr[dstIndex] = extend11To16(uncompressedBlock16[srcIndex]);
+ }
+ }
+ }
+ }
+ }
+};
+
+var decompressEAC_RG11 = function(/*const tcu::PixelBufferAccess&*/ dst, width, height, src, signedMode) {
+ /** @const */ var numBlocksX = tcuCompressedTexture.divRoundUp(width, 4);
+ /** @const */ var numBlocksY = tcuCompressedTexture.divRoundUp(height, 4);
+ var dstPtr;
+ var dstRowPitch = dst.getRowPitch();
+ var dstPixelSize = ETC2_UNCOMPRESSED_PIXEL_SIZE_RG11;
+ var uncompressedBlockArrayR = new ArrayBuffer(ETC2_UNCOMPRESSED_BLOCK_SIZE_R11);
+ var uncompressedBlockArrayG = new ArrayBuffer(ETC2_UNCOMPRESSED_BLOCK_SIZE_R11);
+ var uncompressedBlockR16;
+ var uncompressedBlockG16;
+ if (signedMode) {
+ dstPtr = new Int16Array(dst.m_data);
+ uncompressedBlockR16 = new Int16Array(uncompressedBlockArrayR);
+ uncompressedBlockG16 = new Int16Array(uncompressedBlockArrayG);
+ } else {
+ dstPtr = new Uint16Array(dst.m_data);
+ uncompressedBlockR16 = new Uint16Array(uncompressedBlockArrayR);
+ uncompressedBlockG16 = new Uint16Array(uncompressedBlockArrayG);
+ }
+
+ for (var blockY = 0; blockY < numBlocksY; blockY++) {
+ for (var blockX = 0; blockX < numBlocksX; blockX++) {
+ /*const deUint64*/ var compressedBlockR = get128BitBlockStart(src, blockY * numBlocksX + blockX);
+ /*const deUint64*/ var compressedBlockG = get128BitBlockEnd(src, blockY * numBlocksX + blockX);
+
+ // Decompress.
+ decompressEAC11Block(uncompressedBlockR16, compressedBlockR, signedMode);
+ decompressEAC11Block(uncompressedBlockG16, compressedBlockG, signedMode);
+
+ // Write to dst.
+ var baseX = blockX * ETC2_BLOCK_WIDTH;
+ var baseY = blockY * ETC2_BLOCK_HEIGHT;
+ for (var y = 0; y < Math.min(ETC2_BLOCK_HEIGHT, height - baseY); y++) {
+ for (var x = 0; x < Math.min(ETC2_BLOCK_WIDTH, width - baseX); x++) {
+ DE_ASSERT(ETC2_UNCOMPRESSED_PIXEL_SIZE_RG11 == 4);
+
+ if (signedMode) {
+ var srcIndex = y * ETC2_BLOCK_WIDTH + x;
+ var dstIndex = 2 * ((baseY + y) * dstRowPitch / dstPixelSize + baseX + x);
+
+ dstPtr[dstIndex] = extend11To16WithSign(uncompressedBlockR16[srcIndex]);
+ dstPtr[dstIndex + 1] = extend11To16WithSign(uncompressedBlockG16[srcIndex]);
+ } else {
+ var srcIndex = y * ETC2_BLOCK_WIDTH + x;
+ var dstIndex = 2 * ((baseY + y) * dstRowPitch / dstPixelSize + baseX + x);
+
+ dstPtr[dstIndex] = extend11To16(uncompressedBlockR16[srcIndex]);
+ dstPtr[dstIndex + 1] = extend11To16(uncompressedBlockG16[srcIndex]);
+ }
+ }
+ }
+ }
+ }
+};
+
+// if alphaMode is true, do PUNCHTHROUGH and store alpha to alphaDst; otherwise do ordinary ETC2 RGB8.
+/**
+ * @param {Uint8Array} dst Destination array
+ * @param {Uint8Array} src Source array
+ * @param {Uint8Array} alphaDst Optional Alpha output channel
+ */
+var decompressETC2Block = function(dst, src, alphaDst, alphaMode) {
+ /**
+ * enum
+ */
+ var Etc2Mode = {
+ MODE_INDIVIDUAL: 0,
+ MODE_DIFFERENTIAL: 1,
+ MODE_T: 2,
+ MODE_H: 3,
+ MODE_PLANAR: 4
+ };
+
+ var diffOpaqueBit = getBit64(src, 33);
+ var selBR = getBits64(src, 59, 63); // 5 bits.
+ var selBG = getBits64(src, 51, 55);
+ var selBB = getBits64(src, 43, 47);
+ var selDR = extendSigned3To8(getBits64(src, 56, 58)); // 3 bits.
+ var selDG = extendSigned3To8(getBits64(src, 48, 50));
+ var selDB = extendSigned3To8(getBits64(src, 40, 42));
+
+ var mode;
+
+ if (!alphaMode && diffOpaqueBit == 0)
+ mode = Etc2Mode.MODE_INDIVIDUAL;
+ else if (!deMath.deInRange32(selBR + selDR, 0, 31))
+ mode = Etc2Mode.MODE_T;
+ else if (!deMath.deInRange32(selBG + selDG, 0, 31))
+ mode = Etc2Mode.MODE_H;
+ else if (!deMath.deInRange32(selBB + selDB, 0, 31))
+ mode = Etc2Mode.MODE_PLANAR;
+ else
+ mode = Etc2Mode.MODE_DIFFERENTIAL;
+
+ if (mode == Etc2Mode.MODE_INDIVIDUAL || mode == Etc2Mode.MODE_DIFFERENTIAL) {
+ // Individual and differential modes have some steps in common, handle them here.
+ var modifierTable = [
+ // 00 01 10 11
+ [2, 8, -2, -8],
+ [5, 17, -5, -17],
+ [9, 29, -9, -29],
+ [13, 42, -13, -42],
+ [18, 60, -18, -60],
+ [24, 80, -24, -80],
+ [33, 106, -33, -106],
+ [47, 183, -47, -183]
+ ];
+
+ var flipBit = getBit64(src, 32);
+ var table = [getBits64(src, 37, 39), getBits64(src, 34, 36)];
+ var baseR = [];
+ var baseG = [];
+ var baseB = [];
+
+ if (mode == Etc2Mode.MODE_INDIVIDUAL) {
+ // Individual mode, initial values.
+ baseR[0] = extend4To8(getBits64(src, 60, 63));
+ baseR[1] = extend4To8(getBits64(src, 56, 59));
+ baseG[0] = extend4To8(getBits64(src, 52, 55));
+ baseG[1] = extend4To8(getBits64(src, 48, 51));
+ baseB[0] = extend4To8(getBits64(src, 44, 47));
+ baseB[1] = extend4To8(getBits64(src, 40, 43));
+ } else {
+ // Differential mode, initial values.
+ baseR[0] = extend5To8(selBR);
+ baseG[0] = extend5To8(selBG);
+ baseB[0] = extend5To8(selBB);
+
+ baseR[1] = extend5To8((selBR + selDR));
+ baseG[1] = extend5To8((selBG + selDG));
+ baseB[1] = extend5To8((selBB + selDB));
+ }
+
+ // Write final pixels for individual or differential mode.
+ var pixelNdx = 0;
+ for (var x = 0; x < ETC2_BLOCK_WIDTH; x++) {
+ for (var y = 0; y < ETC2_BLOCK_HEIGHT; y++, pixelNdx++) {
+ var dstOffset = (y * ETC2_BLOCK_WIDTH + x) * ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8;
+ var subBlock = ((flipBit ? y : x) >= 2) ? 1 : 0;
+ var tableNdx = table[subBlock];
+ var modifierNdx = (getBit64(src, 16 + pixelNdx) << 1) | getBit64(src, pixelNdx);
+ var alphaDstOffset = (y * ETC2_BLOCK_WIDTH + x) * ETC2_UNCOMPRESSED_PIXEL_SIZE_A8; // Only needed for PUNCHTHROUGH version.
+
+ // If doing PUNCHTHROUGH version (alphaMode), opaque bit may affect colors.
+ if (alphaMode && diffOpaqueBit == 0 && modifierNdx == 2) {
+ dst[dstOffset + 0] = 0;
+ dst[dstOffset + 1] = 0;
+ dst[dstOffset + 2] = 0;
+ alphaDst[alphaDstOffset] = 0;
+ } else {
+ var modifier;
+
+ // PUNCHTHROUGH version and opaque bit may also affect modifiers.
+ if (alphaMode && diffOpaqueBit == 0 && (modifierNdx == 0 || modifierNdx == 2))
+ modifier = 0;
+ else
+ modifier = modifierTable[tableNdx][modifierNdx];
+
+ dst[dstOffset + 0] = deMath.clamp(baseR[subBlock] + modifier, 0, 255);
+ dst[dstOffset + 1] = deMath.clamp(baseG[subBlock] + modifier, 0, 255);
+ dst[dstOffset + 2] = deMath.clamp(baseB[subBlock] + modifier, 0, 255);
+
+ if (alphaMode)
+ alphaDst[alphaDstOffset] = 255;
+ }
+ }
+ }
+ } else if (mode == Etc2Mode.MODE_T || mode == Etc2Mode.MODE_H) {
+ // T and H modes have some steps in common, handle them here.
+ var distTable = [3, 6, 11, 16, 23, 32, 41, 64];
+
+ var paintR = [];
+ var paintG = [];
+ var paintB = [];
+
+ if (mode == Etc2Mode.MODE_T) {
+ // T mode, calculate paint values.
+ var R1a = getBits64(src, 59, 60);
+ var R1b = getBits64(src, 56, 57);
+ var G1 = getBits64(src, 52, 55);
+ var B1 = getBits64(src, 48, 51);
+ var R2 = getBits64(src, 44, 47);
+ var G2 = getBits64(src, 40, 43);
+ var B2 = getBits64(src, 36, 39);
+ var distNdx = (getBits64(src, 34, 35) << 1) | getBit64(src, 32);
+ var dist = distTable[distNdx];
+
+ paintR[0] = extend4To8((R1a << 2) | R1b);
+ paintG[0] = extend4To8(G1);
+ paintB[0] = extend4To8(B1);
+ paintR[2] = extend4To8(R2);
+ paintG[2] = extend4To8(G2);
+ paintB[2] = extend4To8(B2);
+ paintR[1] = deMath.clamp(paintR[2] + dist, 0, 255);
+ paintG[1] = deMath.clamp(paintG[2] + dist, 0, 255);
+ paintB[1] = deMath.clamp(paintB[2] + dist, 0, 255);
+ paintR[3] = deMath.clamp(paintR[2] - dist, 0, 255);
+ paintG[3] = deMath.clamp(paintG[2] - dist, 0, 255);
+ paintB[3] = deMath.clamp(paintB[2] - dist, 0, 255);
+ } else {
+ // H mode, calculate paint values.
+ var R1 = getBits64(src, 59, 62);
+ var G1a = getBits64(src, 56, 58);
+ var G1b = getBit64(src, 52);
+ var B1a = getBit64(src, 51);
+ var B1b = getBits64(src, 47, 49);
+ var R2 = getBits64(src, 43, 46);
+ var G2 = getBits64(src, 39, 42);
+ var B2 = getBits64(src, 35, 38);
+ var baseR = [];
+ var baseG = [];
+ var baseB = [];
+ var baseValue = [];
+ var distNdx;
+ var dist;
+
+ baseR[0] = extend4To8(R1);
+ baseG[0] = extend4To8((G1a << 1) | G1b);
+ baseB[0] = extend4To8((B1a << 3) | B1b);
+ baseR[1] = extend4To8(R2);
+ baseG[1] = extend4To8(G2);
+ baseB[1] = extend4To8(B2);
+ baseValue[0] = ((baseR[0]) << 16) | ((baseG[0]) << 8) | baseB[0];
+ baseValue[1] = ((baseR[1]) << 16) | ((baseG[1]) << 8) | baseB[1];
+ distNdx = (getBit64(src, 34) << 2) | (getBit64(src, 32) << 1);
+ if (baseValue[0] >= baseValue[1])
+ distNdx += 1;
+ dist = distTable[distNdx];
+
+ paintR[0] = deMath.clamp(baseR[0] + dist, 0, 255);
+ paintG[0] = deMath.clamp(baseG[0] + dist, 0, 255);
+ paintB[0] = deMath.clamp(baseB[0] + dist, 0, 255);
+ paintR[1] = deMath.clamp(baseR[0] - dist, 0, 255);
+ paintG[1] = deMath.clamp(baseG[0] - dist, 0, 255);
+ paintB[1] = deMath.clamp(baseB[0] - dist, 0, 255);
+ paintR[2] = deMath.clamp(baseR[1] + dist, 0, 255);
+ paintG[2] = deMath.clamp(baseG[1] + dist, 0, 255);
+ paintB[2] = deMath.clamp(baseB[1] + dist, 0, 255);
+ paintR[3] = deMath.clamp(baseR[1] - dist, 0, 255);
+ paintG[3] = deMath.clamp(baseG[1] - dist, 0, 255);
+ paintB[3] = deMath.clamp(baseB[1] - dist, 0, 255);
+ }
+
+ // Write final pixels for T or H mode.
+ var pixelNdx = 0;
+ for (var x = 0; x < ETC2_BLOCK_WIDTH; x++) {
+ for (var y = 0; y < ETC2_BLOCK_HEIGHT; y++, pixelNdx++) {
+ var dstOffset = (y * ETC2_BLOCK_WIDTH + x) * ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8;
+ var paintNdx = (getBit64(src, 16 + pixelNdx) << 1) | getBit64(src, pixelNdx);
+ var alphaDstOffset = (y * ETC2_BLOCK_WIDTH + x) * ETC2_UNCOMPRESSED_PIXEL_SIZE_A8; // Only needed for PUNCHTHROUGH version.
+
+ if (alphaMode && diffOpaqueBit == 0 && paintNdx == 2) {
+ dst[dstOffset + 0] = 0;
+ dst[dstOffset + 1] = 0;
+ dst[dstOffset + 2] = 0;
+ alphaDst[alphaDstOffset] = 0;
+ } else {
+ dst[dstOffset + 0] = deMath.clamp(paintR[paintNdx], 0, 255);
+ dst[dstOffset + 1] = deMath.clamp(paintG[paintNdx], 0, 255);
+ dst[dstOffset + 2] = deMath.clamp(paintB[paintNdx], 0, 255);
+
+ if (alphaMode)
+ alphaDst[alphaDstOffset] = 255;
+ }
+ }
+ }
+ } else {
+ // Planar mode.
+ var GO1 = getBit64(src, 56);
+ var GO2 = getBits64(src, 49, 54);
+ var BO1 = getBit64(src, 48);
+ var BO2 = getBits64(src, 43, 44);
+ var BO3 = getBits64(src, 39, 41);
+ var RH1 = getBits64(src, 34, 38);
+ var RH2 = getBit64(src, 32);
+ var RO = extend6To8(getBits64(src, 57, 62));
+ var GO = extend7To8((GO1 << 6) | GO2);
+ var BO = extend6To8((BO1 << 5) | (BO2 << 3) | BO3);
+ var RH = extend6To8((RH1 << 1) | RH2);
+ var GH = extend7To8(getBits64(src, 25, 31));
+ var BH = extend6To8(getBits64(src, 19, 24));
+ var RV = extend6To8(getBits64(src, 13, 18));
+ var GV = extend7To8(getBits64(src, 6, 12));
+ var BV = extend6To8(getBits64(src, 0, 5));
+
+ // Write final pixels for planar mode.
+ for (var y = 0; y < 4; y++) {
+ for (var x = 0; x < 4; x++) {
+ var dstOffset = (y * ETC2_BLOCK_WIDTH + x) * ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8;
+ var unclampedR = (x * (RH - RO) + y * (RV - RO) + 4 * RO + 2) / 4;
+ var unclampedG = (x * (GH - GO) + y * (GV - GO) + 4 * GO + 2) / 4;
+ var unclampedB = (x * (BH - BO) + y * (BV - BO) + 4 * BO + 2) / 4;
+ var alphaDstOffset = (y * ETC2_BLOCK_WIDTH + x) * ETC2_UNCOMPRESSED_PIXEL_SIZE_A8; // Only needed for PUNCHTHROUGH version.
+
+ dst[dstOffset + 0] = deMath.clamp(unclampedR, 0, 255);
+ dst[dstOffset + 1] = deMath.clamp(unclampedG, 0, 255);
+ dst[dstOffset + 2] = deMath.clamp(unclampedB, 0, 255);
+
+ if (alphaMode)
+ alphaDst[alphaDstOffset] = 255;
+ }
+ }
+ }
+};
+
+var decompressEAC8Block = function(dst, src) {
+ var modifierTable = [
+ [-3, -6, -9, -15, 2, 5, 8, 14],
+ [-3, -7, -10, -13, 2, 6, 9, 12],
+ [-2, -5, -8, -13, 1, 4, 7, 12],
+ [-2, -4, -6, -13, 1, 3, 5, 12],
+ [-3, -6, -8, -12, 2, 5, 7, 11],
+ [-3, -7, -9, -11, 2, 6, 8, 10],
+ [-4, -7, -8, -11, 3, 6, 7, 10],
+ [-3, -5, -8, -11, 2, 4, 7, 10],
+ [-2, -6, -8, -10, 1, 5, 7, 9],
+ [-2, -5, -8, -10, 1, 4, 7, 9],
+ [-2, -4, -8, -10, 1, 3, 7, 9],
+ [-2, -5, -7, -10, 1, 4, 6, 9],
+ [-3, -4, -7, -10, 2, 3, 6, 9],
+ [-1, -2, -3, -10, 0, 1, 2, 9],
+ [-4, -6, -8, -9, 3, 5, 7, 8],
+ [-3, -5, -7, -9, 2, 4, 6, 8]
+ ];
+
+ var baseCodeword = getBits64(src, 56, 63);
+ var multiplier = getBits64(src, 52, 55);
+ var tableNdx = getBits64(src, 48, 51);
+
+ var pixelNdx = 0;
+ for (var x = 0; x < ETC2_BLOCK_WIDTH; x++) {
+ for (var y = 0; y < ETC2_BLOCK_HEIGHT; y++, pixelNdx++) {
+ var dstOffset = (y * ETC2_BLOCK_WIDTH + x);
+ var pixelBitNdx = 45 - 3 * pixelNdx;
+ var modifierNdx = (getBit64(src, pixelBitNdx + 2) << 2) | (getBit64(src, pixelBitNdx + 1) << 1) | getBit64(src, pixelBitNdx);
+ var modifier = modifierTable[tableNdx][modifierNdx];
+
+ dst[dstOffset] = deMath.clamp(baseCodeword + multiplier * modifier, 0, 255);
+ }
+ }
+};
+
+var decompressETC2 = function(/*const tcu::PixelBufferAccess&*/ dst, width, height, src) {
+ var numBlocksX = tcuCompressedTexture.divRoundUp(width, 4);
+ var numBlocksY = tcuCompressedTexture.divRoundUp(height, 4);
+ var dstPtr = new Uint8Array(dst.m_data);
+ var dstRowPitch = dst.getRowPitch();
+ var dstPixelSize = ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8;
+ var uncompressedBlockArray = new ArrayBuffer(ETC2_UNCOMPRESSED_BLOCK_SIZE_RGB8);
+ var uncompressedBlock = new Uint8Array(uncompressedBlockArray);
+
+ for (var blockY = 0; blockY < numBlocksY; blockY++) {
+ for (var blockX = 0; blockX < numBlocksX; blockX++) {
+ var compressedBlock = get64BitBlock(src, blockY * numBlocksX + blockX);
+
+ // Decompress.
+ decompressETC2Block(uncompressedBlock, compressedBlock, null, false);
+
+ // Write to dst.
+ var baseX = blockX * ETC2_BLOCK_WIDTH;
+ var baseY = blockY * ETC2_BLOCK_HEIGHT;
+ for (var y = 0; y < Math.min(ETC2_BLOCK_HEIGHT, height - baseY); y++) {
+ for (var x = 0; x < Math.min(ETC2_BLOCK_WIDTH, width - baseX); x++) {
+ var srcIndex = (y * ETC2_BLOCK_WIDTH + x) * ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8;
+ var dstIndex = (baseY + y) * dstRowPitch + (baseX + x) * dstPixelSize;
+
+ for (var i = 0; i < ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8; i++)
+ dstPtr[dstIndex + i] = uncompressedBlock[srcIndex + i];
+ }
+ }
+ }
+ }
+};
+
+var decompressETC2_EAC_RGBA8 = function(/*const tcu::PixelBufferAccess&*/ dst, width, height, src) {
+ var numBlocksX = tcuCompressedTexture.divRoundUp(width, 4);
+ var numBlocksY = tcuCompressedTexture.divRoundUp(height, 4);
+ var dstPtr = new Uint8Array(dst.m_data);
+ var dstRowPitch = dst.getRowPitch();
+ var dstPixelSize = ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8;
+ var uncompressedBlockArray = new ArrayBuffer(ETC2_UNCOMPRESSED_BLOCK_SIZE_RGB8);
+ var uncompressedBlock = new Uint8Array(uncompressedBlockArray);
+ var uncompressedBlockAlphaArray = new ArrayBuffer(ETC2_UNCOMPRESSED_BLOCK_SIZE_A8);
+ var uncompressedBlockAlpha = new Uint8Array(uncompressedBlockAlphaArray);
+
+ for (var blockY = 0; blockY < numBlocksY; blockY++) {
+ for (var blockX = 0; blockX < numBlocksX; blockX++) {
+ var compressedBlockAlpha = get128BitBlockStart(src, blockY * numBlocksX + blockX);
+ var compressedBlockRGB = get128BitBlockEnd(src, blockY * numBlocksX + blockX);
+
+ // Decompress.
+ decompressETC2Block(uncompressedBlock, compressedBlockRGB, null, false);
+ decompressEAC8Block(uncompressedBlockAlpha, compressedBlockAlpha);
+
+ // Write to dst.
+ var baseX = blockX * ETC2_BLOCK_WIDTH;
+ var baseY = blockY * ETC2_BLOCK_HEIGHT;
+ for (var y = 0; y < Math.min(ETC2_BLOCK_HEIGHT, height - baseY); y++) {
+ for (var x = 0; x < Math.min(ETC2_BLOCK_WIDTH, width - baseX); x++) {
+ var srcIndex = (y * ETC2_BLOCK_WIDTH + x) * ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8;
+ var srcAlphaIndex = (y * ETC2_BLOCK_WIDTH + x) * ETC2_UNCOMPRESSED_PIXEL_SIZE_A8;
+ var dstIndex = (baseY + y) * dstRowPitch + (baseX + x) * dstPixelSize;
+
+ for (var i = 0; i < ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8 - 1; i++)
+ dstPtr[dstIndex + i] = uncompressedBlock[srcIndex + i];
+ dstPtr[dstIndex + ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8 - 1] = uncompressedBlockAlpha[srcAlphaIndex];
+
+ }
+ }
+ }
+ }
+};
+
+var decompressETC2_RGB8_PUNCHTHROUGH_ALPHA1 = function(/*const tcu::PixelBufferAccess&*/ dst, width, height, src) {
+ var numBlocksX = tcuCompressedTexture.divRoundUp(width, 4);
+ var numBlocksY = tcuCompressedTexture.divRoundUp(height, 4);
+ var dstPtr = new Uint8Array(dst.m_data);
+ var dstRowPitch = dst.getRowPitch();
+ var dstPixelSize = ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8;
+ var uncompressedBlockArray = new ArrayBuffer(ETC2_UNCOMPRESSED_BLOCK_SIZE_RGB8);
+ var uncompressedBlock = new Uint8Array(uncompressedBlockArray);
+ var uncompressedBlockAlphaArray = new ArrayBuffer(ETC2_UNCOMPRESSED_BLOCK_SIZE_A8);
+ var uncompressedBlockAlpha = new Uint8Array(uncompressedBlockAlphaArray);
+
+ for (var blockY = 0; blockY < numBlocksY; blockY++) {
+ for (var blockX = 0; blockX < numBlocksX; blockX++) {
+ var compressedBlock = get64BitBlock(src, blockY * numBlocksX + blockX);
+
+ // Decompress.
+ decompressETC2Block(uncompressedBlock, compressedBlock, uncompressedBlockAlpha, true);
+
+ // Write to dst.
+ var baseX = blockX * ETC2_BLOCK_WIDTH;
+ var baseY = blockY * ETC2_BLOCK_HEIGHT;
+ for (var y = 0; y < Math.min(ETC2_BLOCK_HEIGHT, height - baseY); y++) {
+ for (var x = 0; x < Math.min(ETC2_BLOCK_WIDTH, width - baseX); x++) {
+ var srcIndex = (y * ETC2_BLOCK_WIDTH + x) * ETC2_UNCOMPRESSED_PIXEL_SIZE_RGB8;
+ var srcAlphaIndex = (y * ETC2_BLOCK_WIDTH + x) * ETC2_UNCOMPRESSED_PIXEL_SIZE_A8;
+ var dstIndex = (baseY + y) * dstRowPitch + (baseX + x) * dstPixelSize;
+
+ for (var i = 0; i < ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8 - 1; i++)
+ dstPtr[dstIndex + i] = uncompressedBlock[srcIndex + i];
+ dstPtr[dstIndex + ETC2_UNCOMPRESSED_PIXEL_SIZE_RGBA8 - 1] = uncompressedBlockAlpha[srcAlphaIndex];
+
+ }
+ }
+ }
+ }
+};
+
+return {
+ decompressEAC_R11: decompressEAC_R11,
+ decompressEAC_RG11: decompressEAC_RG11,
+ decompressETC2: decompressETC2,
+ decompressETC2_RGB8_PUNCHTHROUGH_ALPHA1: decompressETC2_RGB8_PUNCHTHROUGH_ALPHA1,
+ decompressETC2_EAC_RGBA8: decompressETC2_EAC_RGBA8
+};
+
+}();
+
+/**
+ * @constructor
+ * @param {tcuCompressedTexture.Format} format
+ * @param {number} width
+ * @param {number} height
+ * @param {number=} depth
+ */
+tcuCompressedTexture.CompressedTexture = function(format, width, height, depth) {
+ depth = depth === undefined ? 1 : depth;
+ this.setStorage(format, width, height, depth);
+ /** @type {Uint8Array} */ this.m_data;
+};
+
+/**
+ * @return {number}
+ */
+tcuCompressedTexture.CompressedTexture.prototype.getDataSize = function() {
+ return this.m_data.length;
+};
+
+/**
+ * @return {Uint8Array}
+ */
+tcuCompressedTexture.CompressedTexture.prototype.getData = function() {
+ return this.m_data;
+};
+
+/**
+ * @return {number}
+ */
+tcuCompressedTexture.CompressedTexture.prototype.getWidth = function() {
+ return this.m_width;
+};
+
+/**
+ * @return {number}
+ */
+tcuCompressedTexture.CompressedTexture.prototype.getHeight = function() {
+ return this.m_height;
+};
+
+/**
+ * @return {tcuCompressedTexture.Format}
+ */
+tcuCompressedTexture.CompressedTexture.prototype.getFormat = function() {
+ return this.m_format;
+};
+
+tcuCompressedTexture.CompressedTexture.prototype.setStorage = function(format, width, height, depth) {
+ depth = depth === undefined ? 1 : depth;
+ this.m_format = format;
+ this.m_width = width;
+ this.m_height = height;
+ this.m_depth = depth;
+
+ if (tcuCompressedTexture.isEtcFormat(this.m_format)) {
+ DE_ASSERT(this.m_depth == 1);
+
+ var blockSizeMultiplier = 0; // How many 64-bit parts each compressed block contains.
+
+ switch (this.m_format) {
+ case tcuCompressedTexture.Format.ETC1_RGB8: blockSizeMultiplier = 1; break;
+ case tcuCompressedTexture.Format.EAC_R11: blockSizeMultiplier = 1; break;
+ case tcuCompressedTexture.Format.EAC_SIGNED_R11: blockSizeMultiplier = 1; break;
+ case tcuCompressedTexture.Format.EAC_RG11: blockSizeMultiplier = 2; break;
+ case tcuCompressedTexture.Format.EAC_SIGNED_RG11: blockSizeMultiplier = 2; break;
+ case tcuCompressedTexture.Format.ETC2_RGB8: blockSizeMultiplier = 1; break;
+ case tcuCompressedTexture.Format.ETC2_SRGB8: blockSizeMultiplier = 1; break;
+ case tcuCompressedTexture.Format.ETC2_RGB8_PUNCHTHROUGH_ALPHA1: blockSizeMultiplier = 1; break;
+ case tcuCompressedTexture.Format.ETC2_SRGB8_PUNCHTHROUGH_ALPHA1: blockSizeMultiplier = 1; break;
+ case tcuCompressedTexture.Format.ETC2_EAC_RGBA8: blockSizeMultiplier = 2; break;
+ case tcuCompressedTexture.Format.ETC2_EAC_SRGB8_ALPHA8: blockSizeMultiplier = 2; break;
+
+ default:
+ throw new Error('Unsupported format ' + format);
+ break;
+ }
+
+ this.m_array = new ArrayBuffer(blockSizeMultiplier * 8 * tcuCompressedTexture.divRoundUp(this.m_width, 4) * tcuCompressedTexture.divRoundUp(this.m_height, 4));
+ this.m_data = new Uint8Array(this.m_array);
+ }
+ // else if (isASTCFormat(this.m_format))
+ // {
+ // if (this.m_depth > 1)
+ // throw tcu::InternalError("3D ASTC textures not currently supported");
+
+ // const IVec3 blockSize = getASTCBlockSize(this.m_format);
+ // this.m_data.resize(ASTC_BLOCK_SIZE_BYTES * tcuCompressedTexture.divRoundUp(this.m_width, blockSize[0]) * tcuCompressedTexture.divRoundUp(this.m_height, blockSize[1]) * tcuCompressedTexture.divRoundUp(this.m_depth, blockSize[2]));
+ // }
+ // else
+ // {
+ // DE_ASSERT(this.m_format == FORMAT_LAST);
+ // DE_ASSERT(this.m_width == 0 && this.m_height == 0 && this.m_depth == 0);
+ // this.m_data.resize(0);
+ // }
+};
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Get uncompressed texture format
+ *//*--------------------------------------------------------------------*/
+tcuCompressedTexture.CompressedTexture.prototype.getUncompressedFormat = function() {
+ if (tcuCompressedTexture.isEtcFormat(this.m_format)) {
+ switch (this.m_format) {
+ case tcuCompressedTexture.Format.ETC1_RGB8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8);
+ case tcuCompressedTexture.Format.EAC_R11: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNORM_INT16);
+ case tcuCompressedTexture.Format.EAC_SIGNED_R11: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SNORM_INT16);
+ case tcuCompressedTexture.Format.EAC_RG11: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNORM_INT16);
+ case tcuCompressedTexture.Format.EAC_SIGNED_RG11: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SNORM_INT16);
+ case tcuCompressedTexture.Format.ETC2_RGB8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8);
+ case tcuCompressedTexture.Format.ETC2_SRGB8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.sRGB, tcuTexture.ChannelType.UNORM_INT8);
+ case tcuCompressedTexture.Format.ETC2_RGB8_PUNCHTHROUGH_ALPHA1: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8);
+ case tcuCompressedTexture.Format.ETC2_SRGB8_PUNCHTHROUGH_ALPHA1: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.sRGBA, tcuTexture.ChannelType.UNORM_INT8);
+ case tcuCompressedTexture.Format.ETC2_EAC_RGBA8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8);
+ case tcuCompressedTexture.Format.ETC2_EAC_SRGB8_ALPHA8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.sRGBA, tcuTexture.ChannelType.UNORM_INT8);
+ default:
+ throw new Error('Unsupported format ' + this.m_format);
+ }
+ }
+ // else if (isASTCFormat(m_format))
+ // {
+ // if (isASTCSRGBFormat(m_format))
+ // return TextureFormat(tcuTexture.ChannelType.sRGBA, tcuTexture.ChannelType.UNORM_INT8);
+ // else
+ // return TextureFormat(tcuTexture.ChannelType.RGBA, tcuTexture.ChannelType.HALF_FLOAT);
+ // }
+ // else
+ // {
+ // DE_ASSERT(false);
+ // return TextureFormat();
+ // }
+};
+
+/**
+ * Decode to uncompressed pixel data
+ * @param {tcuTexture.PixelBufferAccess} dst Destination buffer
+ */
+tcuCompressedTexture.CompressedTexture.prototype.decompress = function(dst) {
+ DE_ASSERT(dst.getWidth() == this.m_width && dst.getHeight() == this.m_height && dst.getDepth() == 1);
+ var format = this.getUncompressedFormat();
+ if (dst.getFormat().order != format.order || dst.getFormat().type != format.type)
+ throw new Error('Formats do not match.');
+
+ if (tcuCompressedTexture.isEtcFormat(this.m_format)) {
+ switch (this.m_format) {
+ // case tcuCompressedTexture.Format.ETC1_RGB8: decompressETC1 (dst, this.m_width, this.m_height, this.m_data); break;
+ case tcuCompressedTexture.Format.EAC_R11: tcuCompressedTexture.etcDecompressInternal.decompressEAC_R11(dst, this.m_width, this.m_height, this.m_array, false); break;
+ case tcuCompressedTexture.Format.EAC_SIGNED_R11: tcuCompressedTexture.etcDecompressInternal.decompressEAC_R11(dst, this.m_width, this.m_height, this.m_array, true); break;
+ case tcuCompressedTexture.Format.EAC_RG11: tcuCompressedTexture.etcDecompressInternal.decompressEAC_RG11(dst, this.m_width, this.m_height, this.m_array, false); break;
+ case tcuCompressedTexture.Format.EAC_SIGNED_RG11: tcuCompressedTexture.etcDecompressInternal.decompressEAC_RG11(dst, this.m_width, this.m_height, this.m_array, true); break;
+ case tcuCompressedTexture.Format.ETC2_RGB8: tcuCompressedTexture.etcDecompressInternal.decompressETC2(dst, this.m_width, this.m_height, this.m_array); break;
+ case tcuCompressedTexture.Format.ETC2_SRGB8: tcuCompressedTexture.etcDecompressInternal.decompressETC2(dst, this.m_width, this.m_height, this.m_array); break;
+ case tcuCompressedTexture.Format.ETC2_RGB8_PUNCHTHROUGH_ALPHA1: tcuCompressedTexture.etcDecompressInternal.decompressETC2_RGB8_PUNCHTHROUGH_ALPHA1(dst, this.m_width, this.m_height, this.m_array); break;
+ case tcuCompressedTexture.Format.ETC2_SRGB8_PUNCHTHROUGH_ALPHA1: tcuCompressedTexture.etcDecompressInternal.decompressETC2_RGB8_PUNCHTHROUGH_ALPHA1(dst, this.m_width, this.m_height, this.m_array); break;
+ case tcuCompressedTexture.Format.ETC2_EAC_RGBA8: tcuCompressedTexture.etcDecompressInternal.decompressETC2_EAC_RGBA8(dst, this.m_width, this.m_height, this.m_array); break;
+ case tcuCompressedTexture.Format.ETC2_EAC_SRGB8_ALPHA8: tcuCompressedTexture.etcDecompressInternal.decompressETC2_EAC_RGBA8(dst, this.m_width, this.m_height, this.m_array); break;
+
+ default:
+ throw new Error('Unsupported format ' + this.m_format);
+ break;
+ }
+ }
+ // else if (isASTCFormat(m_format))
+ // {
+ // const tcu::IVec3 blockSize = getASTCBlockSize(m_format);
+ // const bool isSRGBFormat = isASTCSRGBFormat(m_format);
+
+ // if (blockSize[2] > 1)
+ // throw tcu::InternalError("3D ASTC textures not currently supported");
+
+ // decompressASTC(dst, m_width, m_height, &m_data[0], blockSize[0], blockSize[1], isSRGBFormat, isSRGBFormat || params.isASTCModeLDR);
+ // } /**/
+ else
+ throw new Error('Unsupported format ' + this.m_format);
+};
+
+ });
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloat.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloat.js
new file mode 100644
index 0000000000..0cc74fe5a9
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloat.js
@@ -0,0 +1,862 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuFloat');
+goog.require('framework.delibs.debase.deMath');
+
+goog.scope(function() {
+
+var tcuFloat = framework.common.tcuFloat;
+var deMath = framework.delibs.debase.deMath;
+
+var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+};
+
+tcuFloat.FloatFlags = {
+ FLOAT_HAS_SIGN: (1 << 0),
+ FLOAT_SUPPORT_DENORM: (1 << 1)
+};
+
+/**
+ * Defines a tcuFloat.FloatDescription object, which is an essential part of the tcuFloat.deFloat type.
+ * Holds the information that shapes the tcuFloat.deFloat.
+ * @constructor
+ */
+tcuFloat.FloatDescription = function(exponentBits, mantissaBits, exponentBias, flags) {
+ this.ExponentBits = exponentBits;
+ this.MantissaBits = mantissaBits;
+ this.ExponentBias = exponentBias;
+ this.Flags = flags;
+
+ this.totalBitSize = 1 + this.ExponentBits + this.MantissaBits;
+ this.totalByteSize = Math.floor(this.totalBitSize / 8) + ((this.totalBitSize % 8) > 0 ? 1 : 0);
+};
+
+/**
+ * Builds a zero float of the current binary description.
+ * @param {number} sign
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.FloatDescription.prototype.zero = function(sign) {
+ return tcuFloat.newDeFloatFromParameters(this.zeroNumber(sign), this);
+};
+
+tcuFloat.FloatDescription.prototype.zeroNumber = function(sign) {
+ return deMath.shiftLeft((sign > 0 ? 0 : 1), (this.ExponentBits + this.MantissaBits));
+};
+
+/**
+ * Builds an infinity float representation of the current binary description.
+ * @param {number} sign
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.FloatDescription.prototype.inf = function(sign) {
+ return tcuFloat.newDeFloatFromParameters(this.infNumber(sign), this);
+};
+
+tcuFloat.FloatDescription.prototype.infNumber = function(sign) {
+ return ((sign > 0 ? 0 : 1) << (this.ExponentBits + this.MantissaBits)) |
+ deMath.shiftLeft(((1 << this.ExponentBits) - 1), this.MantissaBits); //Unless using very large exponent types, native shift is safe here, i guess.
+};
+
+/**
+ * Builds a NaN float representation of the current binary description.
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.FloatDescription.prototype.nan = function() {
+ return tcuFloat.newDeFloatFromParameters(this.nanNumber(), this);
+};
+
+tcuFloat.FloatDescription.prototype.nanNumber = function() {
+ return deMath.shiftLeft(1, (this.ExponentBits + this.MantissaBits)) - 1;
+};
+
+/**
+ * Builds a tcuFloat.deFloat number based on the description and the given
+ * sign, exponent and mantissa values.
+ * @param {number} sign
+ * @param {number} exponent
+ * @param {number} mantissa
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.FloatDescription.prototype.construct = function(sign, exponent, mantissa) {
+ // Repurpose this otherwise invalid input as a shorthand notation for zero (no need for caller to care about internal representation)
+ /** @type {boolean} */ var isShorthandZero = exponent == 0 && mantissa == 0;
+
+ // Handles the typical notation for zero (min exponent, mantissa 0). Note that the exponent usually used exponent (-ExponentBias) for zero/subnormals is not used.
+ // Instead zero/subnormals have the (normally implicit) leading mantissa bit set to zero.
+
+ /** @type {boolean} */ var isDenormOrZero = (exponent == 1 - this.ExponentBias) && (deMath.shiftRight(mantissa, this.MantissaBits) == 0);
+ /** @type {number} */ var s = deMath.shiftLeft((sign < 0 ? 1 : 0), (this.ExponentBits + this.MantissaBits));
+ /** @type {number} */ var exp = (isShorthandZero || isDenormOrZero) ? 0 : exponent + this.ExponentBias;
+
+ DE_ASSERT(sign == +1 || sign == -1);
+ DE_ASSERT(isShorthandZero || isDenormOrZero || deMath.shiftRight(mantissa, this.MantissaBits) == 1);
+ DE_ASSERT((exp >> this.ExponentBits) == 0); //Native shift is safe
+
+ return tcuFloat.newDeFloatFromParameters(
+ deMath.binaryOp(
+ deMath.binaryOp(
+ s,
+ deMath.shiftLeft(exp, this.MantissaBits),
+ deMath.BinaryOp.OR
+ ),
+ deMath.binaryOp(
+ mantissa,
+ deMath.shiftLeft(1, this.MantissaBits) - 1,
+ deMath.BinaryOp.AND
+ ),
+ deMath.BinaryOp.OR
+ ),
+ this
+ );
+};
+
+/**
+ * Builds a tcuFloat.deFloat number based on the description and the given
+ * sign, exponent and binary mantissa values.
+ * @param {number} sign
+ * @param {number} exponent
+ * @param {number} mantissaBits The raw binary representation.
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.FloatDescription.prototype.constructBits = function(sign, exponent, mantissaBits) {
+ /** @type {number} */ var signBit = sign < 0 ? 1 : 0;
+ /** @type {number} */ var exponentBits = exponent + this.ExponentBias;
+
+ DE_ASSERT(sign == +1 || sign == -1);
+ DE_ASSERT((exponentBits >> this.ExponentBits) == 0);
+ DE_ASSERT(deMath.shiftRight(mantissaBits, this.MantissaBits) == 0);
+
+ return tcuFloat.newDeFloatFromParameters(
+ deMath.binaryOp(
+ deMath.binaryOp(
+ deMath.shiftLeft(
+ signBit,
+ this.ExponentBits + this.MantissaBits
+ ),
+ deMath.shiftLeft(exponentBits, this.MantissaBits),
+ deMath.BinaryOp.OR
+ ),
+ mantissaBits,
+ deMath.BinaryOp.OR
+ ),
+ this
+ );
+};
+
+/**
+ * Converts a tcuFloat.deFloat from it's own format description into the format described
+ * by this description.
+ * @param {tcuFloat.deFloat} other Other float to convert to this format description.
+ * @return {tcuFloat.deFloat} converted tcuFloat.deFloat
+ */
+tcuFloat.FloatDescription.prototype.convert = function(other) {
+ /** @type {number} */ var otherExponentBits = other.description.ExponentBits;
+ /** @type {number} */ var otherMantissaBits = other.description.MantissaBits;
+ /** @type {number} */ var otherExponentBias = other.description.ExponentBias;
+ /** @type {number} */ var otherFlags = other.description.Flags;
+
+ /** @type {number} */ var bitDiff;
+ /** @type {number} */ var half;
+ /** @type {number} */ var bias;
+
+ if (!(this.Flags & tcuFloat.FloatFlags.FLOAT_HAS_SIGN) && other.sign() < 0) {
+ // Negative number, truncate to zero.
+ return this.zero(+1);
+ } else if (other.isInf()) {
+ return this.inf(other.sign());
+ } else if (other.isNaN()) {
+ return this.nan();
+ } else if (other.isZero()) {
+ return this.zero(other.sign());
+ } else {
+ /** @type {number} */ var eMin = 1 - this.ExponentBias;
+ /** @type {number} */ var eMax = ((1 << this.ExponentBits) - 2) - this.ExponentBias;
+
+ /** @type {number} */ var s = deMath.shiftLeft(other.signBit(), (this.ExponentBits + this.MantissaBits)); // \note Not sign, but sign bit.
+ /** @type {number} */ var e = other.exponent();
+ /** @type {number} */ var m = other.mantissa();
+
+ // Normalize denormalized values prior to conversion.
+ while (!deMath.binaryOp(m, deMath.shiftLeft(1, otherMantissaBits), deMath.BinaryOp.AND)) {
+ m = deMath.shiftLeft(m, 1);
+ e -= 1;
+ }
+
+ if (e < eMin) {
+ // Underflow.
+ if ((this.Flags & tcuFloat.FloatFlags.FLOAT_SUPPORT_DENORM) && (eMin - e - 1 <= this.MantissaBits)) {
+ // Shift and round (RTE).
+ bitDiff = (otherMantissaBits - this.MantissaBits) + (eMin - e);
+ half = deMath.shiftLeft(1, (bitDiff - 1)) - 1;
+ bias = deMath.binaryOp(deMath.shiftRight(m, bitDiff), 1, deMath.BinaryOp.AND);
+
+ return tcuFloat.newDeFloatFromParameters(
+ deMath.binaryOp(
+ s,
+ deMath.shiftRight(
+ m + half + bias,
+ bitDiff
+ ),
+ deMath.BinaryOp.OR
+ ),
+ this
+ );
+ } else
+ return this.zero(other.sign());
+ } else {
+ // Remove leading 1.
+ m = deMath.binaryOp(m, deMath.binaryNot(deMath.shiftLeft(1, otherMantissaBits)), deMath.BinaryOp.AND);
+
+ if (this.MantissaBits < otherMantissaBits) {
+ // Round mantissa (round to nearest even).
+ bitDiff = otherMantissaBits - this.MantissaBits;
+ half = deMath.shiftLeft(1, (bitDiff - 1)) - 1;
+ bias = deMath.binaryOp(deMath.shiftRight(m, bitDiff), 1, deMath.BinaryOp.AND);
+
+ m = deMath.shiftRight(m + half + bias, bitDiff);
+
+ if (deMath.binaryOp(m, deMath.shiftLeft(1, this.MantissaBits), deMath.BinaryOp.AND)) {
+ // Overflow in mantissa.
+ m = 0;
+ e += 1;
+ }
+ } else {
+ bitDiff = this.MantissaBits - otherMantissaBits;
+ m = deMath.shiftLeft(m, bitDiff);
+ }
+
+ if (e > eMax) {
+ // Overflow.
+ return this.inf(other.sign());
+ } else {
+ DE_ASSERT(deMath.deInRange32(e, eMin, eMax));
+ DE_ASSERT(deMath.binaryOp((e + this.ExponentBias), deMath.binaryNot(deMath.shiftLeft(1, this.ExponentBits) - 1), deMath.BinaryOp.AND) == 0);
+ DE_ASSERT(deMath.binaryOp(m, deMath.binaryNot(deMath.shiftLeft(1, this.MantissaBits) - 1), deMath.BinaryOp.AND) == 0);
+
+ return tcuFloat.newDeFloatFromParameters(
+ deMath.binaryOp(
+ deMath.binaryOp(
+ s,
+ deMath.shiftLeft(
+ e + this.ExponentBias,
+ this.MantissaBits
+ ),
+ deMath.BinaryOp.OR
+ ),
+ m,
+ deMath.BinaryOp.OR
+ ),
+ this
+ );
+ }
+ }
+ }
+};
+
+/**
+ * tcuFloat.deFloat class - Empty constructor, builds a 32 bit float by default
+ * @constructor
+ */
+tcuFloat.deFloat = function() {
+ this.description = tcuFloat.description32;
+
+ this.m_buffer = null;
+ this.m_array = null;
+ this.m_array32 = null;
+ this.bitValue = undefined;
+ this.signValue = undefined;
+ this.expValue = undefined;
+ this.mantissaValue = undefined;
+
+ this.m_value = 0;
+};
+
+/**
+ * buffer - Get the deFloat's existing ArrayBuffer or create one if none exists.
+ * @return {ArrayBuffer}
+ */
+tcuFloat.deFloat.prototype.buffer = function() {
+ if (!this.m_buffer)
+ this.m_buffer = new ArrayBuffer(this.description.totalByteSize);
+ return this.m_buffer;
+};
+
+/**
+ * array - Get the deFloat's existing Uint8Array or create one if none exists.
+ * @return {Uint8Array}
+ */
+tcuFloat.deFloat.prototype.array = function() {
+ if (!this.m_array)
+ this.m_array = new Uint8Array(this.buffer());
+ return this.m_array;
+};
+
+/**
+ * array32 - Get the deFloat's existing Uint32Array or create one if none exists.
+ * @return {Uint32Array}
+ */
+tcuFloat.deFloat.prototype.array32 = function() {
+ if (!this.m_array32)
+ this.m_array32 = new Uint32Array(this.buffer());
+ return this.m_array32;
+};
+
+/**
+ * deFloatNumber - To be used immediately after constructor
+ * Builds a 32-bit tcuFloat.deFloat based on a 64-bit JS number.
+ * @param {number} jsnumber
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.deFloat.prototype.deFloatNumber = function(jsnumber) {
+ var view32 = new DataView(this.buffer());
+ view32.setFloat32(0, jsnumber, true); //little-endian
+ this.m_value = view32.getFloat32(0, true); //little-endian
+
+ // Clear cached values
+ this.bitValue = undefined;
+ this.signValue = undefined;
+ this.expValue = undefined;
+ this.mantissaValue = undefined;
+
+ return this;
+};
+
+/**
+ * deFloatNumber64 - To be used immediately after constructor
+ * Builds a 64-bit tcuFloat.deFloat based on a 64-bit JS number.
+ * @param {number} jsnumber
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.deFloat.prototype.deFloatNumber64 = function(jsnumber) {
+ var view64 = new DataView(this.buffer());
+ view64.setFloat64(0, jsnumber, true); //little-endian
+ this.m_value = view64.getFloat64(0, true); //little-endian
+
+ // Clear cached values
+ this.bitValue = undefined;
+ this.signValue = undefined;
+ this.expValue = undefined;
+ this.mantissaValue = undefined;
+
+ return this;
+};
+
+/**
+ * Convenience function to build a 32-bit tcuFloat.deFloat based on a 64-bit JS number
+ * Builds a 32-bit tcuFloat.deFloat based on a 64-bit JS number.
+ * @param {number} jsnumber
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.newDeFloatFromNumber = function(jsnumber) {
+ return new tcuFloat.deFloat().deFloatNumber(jsnumber);
+};
+
+/**
+ * deFloatBuffer - To be used immediately after constructor
+ * Builds a tcuFloat.deFloat based on a buffer and a format description.
+ * The buffer is assumed to contain data of the given description.
+ * @param {ArrayBuffer} buffer
+ * @param {tcuFloat.FloatDescription} description
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.deFloat.prototype.deFloatBuffer = function(buffer, description) {
+ this.m_buffer = buffer;
+ this.m_array = new Uint8Array(this.m_buffer);
+ this.m_array32 = new Uint32Array(this.m_buffer);
+
+ this.m_value = deMath.arrayToNumber(this.m_array);
+
+ // Clear cached values
+ this.bitValue = undefined;
+ this.signValue = undefined;
+ this.expValue = undefined;
+ this.mantissaValue = undefined;
+
+ return this;
+};
+
+/**
+ * Convenience function to build a tcuFloat.deFloat based on a buffer and a format description
+ * The buffer is assumed to contain data of the given description.
+ * @param {ArrayBuffer} buffer
+ * @param {tcuFloat.FloatDescription} description
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.newDeFloatFromBuffer = function(buffer, description) {
+ return new tcuFloat.deFloat().deFloatBuffer(buffer, description);
+};
+
+/**
+ * Set the tcuFloat.deFloat from the given bitwise representation.
+ *
+ * @param {number} jsnumber This is taken to be the bitwise representation of
+ * the floating point number represented by this deFloat. It must be an
+ * integer, less than 2^52, and compatible with the existing description.
+ * @return {tcuFloat.deFloat}
+ **/
+tcuFloat.deFloat.prototype.deFloatParametersNumber = function(jsnumber) {
+ /** @type {number} */ var jsnumberMax = -1 >>> (32 - this.description.totalBitSize);
+ DE_ASSERT(Number.isInteger(jsnumber) && jsnumber <= jsnumberMax);
+
+ this.m_value = jsnumber;
+ deMath.numberToArray(this.m_array, jsnumber);
+
+ // Clear cached values
+ this.bitValue = undefined;
+ this.signValue = undefined;
+ this.expValue = undefined;
+ this.mantissaValue = undefined;
+
+ return this;
+};
+
+/**
+ * Initializes a tcuFloat.deFloat from the given bitwise representation,
+ * with the specified format description.
+ *
+ * @param {number} jsnumber This is taken to be the bitwise representation of
+ * the floating point number represented by this deFloat. It must be an
+ * integer, less than 2^52, and compatible with the new description.
+ * @param {tcuFloat.FloatDescription} description
+ * @return {tcuFloat.deFloat}
+ **/
+tcuFloat.deFloat.prototype.deFloatParameters = function(jsnumber, description) {
+ /** @type {number} */ var maxUint52 = 0x10000000000000;
+ DE_ASSERT(Number.isInteger(jsnumber) && jsnumber < maxUint52);
+ if (description.totalBitSize > 52) {
+ // The jsnumber representation for this number can't possibly be valid.
+ // Make sure it has a sentinel 0 value.
+ DE_ASSERT(jsnumber === 0);
+ }
+
+ this.description = description;
+
+ this.m_buffer = new ArrayBuffer(this.description.totalByteSize);
+ this.m_array = new Uint8Array(this.m_buffer);
+
+ return this.deFloatParametersNumber(jsnumber);
+};
+
+/**
+ * Convenience function. Creates a tcuFloat.deFloat, then initializes it from
+ * the given bitwise representation, with the specified format description.
+ *
+ * @param {number} jsnumber This is taken to be the bitwise representation of
+ * the floating point number represented by this deFloat. It must be an
+ * integer, less than 2^52, and compatible with the new description.
+ * @param {tcuFloat.FloatDescription} description
+ * @return {tcuFloat.deFloat}
+ **/
+tcuFloat.newDeFloatFromParameters = function(jsnumber, description) {
+ return new tcuFloat.deFloat().deFloatParameters(jsnumber, description);
+};
+
+/**
+ * Returns bit range [begin, end)
+ * @param {number} begin
+ * @param {number} end
+ * @return {number}
+ */
+tcuFloat.deFloat.prototype.getBitRange = function(begin, end) {
+ if (this.description.totalBitSize <= 52) {
+ // this.bits() is invalid for more than 52 bits.
+ return deMath.getBitRange(this.bits(), begin, end);
+ } else {
+ return deMath.getArray32BitRange(this.array32(), begin, end);
+ }
+};
+
+/**
+ * Returns the raw binary representation value of the tcuFloat.deFloat
+ * @return {number}
+ */
+tcuFloat.deFloat.prototype.bits = function() {
+ if (typeof this.bitValue === 'undefined')
+ this.bitValue = deMath.arrayToNumber(this.array());
+ return this.bitValue;
+};
+
+/**
+ * Returns the raw binary sign bit
+ * @return {number}
+ */
+tcuFloat.deFloat.prototype.signBit = function() {
+ if (typeof this.signValue === 'undefined')
+ this.signValue = this.getBitRange(this.description.totalBitSize - 1, this.description.totalBitSize);
+ return this.signValue;
+};
+
+/**
+ * Returns the raw binary exponent bits
+ * @return {number}
+ */
+tcuFloat.deFloat.prototype.exponentBits = function() {
+ if (typeof this.expValue === 'undefined')
+ this.expValue = this.getBitRange(this.description.MantissaBits, this.description.MantissaBits + this.description.ExponentBits);
+ return this.expValue;
+};
+
+/**
+ * Returns the raw binary mantissa bits
+ * @return {number}
+ */
+tcuFloat.deFloat.prototype.mantissaBits = function() {
+ if (typeof this.mantissaValue === 'undefined')
+ this.mantissaValue = this.getBitRange(0, this.description.MantissaBits);
+ return this.mantissaValue;
+};
+
+/**
+ * Returns the sign as a factor (-1 or 1)
+ * @return {number}
+ */
+tcuFloat.deFloat.prototype.sign = function() {
+ var sign = this.signBit();
+ var signvalue = sign ? -1 : 1;
+ return signvalue;
+};
+
+/**
+ * Returns the real exponent, checking if it's a denorm or zero number or not
+ * @return {number}
+ */
+tcuFloat.deFloat.prototype.exponent = function() {return this.isDenorm() ? 1 - this.description.ExponentBias : this.exponentBits() - this.description.ExponentBias;};
+
+/**
+ * Returns the (still raw) mantissa, checking if it's a denorm or zero number or not
+ * Makes the normally implicit bit explicit.
+ * @return {number}
+ */
+tcuFloat.deFloat.prototype.mantissa = function() {return this.isZero() || this.isDenorm() ? this.mantissaBits() : deMath.binaryOp(this.mantissaBits(), deMath.shiftLeft(1, this.description.MantissaBits), deMath.BinaryOp.OR);};
+
+/**
+ * Returns if the number is infinity or not.
+ * @return {boolean}
+ */
+tcuFloat.deFloat.prototype.isInf = function() {return this.exponentBits() == ((1 << this.description.ExponentBits) - 1) && this.mantissaBits() == 0;};
+
+/**
+ * Returns if the number is NaN or not.
+ * @return {boolean}
+ */
+tcuFloat.deFloat.prototype.isNaN = function() {return this.exponentBits() == ((1 << this.description.ExponentBits) - 1) && this.mantissaBits() != 0;};
+
+/**
+ * Returns if the number is zero or not.
+ * @return {boolean}
+ */
+tcuFloat.deFloat.prototype.isZero = function() {return this.exponentBits() == 0 && this.mantissaBits() == 0;};
+
+/**
+ * Returns if the number is denormalized or not.
+ * @return {boolean}
+ */
+tcuFloat.deFloat.prototype.isDenorm = function() {return this.exponentBits() == 0 && this.mantissaBits() != 0;};
+
+/**
+ * Builds a zero float of the current binary description.
+ * @param {number} sign
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.deFloat.prototype.zero = function(sign) {
+ return this.description.zero(sign);
+};
+
+/**
+ * Builds an infinity float representation of the current binary description.
+ * @param {number} sign
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.deFloat.prototype.inf = function(sign) {
+ return this.description.inf(sign);
+};
+
+/**
+ * Builds a NaN float representation of the current binary description.
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.deFloat.prototype.nan = function() {
+ return this.description.nan();
+};
+
+/**
+ * Builds a float of the current binary description.
+ * Given a sign, exponent and mantissa.
+ * @param {number} sign
+ * @param {number} exponent
+ * @param {number} mantissa
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.deFloat.prototype.construct = function(sign, exponent, mantissa) {
+ return this.description.construct(sign, exponent, mantissa);
+};
+
+/**
+ * Builds a float of the current binary description.
+ * Given a sign, exponent and a raw binary mantissa.
+ * @param {number} sign
+ * @param {number} exponent
+ * @param {number} mantissaBits Raw binary mantissa.
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.deFloat.prototype.constructBits = function(sign, exponent, mantissaBits) {
+ return this.description.constructBits(sign, exponent, mantissaBits);
+};
+
+/**
+ * Calculates the JS float number from the internal representation.
+ * @return {number} The JS float value represented by this tcuFloat.deFloat.
+ */
+tcuFloat.deFloat.prototype.getValue = function() {
+ if ((this.description.Flags | tcuFloat.FloatFlags.FLOAT_HAS_SIGN) === 0 && this.sign() < 0)
+ return 0;
+ if (this.isInf())
+ return Number.Infinity;
+ if (this.isNaN())
+ return Number.NaN;
+ if (this.isZero())
+ return this.sign() * 0;
+ /**@type {number} */ var mymantissa = this.mantissa();
+ /**@type {number} */ var myexponent = this.exponent();
+ /**@type {number} */ var sign = this.sign();
+
+ /**@type {number} */ var value = mymantissa / Math.pow(2, this.description.MantissaBits) * Math.pow(2, myexponent);
+
+ if (this.description.Flags | tcuFloat.FloatFlags.FLOAT_HAS_SIGN != 0)
+ value = value * sign;
+
+ return value;
+};
+
+tcuFloat.description10 = new tcuFloat.FloatDescription(5, 5, 15, 0);
+tcuFloat.description11 = new tcuFloat.FloatDescription(5, 6, 15, 0);
+tcuFloat.description16 = new tcuFloat.FloatDescription(5, 10, 15, tcuFloat.FloatFlags.FLOAT_HAS_SIGN);
+tcuFloat.description32 = new tcuFloat.FloatDescription(8, 23, 127, tcuFloat.FloatFlags.FLOAT_HAS_SIGN | tcuFloat.FloatFlags.FLOAT_SUPPORT_DENORM);
+tcuFloat.description64 = new tcuFloat.FloatDescription(11, 52, 1023, tcuFloat.FloatFlags.FLOAT_HAS_SIGN | tcuFloat.FloatFlags.FLOAT_SUPPORT_DENORM);
+
+tcuFloat.convertFloat32Inline = (function() {
+ var float32View = new Float32Array(1);
+ var int32View = new Int32Array(float32View.buffer);
+
+ return function(fval, description) {
+ float32View[0] = fval;
+ var fbits = int32View[0];
+
+ var exponentBits = (fbits >> 23) & 0xff;
+ var mantissaBits = fbits & 0x7fffff;
+ var signBit = (fbits & 0x80000000) ? 1 : 0;
+ var sign = signBit ? -1 : 1;
+
+ var isZero = exponentBits == 0 && mantissaBits == 0;
+
+ var bitDiff;
+ var half;
+ var bias;
+
+ if (!(description.Flags & tcuFloat.FloatFlags.FLOAT_HAS_SIGN) && sign < 0) {
+ // Negative number, truncate to zero.
+ return description.zeroNumber(+1);
+ } else if (exponentBits == ((1 << tcuFloat.description32.ExponentBits) - 1) && mantissaBits == 0) { // isInf
+ return description.infNumber(sign);
+ } else if (exponentBits == ((1 << tcuFloat.description32.ExponentBits) - 1) && mantissaBits != 0) { // isNaN
+ return description.nanNumber();
+ } else if (isZero) {
+ return description.zeroNumber(sign);
+ } else {
+ var eMin = 1 - description.ExponentBias;
+ var eMax = ((1 << description.ExponentBits) - 2) - description.ExponentBias;
+
+ var isDenorm = exponentBits == 0 && mantissaBits != 0;
+
+ var s = signBit << (description.ExponentBits + description.MantissaBits); // \note Not sign, but sign bit.
+ var e = isDenorm ? 1 - tcuFloat.description32.ExponentBias : exponentBits - tcuFloat.description32.ExponentBias;// other.exponent();
+ var m = isZero || isDenorm ? mantissaBits : mantissaBits | (1 << tcuFloat.description32.MantissaBits); // other.mantissa();
+
+ // Normalize denormalized values prior to conversion.
+ while (!(m & (1 << tcuFloat.description32.MantissaBits))) {
+ m = deMath.shiftLeft(m, 1);
+ e -= 1;
+ }
+
+ if (e < eMin) {
+ // Underflow.
+ if ((description.Flags & tcuFloat.FloatFlags.FLOAT_SUPPORT_DENORM) && (eMin - e - 1 <= description.MantissaBits)) {
+ // Shift and round (RTE).
+ bitDiff = (tcuFloat.description32.MantissaBits - description.MantissaBits) + (eMin - e);
+ half = (1 << (bitDiff - 1)) - 1;
+ bias = ((m >> bitDiff) & 1);
+ return (s | ((m + half + bias) >> bitDiff));
+ } else
+ return description.zeroNumber(sign);
+ } else {
+ // Remove leading 1.
+ m = (m & ~(1 << tcuFloat.description32.MantissaBits));
+
+ if (description.MantissaBits < tcuFloat.description32.MantissaBits) {
+ // Round mantissa (round to nearest even).
+ bitDiff = tcuFloat.description32.MantissaBits - description.MantissaBits;
+ half = (1 << (bitDiff - 1)) - 1;
+ bias = ((m >> bitDiff) & 1);
+
+ m = (m + half + bias) >> bitDiff;
+
+ if ((m & (1 << description.MantissaBits))) {
+ // Overflow in mantissa.
+ m = 0;
+ e += 1;
+ }
+ } else {
+ bitDiff = description.MantissaBits - tcuFloat.description32.MantissaBits;
+ m = (m << bitDiff);
+ }
+
+ if (e > eMax) {
+ // Overflow.
+ return description.infNumber(sign);
+ } else {
+ DE_ASSERT(deMath.deInRange32(e, eMin, eMax));
+ DE_ASSERT(((e + description.ExponentBias) & ~((1 << description.ExponentBits) - 1)) == 0);
+ DE_ASSERT((m & ~((1 << description.MantissaBits) - 1)) == 0);
+
+ return (s | ((e + description.ExponentBias) << description.MantissaBits)) | m;
+ }
+ }
+ }
+ };
+})();
+
+/**
+ * Builds a 10 bit tcuFloat.deFloat
+ * @param {number} value (64-bit JS float)
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.newFloat10 = function(value) {
+ DE_ASSERT(Number.isInteger(value) && value <= 0x3ff);
+ /**@type {tcuFloat.deFloat} */ var other32 = new tcuFloat.deFloat().deFloatNumber(value);
+ return tcuFloat.description10.convert(other32);
+};
+
+/**
+ * Builds a 11 bit tcuFloat.deFloat
+ * @param {number} value (64-bit JS float)
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.newFloat11 = function(value) {
+ /**@type {tcuFloat.deFloat} */ var other32 = new tcuFloat.deFloat().deFloatNumber(value);
+ return tcuFloat.description11.convert(other32);
+};
+
+/**
+ * Builds a 16 bit tcuFloat.deFloat
+ * @param {number} value (64-bit JS float)
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.newFloat16 = function(value) {
+ /**@type {tcuFloat.deFloat} */ var other32 = new tcuFloat.deFloat().deFloatNumber(value);
+ return tcuFloat.description16.convert(other32);
+};
+
+/**
+ * Builds a 16 bit tcuFloat.deFloat from raw bits
+ * @param {number} value (16-bit value)
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.newFloat32From16 = function(value) {
+ var other16 = tcuFloat.newDeFloatFromParameters(value, tcuFloat.description16);
+ return tcuFloat.description32.convert(other16);
+};
+
+/**
+ * Builds a 16 bit tcuFloat.deFloat with no denorm support
+ * @param {number} value (64-bit JS float)
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.newFloat16NoDenorm = function(value) {
+ /**@type {tcuFloat.deFloat} */ var other32 = new tcuFloat.deFloat().deFloatNumber(value);
+ return tcuFloat.description16.convert(other32);
+};
+
+/**
+ * Builds a 32 bit tcuFloat.deFloat
+ * @param {number} value (64-bit JS float)
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.newFloat32 = function(value) {
+ return new tcuFloat.deFloat().deFloatNumber(value);
+};
+
+tcuFloat.numberToFloat11 = function(value) {
+ return tcuFloat.convertFloat32Inline(value, tcuFloat.description11);
+};
+
+tcuFloat.float11ToNumber = (function() {
+ var x = tcuFloat.newDeFloatFromParameters(0, tcuFloat.description11);
+ return function(float11) {
+ x.deFloatParametersNumber(float11);
+ return x.getValue();
+ };
+})();
+
+tcuFloat.numberToFloat10 = function(value) {
+ return tcuFloat.convertFloat32Inline(value, tcuFloat.description10);
+};
+
+tcuFloat.float10ToNumber = (function() {
+ var x = tcuFloat.newDeFloatFromParameters(0, tcuFloat.description10);
+ return function(float10) {
+ x.deFloatParametersNumber(float10);
+ return x.getValue();
+ };
+})();
+
+tcuFloat.numberToHalfFloat = function(value) {
+ return tcuFloat.convertFloat32Inline(value, tcuFloat.description16);
+};
+
+tcuFloat.numberToHalfFloatNoDenorm = function(value) {
+ return tcuFloat.newFloat16NoDenorm(value).bits();
+};
+
+tcuFloat.halfFloatToNumber = (function() {
+ var x = tcuFloat.newDeFloatFromParameters(0, tcuFloat.description16);
+ return function(half) {
+ x.deFloatParametersNumber(half);
+ return x.getValue();
+ };
+})();
+
+tcuFloat.halfFloatToNumberNoDenorm = tcuFloat.halfFloatToNumber;
+
+/**
+ * Builds a 64 bit tcuFloat.deFloat
+ * @param {number} value (64-bit JS float)
+ * @return {tcuFloat.deFloat}
+ */
+tcuFloat.newFloat64 = function(value) {
+ return new tcuFloat.deFloat().deFloatParameters(0, tcuFloat.description64)
+ .deFloatNumber64(value);
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloatFormat.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloatFormat.js
new file mode 100644
index 0000000000..a0b4dc82cf
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFloatFormat.js
@@ -0,0 +1,349 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program Tester Core
+ * ----------------------------------------
+ *
+ * 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 Adjustable-precision floating point operations.
+ *//*--------------------------------------------------------------------*/
+ 'use strict';
+ goog.provide('framework.common.tcuFloatFormat');
+
+ goog.require('framework.common.tcuInterval');
+goog.require('framework.delibs.debase.deMath');
+
+ goog.scope(function() {
+
+ var tcuFloatFormat = framework.common.tcuFloatFormat;
+ var deMath = framework.delibs.debase.deMath;
+ var tcuInterval = framework.common.tcuInterval;
+
+ /**
+ * @param {tcuFloatFormat.YesNoMaybe} choice
+ * @param {tcuInterval.Interval} no
+ * @param {tcuInterval.Interval} yes
+ * @return {tcuInterval.Interval}
+ */
+ tcuFloatFormat.chooseInterval = function(choice, no, yes) {
+ switch (choice) {
+ case tcuFloatFormat.YesNoMaybe.NO: return no;
+ case tcuFloatFormat.YesNoMaybe.YES: return yes;
+ case tcuFloatFormat.YesNoMaybe.MAYBE: return no.operatorOrBinary(yes);
+ default: throw new Error('Impossible case');
+ }
+ };
+
+ /**
+ * @param {number} maxExp
+ * @param {number} fractionBits
+ * @return {number}
+ */
+ tcuFloatFormat.computeMaxValue = function(maxExp, fractionBits) {
+ return deMath.deLdExp(1, maxExp) + deMath.deLdExp(Math.pow(2, fractionBits) - 1, maxExp - fractionBits);
+ };
+
+ /**
+ * @enum {number}
+ */
+ tcuFloatFormat.YesNoMaybe = {
+ NO: 0,
+ MAYBE: 1,
+ YES: 2
+ };
+
+ /**
+ * @constructor
+ * @param {number} minExp
+ * @param {number} maxExp
+ * @param {number} fractionBits
+ * @param {boolean} exactPrecision
+ * @param {tcuFloatFormat.YesNoMaybe=} hasSubnormal
+ * @param {tcuFloatFormat.YesNoMaybe=} hasInf
+ * @param {tcuFloatFormat.YesNoMaybe=} hasNaN
+ */
+ tcuFloatFormat.FloatFormat = function(minExp, maxExp, fractionBits, exactPrecision, hasSubnormal, hasInf, hasNaN) {
+ // /** @type{number} */ var exponentShift (int exp) const;
+ // Interval clampValue (double d) const;
+
+ /** @type {number} */ this.m_minExp = minExp; // Minimum exponent, inclusive
+ /** @type {number} */ this.m_maxExp = maxExp; // Maximum exponent, inclusive
+ /** @type {number} */ this.m_fractionBits = fractionBits; // Number of fractional bits in significand
+ /** @type {tcuFloatFormat.YesNoMaybe} */ this.m_hasSubnormal = hasSubnormal === undefined ? tcuFloatFormat.YesNoMaybe.MAYBE : hasSubnormal; // Does the format support denormalized numbers?
+ /** @type {tcuFloatFormat.YesNoMaybe} */ this.m_hasInf = hasInf === undefined ? tcuFloatFormat.YesNoMaybe.MAYBE : hasInf; // Does the format support infinities?
+ /** @type {tcuFloatFormat.YesNoMaybe} */ this.m_hasNaN = hasNaN === undefined ? tcuFloatFormat.YesNoMaybe.MAYBE : hasNaN; // Does the format support NaNs?
+ /** @type {boolean} */ this.m_exactPrecision = exactPrecision; // Are larger precisions disallowed?
+ /** @type {number} */ this.m_maxValue = tcuFloatFormat.computeMaxValue(maxExp, fractionBits);
+ };
+
+ /**
+ * @return {number}
+ */
+ tcuFloatFormat.FloatFormat.prototype.getMinExp = function() {
+ return this.m_minExp;
+ };
+
+ /**
+ * @return {number}
+ */
+ tcuFloatFormat.FloatFormat.prototype.getMaxExp = function() {
+ return this.m_maxExp;
+ };
+
+ /**
+ * @return {number}
+ */
+ tcuFloatFormat.FloatFormat.prototype.getMaxValue = function() {
+ return this.m_maxValue;
+ };
+
+ /**
+ * @return {number}
+ */
+ tcuFloatFormat.FloatFormat.prototype.getFractionBits = function() {
+ return this.m_fractionBits;
+ };
+
+ /**
+ * @return {tcuFloatFormat.YesNoMaybe}
+ */
+ tcuFloatFormat.FloatFormat.prototype.hasSubnormal = function() {
+ return this.m_hasSubnormal;
+ };
+
+ /**
+ * @return {tcuFloatFormat.YesNoMaybe}
+ */
+ tcuFloatFormat.FloatFormat.prototype.hasInf = function() {
+ return this.m_hasInf;
+ };
+
+ /**
+ * @param {number} x
+ * @param {number} count
+ * @return {number}
+ */
+ tcuFloatFormat.FloatFormat.prototype.ulp = function(x, count) {
+ var breakdown = deMath.deFractExp(Math.abs(x));
+ /** @type {number} */ var exp = breakdown.exponent;
+ /** @type {number} */ var frac = breakdown.significand;
+
+ if (isNaN(frac))
+ return NaN;
+ else if (!isFinite(frac))
+ return deMath.deLdExp(1.0, this.m_maxExp - this.m_fractionBits);
+ else if (frac == 1.0) {
+ // Harrison's ULP: choose distance to closest (i.e. next lower) at binade
+ // boundary.
+ --exp;
+ } else if (frac == 0.0)
+ exp = this.m_minExp;
+
+ // ULP cannot be lower than the smallest quantum.
+ exp = Math.max(exp, this.m_minExp);
+
+ /** @type {number} */ var oneULP = deMath.deLdExp(1.0, exp - this.m_fractionBits);
+ // ScopedRoundingMode ctx (DE_ROUNDINGMODE_TO_POSITIVE_INF);
+
+ return oneULP * count;
+ };
+
+ /**
+ * Return the difference between the given nominal exponent and
+ * the exponent of the lowest significand bit of the
+ * representation of a number with this format.
+ * For normal numbers this is the number of significand bits, but
+ * for subnormals it is less and for values of exp where 2^exp is too
+ * small to represent it is <0
+ * @param {number} exp
+ * @return {number}
+ */
+ tcuFloatFormat.FloatFormat.prototype.exponentShift = function(exp) {
+ return this.m_fractionBits - Math.max(this.m_minExp - exp, 0);
+ };
+
+ /**
+ * @param {number} d
+ * @param {boolean} upward
+ * @return {number}
+ */
+ tcuFloatFormat.FloatFormat.prototype.round = function(d, upward) {
+ var breakdown = deMath.deFractExp(d);
+ /** @type {number} */ var exp = breakdown.exponent;
+ /** @type {number} */ var frac = breakdown.significand;
+
+ var shift = this.exponentShift(exp);
+ var shiftFrac = deMath.deLdExp(frac, shift);
+ var roundFrac = upward ? Math.ceil(shiftFrac) : Math.floor(shiftFrac);
+
+ return deMath.deLdExp(roundFrac, exp - shift);
+ };
+
+ /**
+ * Return the range of numbers that `d` might be converted to in the
+ * floatformat, given its limitations with infinities, subnormals and maximum
+ * exponent.
+ * @param {number} d
+ * @return {tcuInterval.Interval}
+ */
+ tcuFloatFormat.FloatFormat.prototype.clampValue = function(d) {
+ /** @type {number} */ var rSign = deMath.deSign(d);
+ /** @type {number} */ var rExp = 0;
+
+ // DE_ASSERT(!isNaN(d));
+
+ var breakdown = deMath.deFractExp(d);
+ rExp = breakdown.exponent;
+ if (rExp < this.m_minExp)
+ return tcuFloatFormat.chooseInterval(this.m_hasSubnormal, new tcuInterval.Interval(rSign * 0.0), new tcuInterval.Interval(d));
+ else if (!isFinite(d) || rExp > this.m_maxExp)
+ return tcuFloatFormat.chooseInterval(this.m_hasInf, new tcuInterval.Interval(rSign * this.getMaxValue()), new tcuInterval.Interval(rSign * Number.POSITIVE_INFINITY));
+
+ return new tcuInterval.Interval(d);
+ };
+
+ /**
+ * @param {number} d
+ * @param {boolean} upward
+ * @param {boolean} roundUnderOverflow
+ * @return {number}
+ */
+ tcuFloatFormat.FloatFormat.prototype.roundOutDir = function(d, upward, roundUnderOverflow) {
+ var breakdown = deMath.deFractExp(d);
+ var exp = breakdown.exponent;
+
+ if (roundUnderOverflow && exp > this.m_maxExp && (upward == (d < 0.0)))
+ return deMath.deSign(d) * this.getMaxValue();
+ else
+ return this.round(d, upward);
+ };
+
+ /**
+ * @param {tcuInterval.Interval} x
+ * @param {boolean} roundUnderOverflow
+ * @return {tcuInterval.Interval}
+ */
+ tcuFloatFormat.FloatFormat.prototype.roundOut = function(x, roundUnderOverflow) {
+ /** @type {tcuInterval.Interval} */ var ret = x.nan();
+
+ if (!x.empty()) {
+ var a = new tcuInterval.Interval(this.roundOutDir(x.lo(), false, roundUnderOverflow));
+ var b = new tcuInterval.Interval(this.roundOutDir(x.hi(), true, roundUnderOverflow));
+ ret.operatorOrAssignBinary(tcuInterval.withIntervals(a, b));
+ }
+ return ret;
+ };
+
+ //! Return the range of numbers that might be used with this format to
+ //! represent a number within `x`.
+ /**
+ * @param {tcuInterval.Interval} x
+ * @return {tcuInterval.Interval}
+ */
+ tcuFloatFormat.FloatFormat.prototype.convert = function(x) {
+ /** @type {tcuInterval.Interval} */ var ret = new tcuInterval.Interval();
+ /** @type {tcuInterval.Interval} */ var tmp = x;
+
+ if (x.hasNaN()) {
+ // If NaN might be supported, NaN is a legal return value
+ if (this.m_hasNaN != tcuFloatFormat.YesNoMaybe.NO)
+ ret.operatorOrAssignBinary(new tcuInterval.Interval(NaN));
+
+ // If NaN might not be supported, any (non-NaN) value is legal,
+ // _subject_ to clamping. Hence we modify tmp, not ret.
+ if (this.m_hasNaN != tcuFloatFormat.YesNoMaybe.YES)
+ tmp = tcuInterval.unbounded();
+ }
+
+ // Round both bounds _inwards_ to closest representable values.
+ if (!tmp.empty())
+ ret.operatorOrAssignBinary(
+ this.clampValue(this.round(tmp.lo(), true)).operatorOrBinary(
+ this.clampValue(this.round(tmp.hi(), false))));
+
+ // If this format's precision is not exact, the (possibly out-of-bounds)
+ // original value is also a possible result.
+ if (!this.m_exactPrecision)
+ ret.operatorOrAssignBinary(x);
+
+ return ret;
+ };
+
+ /**
+ * @param {number} x
+ * @return {string}
+ */
+ tcuFloatFormat.FloatFormat.prototype.floatToHex = function(x) {
+ if (isNaN(x))
+ return 'NaN';
+ else if (!isFinite(x))
+ return (x < 0.0 ? '-' : '+') + ('inf');
+ else if (x == 0.0) // \todo [2014-03-27 lauri] Negative zero
+ return '0.0';
+
+ return x.toString(10);
+ // TODO
+ // var breakdown = deMath.deFractExp(deAbs(x));
+ // /** @type{number} */ var exp = breakdown.exponent;
+ // /** @type{number} */ var frac = breakdown.significand;
+ // /** @type{number} */ var shift = this.exponentShift(exp);
+ // /** @type{number} */ var bits = deUint64(deLdExp(frac, shift));
+ // /** @type{number} */ var whole = bits >> m_fractionBits;
+ // /** @type{number} */ var fraction = bits & ((deUint64(1) << m_fractionBits) - 1);
+ // /** @type{number} */ var exponent = exp + m_fractionBits - shift;
+ // /** @type{number} */ var numDigits = (this.m_fractionBits + 3) / 4;
+ // /** @type{number} */ var aligned = fraction << (numDigits * 4 - m_fractionBits);
+ // /** @type{string} */ var oss = '';
+
+ // oss + (x < 0 ? '-' : '')
+ // + '0x' + whole + '.'
+ // + std::hex + std::setw(numDigits) + std::setfill('0') + aligned
+ // + 'p' + std::dec + std::setw(0) + exponent;
+ //return oss;
+ };
+
+ /**
+ * @param {tcuInterval.Interval} interval
+ * @return {string}
+ */
+ tcuFloatFormat.FloatFormat.prototype.intervalToHex = function(interval) {
+ if (interval.empty())
+ return interval.hasNaN() ? '{ NaN }' : '{}';
+
+ else if (interval.lo() == interval.hi())
+ return ((interval.hasNaN() ? '{ NaN, ' : '{ ') +
+ this.floatToHex(interval.lo()) + ' }');
+ else if (interval == tcuInterval.unbounded(true))
+ return '<any>';
+
+ return ((interval.hasNaN() ? '{ NaN } | ' : '') +
+ '[' + this.floatToHex(interval.lo()) + ', ' + this.floatToHex(interval.hi()) + ']');
+ };
+
+ /**
+ * @return {tcuFloatFormat.FloatFormat}
+ */
+ tcuFloatFormat.nativeDouble = function() {
+ return new tcuFloatFormat.FloatFormat(-1021 - 1, // min_exponent
+ 1024 - 1, // max_exponent
+ 53 - 1, // digits
+ true, // has_denorm
+ tcuFloatFormat.YesNoMaybe.YES, // has_infinity
+ tcuFloatFormat.YesNoMaybe.YES, // has_quiet_nan
+ tcuFloatFormat.YesNoMaybe.YES); // has_denorm
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFuzzyImageCompare.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFuzzyImageCompare.js
new file mode 100644
index 0000000000..828d830100
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuFuzzyImageCompare.js
@@ -0,0 +1,338 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuFuzzyImageCompare');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.common.tcuTextureUtil');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.delibs.debase.deRandom');
+
+goog.scope(function() {
+
+var tcuFuzzyImageCompare = framework.common.tcuFuzzyImageCompare;
+var deMath = framework.delibs.debase.deMath;
+var deRandom = framework.delibs.debase.deRandom;
+var tcuTexture = framework.common.tcuTexture;
+var tcuTextureUtil = framework.common.tcuTextureUtil;
+
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+ /**
+ * tcuFuzzyImageCompare.FuzzyCompareParams struct
+ * @constructor
+ * @param {number=} maxSampleSkip_
+ * @param {number=} minErrThreshold_
+ * @param {number=} errExp_
+ */
+ tcuFuzzyImageCompare.FuzzyCompareParams = function(maxSampleSkip_, minErrThreshold_, errExp_) {
+ /** @type {number} */ this.maxSampleSkip = maxSampleSkip_ === undefined ? 8 : maxSampleSkip_;
+ /** @type {number} */ this.minErrThreshold = minErrThreshold_ === undefined ? 4 : minErrThreshold_;
+ /** @type {number} */ this.errExp = errExp_ === undefined ? 4.0 : errExp_;
+ };
+
+ /**
+ * @param {Array<number>} v
+ * @return {Array<number>}
+ */
+ tcuFuzzyImageCompare.roundArray4ToUint8Sat = function(v) {
+ return [
+ deMath.clamp(Math.trunc(v[0] + 0.5), 0, 255),
+ deMath.clamp(Math.trunc(v[1] + 0.5), 0, 255),
+ deMath.clamp(Math.trunc(v[2] + 0.5), 0, 255),
+ deMath.clamp(Math.trunc(v[3] + 0.5), 0, 255)
+ ];
+ };
+
+ /**
+ * @param {Array<number>} pa
+ * @param {Array<number>} pb
+ * @param {number} minErrThreshold
+ * @return {number}
+ */
+ tcuFuzzyImageCompare.compareColors = function(pa, pb, minErrThreshold) {
+ /** @type {number}*/ var r = Math.max(Math.abs(pa[0] - pb[0]) - minErrThreshold, 0);
+ /** @type {number}*/ var g = Math.max(Math.abs(pa[1] - pb[1]) - minErrThreshold, 0);
+ /** @type {number}*/ var b = Math.max(Math.abs(pa[2] - pb[2]) - minErrThreshold, 0);
+ /** @type {number}*/ var a = Math.max(Math.abs(pa[3] - pb[3]) - minErrThreshold, 0);
+
+ /** @type {number}*/ var scale = 1.0 / (255 - minErrThreshold);
+ /** @type {number}*/ var sqSum = (r * r + g * g + b * b + a * a) * (scale * scale);
+
+ return Math.sqrt(sqSum);
+ };
+
+ /**
+ * @param {tcuTexture.RGBA8View} src
+ * @param {number} u
+ * @param {number} v
+ * @param {number} NumChannels
+ * @return {Array<number>}
+ */
+ tcuFuzzyImageCompare.bilinearSample = function(src, u, v, NumChannels) {
+ /** @type {number}*/ var w = src.width;
+ /** @type {number}*/ var h = src.height;
+
+ /** @type {number}*/ var x0 = Math.floor(u - 0.5);
+ /** @type {number}*/ var x1 = x0 + 1;
+ /** @type {number}*/ var y0 = Math.floor(v - 0.5);
+ /** @type {number}*/ var y1 = y0 + 1;
+
+ /** @type {number}*/ var i0 = deMath.clamp(x0, 0, w - 1);
+ /** @type {number}*/ var i1 = deMath.clamp(x1, 0, w - 1);
+ /** @type {number}*/ var j0 = deMath.clamp(y0, 0, h - 1);
+ /** @type {number}*/ var j1 = deMath.clamp(y1, 0, h - 1);
+
+ /** @type {number}*/ var a = (u - 0.5) - Math.floor(u - 0.5);
+ /** @type {number}*/ var b = (v - 0.5) - Math.floor(v - 0.5);
+
+ /** @type {Array<number>} */ var p00 = src.read(i0, j0, NumChannels);
+ /** @type {Array<number>} */ var p10 = src.read(i1, j0, NumChannels);
+ /** @type {Array<number>} */ var p01 = src.read(i0, j1, NumChannels);
+ /** @type {Array<number>} */ var p11 = src.read(i1, j1, NumChannels);
+ /** @type {number} */ var dst = 0;
+
+ // Interpolate.
+ /** @type {Array<number>}*/ var f = [];
+ for (var c = 0; c < NumChannels; c++) {
+ f[c] = p00[c] * (1.0 - a) * (1.0 - b) +
+ (p10[c] * a * (1.0 - b)) +
+ (p01[c] * (1.0 - a) * b) +
+ (p11[c] * a * b);
+ }
+
+ return tcuFuzzyImageCompare.roundArray4ToUint8Sat(f);
+ };
+
+ /**
+ * @param {tcuTexture.RGBA8View} dst
+ * @param {tcuTexture.RGBA8View} src
+ * @param {number} shiftX
+ * @param {number} shiftY
+ * @param {Array<number>} kernelX
+ * @param {Array<number>} kernelY
+ * @param {number} DstChannels
+ * @param {number} SrcChannels
+ */
+ tcuFuzzyImageCompare.separableConvolve = function(dst, src, shiftX, shiftY, kernelX, kernelY, DstChannels, SrcChannels) {
+ DE_ASSERT(dst.width == src.width && dst.height == src.height);
+
+ /** @type {tcuTexture.TextureLevel} */ var tmp = new tcuTexture.TextureLevel(dst.getFormat(), dst.height, dst.width);
+ var tmpView = new tcuTexture.RGBA8View(tmp.getAccess());
+
+ /** @type {number} */ var kw = kernelX.length;
+ /** @type {number} */ var kh = kernelY.length;
+
+ /** @type {Array<number>} */ var sum = [];
+ /** @type {number} */ var f;
+ /** @type {Array<number>} */ var p;
+
+ // Horizontal pass
+ // \note Temporary surface is written in column-wise order
+ for (var j = 0; j < src.height; j++) {
+ for (var i = 0; i < src.width; i++) {
+ sum[0] = sum[1] = sum[2] = sum[3] = 0;
+ for (var kx = 0; kx < kw; kx++) {
+ f = kernelX[kw - kx - 1];
+ p = src.read(deMath.clamp(i + kx - shiftX, 0, src.width - 1), j, SrcChannels);
+ sum = deMath.add(sum, deMath.scale(p, f));
+ }
+
+ sum = tcuFuzzyImageCompare.roundArray4ToUint8Sat(sum);
+ tmpView.write(j, i, sum, DstChannels);
+ }
+ }
+
+ // Vertical pass
+ for (var j = 0; j < src.height; j++) {
+ for (var i = 0; i < src.width; i++) {
+ sum[0] = sum[1] = sum[2] = sum[3] = 0;
+ for (var ky = 0; ky < kh; ky++) {
+ f = kernelY[kh - ky - 1];
+ p = tmpView.read(deMath.clamp(j + ky - shiftY, 0, tmpView.width - 1), i, DstChannels);
+ sum = deMath.add(sum, deMath.scale(p, f));
+ }
+
+ sum = tcuFuzzyImageCompare.roundArray4ToUint8Sat(sum);
+ dst.write(i, j, sum, DstChannels);
+ }
+ }
+ };
+
+ /**
+ * @param {tcuFuzzyImageCompare.FuzzyCompareParams} params
+ * @param {deRandom.Random} rnd
+ * @param {Array<number>} pixel
+ * @param {tcuTexture.RGBA8View} surface
+ * @param {number} x
+ * @param {number} y
+ * @param {number} NumChannels
+ * @return {number}
+ */
+ tcuFuzzyImageCompare.compareToNeighbor = function(params, rnd, pixel, surface, x, y, NumChannels) {
+ /** @type {number} */ var minErr = 100;
+
+ // (x, y) + (0, 0)
+ minErr = Math.min(minErr, tcuFuzzyImageCompare.compareColors(pixel, surface.read(x, y, NumChannels), params.minErrThreshold));
+ if (minErr == 0.0)
+ return minErr;
+
+ // Area around (x, y)
+ /** @type {Array<Array.<number>>} */ var s_coords =
+ [
+ [-1, -1],
+ [0, -1],
+ [1, -1],
+ [-1, 0],
+ [1, 0],
+ [-1, 1],
+ [0, 1],
+ [1, 1]
+ ];
+
+ /** @type {number} */ var dx;
+ /** @type {number} */ var dy;
+
+ for (var d = 0; d < s_coords.length; d++) {
+ dx = x + s_coords[d][0];
+ dy = y + s_coords[d][1];
+
+ if (!deMath.deInBounds32(dx, 0, surface.width) || !deMath.deInBounds32(dy, 0, surface.height))
+ continue;
+
+ minErr = Math.min(minErr, tcuFuzzyImageCompare.compareColors(pixel, surface.read(dx, dy, NumChannels), params.minErrThreshold));
+ if (minErr == 0.0)
+ return minErr;
+ }
+
+ // Random bilinear-interpolated samples around (x, y)
+ for (var s = 0; s < 32; s++) {
+ dx = x + rnd.getFloat() * 2.0 - 0.5;
+ dy = y + rnd.getFloat() * 2.0 - 0.5;
+
+ /** @type {Array<number>} */ var sample = tcuFuzzyImageCompare.bilinearSample(surface, dx, dy, NumChannels);
+
+ minErr = Math.min(minErr, tcuFuzzyImageCompare.compareColors(pixel, sample, params.minErrThreshold));
+ if (minErr == 0.0)
+ return minErr;
+ }
+
+ return minErr;
+ };
+
+ /**
+ * @param {Array<number>} c
+ * @return {number}
+ */
+ tcuFuzzyImageCompare.toGrayscale = function(c) {
+ return 0.2126 * c[0] + 0.7152 * c[1] + 0.0722 * c[2];
+ };
+
+ /**
+ * @param {tcuTexture.TextureFormat} format
+ * @return {boolean}
+ */
+ tcuFuzzyImageCompare.isFormatSupported = function(format) {
+ return format.type == tcuTexture.ChannelType.UNORM_INT8 && (format.order == tcuTexture.ChannelOrder.RGB || format.order == tcuTexture.ChannelOrder.RGBA);
+ };
+
+ /**
+ * @param {tcuFuzzyImageCompare.FuzzyCompareParams} params
+ * @param {tcuTexture.ConstPixelBufferAccess} ref
+ * @param {tcuTexture.ConstPixelBufferAccess} cmp
+ * @param {tcuTexture.PixelBufferAccess} errorMask
+ * @return {number}
+ */
+ tcuFuzzyImageCompare.fuzzyCompare = function(params, ref, cmp, errorMask) {
+ assertMsgOptions(ref.getWidth() == cmp.getWidth() && ref.getHeight() == cmp.getHeight(),
+ 'Reference and result images have different dimensions', false, true);
+
+ assertMsgOptions(ref.getWidth() == errorMask.getWidth() && ref.getHeight() == errorMask.getHeight(),
+ 'Reference and error mask images have different dimensions', false, true);
+
+ if (!tcuFuzzyImageCompare.isFormatSupported(ref.getFormat()) || !tcuFuzzyImageCompare.isFormatSupported(cmp.getFormat()))
+ throw new Error('Unsupported format in fuzzy comparison');
+
+ /** @type {number} */ var width = ref.getWidth();
+ /** @type {number} */ var height = ref.getHeight();
+ /** @type {deRandom.Random} */ var rnd = new deRandom.Random(667);
+
+ // Filtered
+ /** @type {tcuTexture.TextureLevel} */ var refFiltered = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height);
+ /** @type {tcuTexture.TextureLevel} */ var cmpFiltered = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height);
+
+ var refView = new tcuTexture.RGBA8View(ref);
+ var cmpView = new tcuTexture.RGBA8View(cmp);
+ var refFilteredView = new tcuTexture.RGBA8View(tcuTexture.PixelBufferAccess.newFromTextureLevel(refFiltered));
+ var cmpFilteredView = new tcuTexture.RGBA8View(tcuTexture.PixelBufferAccess.newFromTextureLevel(cmpFiltered));
+
+ // Kernel = {0.15, 0.7, 0.15}
+ /** @type {Array<number>} */ var kernel = [0.1, 0.8, 0.1];
+ /** @type {number} */ var shift = Math.floor((kernel.length - 1) / 2);
+
+ switch (ref.getFormat().order) {
+ case tcuTexture.ChannelOrder.RGBA: tcuFuzzyImageCompare.separableConvolve(refFilteredView, refView, shift, shift, kernel, kernel, 4, 4); break;
+ case tcuTexture.ChannelOrder.RGB: tcuFuzzyImageCompare.separableConvolve(refFilteredView, refView, shift, shift, kernel, kernel, 4, 3); break;
+ default:
+ throw new Error('tcuFuzzyImageCompare.fuzzyCompare - Invalid ChannelOrder');
+ }
+
+ switch (cmp.getFormat().order) {
+ case tcuTexture.ChannelOrder.RGBA: tcuFuzzyImageCompare.separableConvolve(cmpFilteredView, cmpView, shift, shift, kernel, kernel, 4, 4); break;
+ case tcuTexture.ChannelOrder.RGB: tcuFuzzyImageCompare.separableConvolve(cmpFilteredView, cmpView, shift, shift, kernel, kernel, 4, 3); break;
+ default:
+ throw new Error('tcuFuzzyImageCompare.fuzzyCompare - Invalid ChannelOrder');
+ }
+
+ /** @type {number} */ var numSamples = 0;
+ /** @type {number} */ var errSum = 0.0;
+
+ // Clear error mask to green.
+ errorMask.clear([0.0, 1.0, 0.0, 1.0]);
+
+ for (var y = 1; y < height - 1; y++) {
+ for (var x = 1; x < width - 1; x += params.maxSampleSkip > 0 ? rnd.getInt(0, params.maxSampleSkip) : 1) {
+ /** @type {number} */ var err = Math.min(tcuFuzzyImageCompare.compareToNeighbor(params, rnd, refFilteredView.read(x, y, 4), cmpFilteredView, x, y, 4),
+ tcuFuzzyImageCompare.compareToNeighbor(params, rnd, cmpFilteredView.read(x, y, 4), refFilteredView, x, y, 4));
+
+ err = Math.pow(err, params.errExp);
+
+ errSum += err;
+ numSamples += 1;
+
+ // Build error image.
+ /** @type {number} */ var red = err * 500.0;
+ /** @type {number} */ var luma = tcuFuzzyImageCompare.toGrayscale(cmp.getPixel(x, y));
+ /** @type {number} */ var rF = 0.7 + 0.3 * luma;
+ errorMask.setPixel([red * rF, (1.0 - red) * rF, 0.0, 1.0], x, y);
+
+ }
+ }
+
+ // Scale error sum based on number of samples taken
+ errSum *= ((width - 2) * (height - 2)) / numSamples;
+
+ return errSum;
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuImageCompare.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuImageCompare.js
new file mode 100644
index 0000000000..3a8138ef23
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuImageCompare.js
@@ -0,0 +1,757 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuImageCompare');
+goog.require('framework.common.tcuBilinearImageCompare');
+goog.require('framework.common.tcuFloat');
+goog.require('framework.common.tcuFuzzyImageCompare');
+goog.require('framework.common.tcuLogImage');
+goog.require('framework.common.tcuRGBA');
+goog.require('framework.common.tcuSurface');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.common.tcuTextureUtil');
+goog.require('framework.delibs.debase.deMath');
+
+goog.scope(function() {
+
+var tcuImageCompare = framework.common.tcuImageCompare;
+var tcuSurface = framework.common.tcuSurface;
+var deMath = framework.delibs.debase.deMath;
+var tcuTexture = framework.common.tcuTexture;
+var tcuTextureUtil = framework.common.tcuTextureUtil;
+var tcuFloat = framework.common.tcuFloat;
+var tcuFuzzyImageCompare = framework.common.tcuFuzzyImageCompare;
+var tcuBilinearImageCompare = framework.common.tcuBilinearImageCompare;
+var tcuRGBA = framework.common.tcuRGBA;
+var tcuLogImage = framework.common.tcuLogImage;
+
+/**
+ * @enum
+ */
+tcuImageCompare.CompareLogMode = {
+ EVERYTHING: 0,
+ RESULT: 1,
+ ON_ERROR: 2
+};
+
+/**
+ * @param {framework.common.tcuTexture.ConstPixelBufferAccess} result
+ * @param {framework.common.tcuTexture.ConstPixelBufferAccess} reference
+ * @param {framework.common.tcuTexture.ConstPixelBufferAccess=} diff
+ */
+tcuImageCompare.displayImages = function(result, reference, diff) {
+ var limits = tcuImageCompare.computeScaleAndBias(reference, result);
+ tcuLogImage.logImage('Result', '', result, limits.scale, limits.bias);
+ tcuLogImage.logImage('Reference', '', reference, limits.scale, limits.bias);
+ if (diff)
+ tcuLogImage.logImage('Error', 'error mask', diff);
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @return {{scale: Array<number>, bias: Array<number>}}
+ */
+tcuImageCompare.computeScaleAndBias = function(reference, result) {
+ var minVal = [];
+ var maxVal = [];
+ var scale = [];
+ var bias = [];
+
+ var eps = 0.0001;
+ var referenceRange = tcuTextureUtil.estimatePixelValueRange(reference);
+ var resultRange = tcuTextureUtil.estimatePixelValueRange(result);
+
+ minVal[0] = Math.min(referenceRange[0][0], resultRange[0][0]);
+ minVal[1] = Math.min(referenceRange[0][1], resultRange[0][1]);
+ minVal[2] = Math.min(referenceRange[0][2], resultRange[0][2]);
+ minVal[3] = Math.min(referenceRange[0][3], resultRange[0][3]);
+
+ maxVal[0] = Math.max(referenceRange[1][0], resultRange[1][0]);
+ maxVal[1] = Math.max(referenceRange[1][1], resultRange[1][1]);
+ maxVal[2] = Math.max(referenceRange[1][2], resultRange[1][2]);
+ maxVal[3] = Math.max(referenceRange[1][3], resultRange[1][3]);
+
+ for (var c = 0; c < 4; c++) {
+ if (maxVal[c] - minVal[c] < eps) {
+ scale[c] = (maxVal[c] < eps) ? 1 : (1 / maxVal[c]);
+ bias[c] = (c == 3) ? (1 - maxVal[c] * scale[c]) : (0 - minVal[c] * scale[c]);
+ } else {
+ scale[c] = 1 / (maxVal[c] - minVal[c]);
+ bias[c] = 0 - minVal[c] * scale[c];
+ }
+ }
+ return {
+ scale: scale,
+ bias: bias
+ };
+};
+
+/**
+ * \brief Per-pixel threshold-based comparison
+ *
+ * This compare computes per-pixel differences between result and reference
+ * image. Comparison fails if any pixels exceed the given threshold value.
+ *
+ * This comparison can be used for integer- and fixed-point texture formats.
+ * Difference is computed in integer space.
+ *
+ * On failure error image is generated that shows where the failing pixels
+ * are.
+ *
+ * @param {string} imageSetName Name for image set when logging results
+ * @param {string} imageSetDesc Description for image set
+ * @param {tcuTexture.ConstPixelBufferAccess} reference Reference image
+ * @param {tcuTexture.ConstPixelBufferAccess} result Result image
+ * @param {Array<number>} threshold Maximum allowed difference
+ * @param {tcuImageCompare.CompareLogMode=} logMode
+ * @param {Array< Array<number> >} skipPixels pixels that are skipped comparison
+ * @return {boolean} true if comparison passes, false otherwise
+ */
+ tcuImageCompare.intThresholdCompare = function(imageSetName, imageSetDesc, reference, result, threshold, logMode, skipPixels) {
+ var width = reference.getWidth();
+ var height = reference.getHeight();
+ var depth = reference.getDepth();
+ var errorMask = new tcuSurface.Surface(width, height);
+
+ var maxDiff = [0, 0, 0, 0];
+ // var pixelBias = [0, 0, 0, 0]; // Vec4 // TODO: check, only used in computeScaleAndBias, which is not included
+ // var pixelScale = [1, 1, 1, 1]; // Vec4 // TODO: check, only used in computeScaleAndBias
+
+ assertMsgOptions(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth,
+ 'Reference and result images have different dimensions', false, true);
+
+ for (var z = 0; z < depth; z++) {
+ for (var y = 0; y < height; y++) {
+ for (var x = 0; x < width; x++) {
+ if (skipPixels && skipPixels.length > 0) {
+ var skip = false;
+ for (var ii = 0; ii < skipPixels.length; ++ii) {
+ var refZ = (skipPixels[ii].length > 2 ? skipPixels[ii][2] : 0);
+ if (x == skipPixels[ii][0] && y == skipPixels[ii][1] && z == refZ) {
+ skip = true;
+ break;
+ }
+ }
+ if (skip)
+ continue;
+ }
+ var refPix = reference.getPixelInt(x, y, z);
+ var cmpPix = result.getPixelInt(x, y, z);
+
+ var diff = deMath.absDiff(refPix, cmpPix);
+ var isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold));
+
+ maxDiff = deMath.max(maxDiff, diff);
+ var color = [0, 255, 0, 255];
+ if (!isOk)
+ color = [255, 0, 0, 255];
+ errorMask.setPixel(x, y, color);
+ }
+ }
+ }
+
+ var compareOk = deMath.boolAll(deMath.lessThanEqual(maxDiff, threshold));
+
+ if (!compareOk) {
+ debug('Image comparison failed: max difference = ' + maxDiff + ', threshold = ' + threshold);
+ tcuImageCompare.displayImages(result, reference, errorMask.getAccess());
+ }
+
+ return compareOk;
+};
+
+/**
+ * \brief Per-pixel threshold-based deviation-ignoring comparison
+ *
+ * This compare computes per-pixel differences between result and reference
+ * image. Pixel fails the test if there is no pixel matching the given
+ * threshold value in the search volume. Comparison fails if the number of
+ * failing pixels exceeds the given limit.
+ *
+ * If the search volume contains out-of-bounds pixels, comparison can be set
+ * to either ignore these pixels in search or to accept any pixel that has
+ * out-of-bounds pixels in its search volume.
+ *
+ * This comparison can be used for integer- and fixed-point texture formats.
+ * Difference is computed in integer space.
+ *
+ * On failure error image is generated that shows where the failing pixels
+ * are.
+ *
+ * @param {string} imageSetName Name for image set when logging results
+ * @param {string} imageSetDesc Description for image set
+ * @param {tcuTexture.ConstPixelBufferAccess} reference Reference image
+ * @param {tcuTexture.ConstPixelBufferAccess} result Result image
+ * @param {Array<number>} threshold Maximum allowed difference
+ * @param {Array<number>} maxPositionDeviation Maximum allowed distance in the search volume.
+ * @param {boolean} acceptOutOfBoundsAsAnyValue Accept any pixel in the boundary region
+ * @param {number} maxAllowedFailingPixels Maximum number of failing pixels
+ * @return {boolean} true if comparison passes, false otherwise
+ */
+tcuImageCompare.intThresholdPositionDeviationErrorThresholdCompare = function(
+ imageSetName, imageSetDesc, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue, maxAllowedFailingPixels) {
+ /** @type {number} */ var width = reference.getWidth();
+ /** @type {number} */ var height = reference.getHeight();
+ /** @type {number} */ var depth = reference.getDepth();
+ /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(width, height);
+ /** @type {number} */ var numFailingPixels = tcuImageCompare.findNumPositionDeviationFailingPixels(errorMask.getAccess(), reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue);
+ var compareOk = numFailingPixels <= maxAllowedFailingPixels;
+ /** @type {Array<number>} */ var pixelBias = [0.0, 0.0, 0.0, 0.0];
+ /** @type {Array<number>} */ var pixelScale = [1.0, 1.0, 1.0, 1.0];
+
+ if (!compareOk) {
+ debug('Position deviation error threshold image comparison failed: failed pixels = ' + numFailingPixels + ', threshold = ' + threshold);
+ tcuImageCompare.displayImages(result, reference, errorMask.getAccess());
+ } else
+ tcuLogImage.logImage('Result', '', result);
+
+ /*if (!compareOk) {
+ // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
+ if (tcuTexture.getTextureChannelClass(reference.getFormat().type) != tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT ||
+ tcuTexture.getTextureChannelClass(result.getFormat().type) != tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT) {
+ computeScaleAndBias(reference, result, pixelScale, pixelBias);
+ log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
+ }
+
+ if (!compareOk)
+ log << TestLog::Message
+ << "Image comparison failed:\n"
+ << "\tallowed position deviation = " << maxPositionDeviation << "\n"
+ << "\tcolor threshold = " << threshold
+ << TestLog::EndMessage;
+ log << TestLog::Message << "Number of failing pixels = " << numFailingPixels << ", max allowed = " << maxAllowedFailingPixels << TestLog::EndMessage;
+
+ log << TestLog::ImageSet(imageSetName, imageSetDesc)
+ << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
+ << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
+ << TestLog::Image("ErrorMask", "Error mask", errorMask)
+ << TestLog::EndImageSet;
+ } else if (logMode == COMPARE_LOG_RESULT) {
+ if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
+ computePixelScaleBias(result, pixelScale, pixelBias);
+
+ log << TestLog::ImageSet(imageSetName, imageSetDesc)
+ << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
+ << TestLog::EndImageSet;
+ }*/
+
+ return compareOk;
+};
+
+/**
+ * tcuImageCompare.floatUlpThresholdCompare
+ * @param {string} imageSetName
+ * @param {string} imageSetDesc
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {Array<number>} threshold - previously used as an Uint32Array
+ * @return {boolean}
+ */
+tcuImageCompare.floatUlpThresholdCompare = function(imageSetName, imageSetDesc, reference, result, threshold) {
+ /** @type {number} */ var width = reference.getWidth();
+ /** @type {number} */ var height = reference.getHeight();
+ /** @type {number} */ var depth = reference.getDepth();
+ /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(width, height);
+
+ /** @type {Array<number>} */ var maxDiff = [0, 0, 0, 0]; // UVec4
+ // var pixelBias = [0, 0, 0, 0]; // Vec4
+ // var pixelScale = [1, 1, 1, 1]; // Vec4
+
+ assertMsgOptions(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth,
+ 'Reference and result images have different dimensions', false, true);
+
+ for (var z = 0; z < depth; z++) {
+ for (var y = 0; y < height; y++) {
+ for (var x = 0; x < width; x++) {
+ /** @type {ArrayBuffer} */ var arrayBufferRef = new ArrayBuffer(4 * 4);
+ /** @type {ArrayBuffer} */ var arrayBufferCmp = new ArrayBuffer(4 * 4);
+
+ /** @type {Array<number>} */ var refPix = reference.getPixel(x, y, z); // getPixel returns a Vec4 pixel color
+
+ /** @type {Array<number>} */ var cmpPix = result.getPixel(x, y, z); // getPixel returns a Vec4 pixel color
+
+ /** @type {Uint32Array} */ var refBits = new Uint32Array(arrayBufferRef); // UVec4
+ /** @type {Uint32Array} */ var cmpBits = new Uint32Array(arrayBufferCmp); // UVec4
+
+ // Instead of memcpy(), which is the way to do float->uint32 reinterpretation in C++
+ for (var i = 0; i < refPix.length; i++) {
+ refBits[i] = tcuFloat.convertFloat32Inline(refPix[i], tcuFloat.description32);
+ cmpBits[i] = tcuFloat.convertFloat32Inline(cmpPix[i], tcuFloat.description32);
+ }
+
+ /** @type {Array<number>} */ var diff = deMath.absDiff(refBits, cmpBits); // UVec4
+ /** @type {boolean} */ var isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold));
+
+ maxDiff = deMath.max(maxDiff, diff);
+
+ errorMask.setPixel(x, y, isOk ? [0, 255, 0, 255] : [255, 0, 0, 255]);
+ }
+ }
+ }
+
+ /** @type {boolean} */ var compareOk = deMath.boolAll(deMath.lessThanEqual(maxDiff, threshold));
+
+ if (!compareOk) {
+ debug('Image comparison failed: max difference = ' + maxDiff + ', threshold = ' + threshold);
+ tcuImageCompare.displayImages(result, reference, errorMask.getAccess());
+ }
+
+ /*if (!compareOk || logMode == COMPARE_LOG_EVERYTHING) {
+ // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
+ if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
+ tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) {
+ computeScaleAndBias(reference, result, pixelScale, pixelBias);
+ log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
+ }
+
+ if (!compareOk)
+ log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage;
+
+ log << TestLog::ImageSet(imageSetName, imageSetDesc)
+ << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
+ << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
+ << TestLog::Image("ErrorMask", "Error mask", errorMask)
+ << TestLog::EndImageSet;
+ } else if (logMode == COMPARE_LOG_RESULT) {
+ if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
+ computePixelScaleBias(result, pixelScale, pixelBias);
+
+ log << TestLog::ImageSet(imageSetName, imageSetDesc)
+ << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
+ << TestLog::EndImageSet;
+ }*/
+
+ return compareOk;
+};
+
+/**
+ * tcuImageCompare.floatThresholdCompare
+ * @param {string} imageSetName
+ * @param {string} imageSetDesc
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {Array<number>} threshold
+ * @return {boolean}
+ */
+tcuImageCompare.floatThresholdCompare = function(imageSetName, imageSetDesc, reference, result, threshold) {
+ /** @type {number} */ var width = reference.getWidth();
+ /** @type {number} */ var height = reference.getHeight();
+ /** @type {number} */ var depth = reference.getDepth();
+ /** @type {tcuSurface.Surface} */ var errorMask = new tcuSurface.Surface(width, height);
+
+ /** @type {Array<number>} */ var maxDiff = [0, 0, 0, 0]; // Vec4
+ // var pixelBias = [0, 0, 0, 0]; // Vec4
+ // var pixelScale = [1, 1, 1, 1]; // Vec4
+
+ assertMsgOptions(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth,
+ 'Reference and result images have different dimensions', false, true);
+
+ for (var z = 0; z < depth; z++) {
+ for (var y = 0; y < height; y++) {
+ for (var x = 0; x < width; x++) {
+ var refPix = reference.getPixel(x, y, z); // Vec4
+ var cmpPix = result.getPixel(x, y, z); // Vec4
+
+ /** @type {Array<number>} */ var diff = deMath.absDiff(refPix, cmpPix); // Vec4
+ /** @type {boolean} */ var isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold));
+
+ maxDiff = deMath.max(maxDiff, diff);
+
+ errorMask.setPixel(x, y, isOk ? [0, 255, 0, 255] : [255, 0, 0, 255]);
+ }
+ }
+ }
+
+ /** @type {boolean} */ var compareOk = deMath.boolAll(deMath.lessThanEqual(maxDiff, threshold));
+
+ if (!compareOk) {
+ debug('Image comparison failed: max difference = ' + maxDiff + ', threshold = ' + threshold);
+ tcuImageCompare.displayImages(result, reference, errorMask.getAccess());
+ }
+
+ /*if (!compareOk || logMode == COMPARE_LOG_EVERYTHING) {
+ // All formats except normalized unsigned fixed point ones need remapping in order to fit into unorm channels in logged images.
+ if (tcu::getTextureChannelClass(reference.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT ||
+ tcu::getTextureChannelClass(result.getFormat().type) != tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT) {
+ computeScaleAndBias(reference, result, pixelScale, pixelBias);
+ log << TestLog::Message << "Result and reference images are normalized with formula p * " << pixelScale << " + " << pixelBias << TestLog::EndMessage;
+ }
+
+ if (!compareOk)
+ log << TestLog::Message << "Image comparison failed: max difference = " << maxDiff << ", threshold = " << threshold << TestLog::EndMessage;
+
+ log << TestLog::ImageSet(imageSetName, imageSetDesc)
+ << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
+ << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
+ << TestLog::Image("ErrorMask", "Error mask", errorMask)
+ << TestLog::EndImageSet;
+ } else if (logMode == COMPARE_LOG_RESULT) {
+ if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
+ computePixelScaleBias(result, pixelScale, pixelBias);
+
+ log << TestLog::ImageSet(imageSetName, imageSetDesc)
+ << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
+ << TestLog::EndImageSet;
+ }*/
+
+ return compareOk;
+};
+
+/**
+ * \brief Per-pixel threshold-based comparison
+ *
+ * This compare computes per-pixel differences between result and reference
+ * image. Comparison fails if any pixels exceed the given threshold value.
+ *
+ * On failure error image is generated that shows where the failing pixels
+ * are.
+ *
+ * @param {string} imageSetName Name for image set when logging results
+ * @param {string} imageSetDesc Description for image set
+ * @param {tcuSurface.Surface} reference Reference image
+ * @param {tcuSurface.Surface} result Result image
+ * @param {Array<number>} threshold Maximum allowed difference
+ * @param {tcuImageCompare.CompareLogMode=} logMode
+ * @param {Array< Array<number> >} skipPixels pixels that are skipped comparison
+ * @return {boolean} true if comparison passes, false otherwise
+ */
+tcuImageCompare.pixelThresholdCompare = function(imageSetName, imageSetDesc, reference, result, threshold, logMode, skipPixels) {
+ return tcuImageCompare.intThresholdCompare(imageSetName, imageSetDesc, reference.getAccess(), result.getAccess(), threshold, logMode, skipPixels);
+};
+
+/**
+ * @param {tcuTexture.PixelBufferAccess} errorMask
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {Array<number>} threshold
+ * @param {Array<number>} maxPositionDeviation
+ * @param {boolean} acceptOutOfBoundsAsAnyValue
+ * @return {number}
+ */
+tcuImageCompare.findNumPositionDeviationFailingPixels = function(errorMask, reference, result, threshold, maxPositionDeviation, acceptOutOfBoundsAsAnyValue) {
+ /** @type {number} */ var width = reference.getWidth();
+ /** @type {number} */ var height = reference.getHeight();
+ /** @type {number} */ var depth = reference.getDepth();
+ /** @type {number} */ var numFailingPixels = 0;
+
+ checkMessage(result.getWidth() == width && result.getHeight() == height && result.getDepth() == depth, 'Surfaces have different dimensions');
+
+ for (var z = 0; z < depth; z++) {
+ for (var y = 0; y < height; y++) {
+ for (var x = 0; x < width; x++) {
+ /** @type {Array<number>} */ var refPix = reference.getPixelInt(x, y, z);
+ /** @type {Array<number>} */ var cmpPix = result.getPixelInt(x, y, z);
+
+ // Exact match
+ /** @type {Array<number>} */ var diff = deMath.absDiff(refPix, cmpPix);
+ /** @type {boolean} */ var isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold));
+
+ if (isOk) {
+ errorMask.setPixel([0, 0xff, 0, 0xff], x, y, z);
+ continue;
+ }
+
+ // Accept over the image bounds pixels since they could be anything
+
+ if (acceptOutOfBoundsAsAnyValue &&
+ (x < maxPositionDeviation[0] || x + maxPositionDeviation[0] >= width ||
+ y < maxPositionDeviation[1] || y + maxPositionDeviation[1] >= height ||
+ z < maxPositionDeviation[2] || z + maxPositionDeviation[2] >= depth)) {
+ errorMask.setPixel([0, 0xff, 0, 0xff], x, y, z);
+ continue;
+ }
+
+ // Find matching pixels for both result and reference pixel
+
+ var pixelFoundForReference = false;
+ var pixelFoundForResult = false;
+
+ // Find deviated result pixel for reference
+
+ for (var sz = Math.max(0, z - maxPositionDeviation[2]); sz <= Math.min(depth - 1, z + maxPositionDeviation[2]) && !pixelFoundForReference; ++sz)
+ for (var sy = Math.max(0, y - maxPositionDeviation[1]); sy <= Math.min(height - 1, y + maxPositionDeviation[1]) && !pixelFoundForReference; ++sy)
+ for (var sx = Math.max(0, x - maxPositionDeviation[0]); sx <= Math.min(width - 1, x + maxPositionDeviation[0]) && !pixelFoundForReference; ++sx) {
+ /** @type {Array<number>} */ var deviatedCmpPix = result.getPixelInt(sx, sy, sz);
+ diff = deMath.absDiff(refPix, deviatedCmpPix);
+ isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold));
+
+ pixelFoundForReference |= isOk;
+ }
+
+ // Find deviated reference pixel for result
+
+ for (var sz = Math.max(0, z - maxPositionDeviation[2]); sz <= Math.min(depth - 1, z + maxPositionDeviation[2]) && !pixelFoundForResult; ++sz)
+ for (var sy = Math.max(0, y - maxPositionDeviation[1]); sy <= Math.min(height - 1, y + maxPositionDeviation[1]) && !pixelFoundForResult; ++sy)
+ for (var sx = Math.max(0, x - maxPositionDeviation[0]); sx <= Math.min(width - 1, x + maxPositionDeviation[0]) && !pixelFoundForResult; ++sx) {
+ /** @type {Array<number>} */ var deviatedRefPix = reference.getPixelInt(sx, sy, sz);
+ diff = deMath.absDiff(cmpPix, deviatedRefPix);
+ isOk = deMath.boolAll(deMath.lessThanEqual(diff, threshold));
+
+ pixelFoundForResult |= isOk;
+ }
+
+ if (pixelFoundForReference && pixelFoundForResult)
+ errorMask.setPixel([0, 0xff, 0, 0xff], x, y, z);
+ else {
+ errorMask.setPixel([0xff, 0, 0, 0xff], x, y, z);
+ ++numFailingPixels;
+ }
+ }
+ }
+ }
+
+ return numFailingPixels;
+};
+
+ /**
+ * tcuImageCompare.fuzzyCompare
+ * @param {string} imageSetName
+ * @param {string} imageSetDesc
+ * @param {tcuTexture.ConstPixelBufferAccess} reference
+ * @param {tcuTexture.ConstPixelBufferAccess} result
+ * @param {number} threshold
+ * @param {tcuImageCompare.CompareLogMode=} logMode
+ * @return {boolean}
+ */
+tcuImageCompare.fuzzyCompare = function(imageSetName, imageSetDesc, reference, result, threshold, logMode) {
+ /** @type {tcuFuzzyImageCompare.FuzzyCompareParams} */ var params = new tcuFuzzyImageCompare.FuzzyCompareParams(); // Use defaults.
+ /** @type {tcuTexture.TextureLevel} */ var errorMask = new tcuTexture.TextureLevel(
+ new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB,
+ tcuTexture.ChannelType.UNORM_INT8),
+ reference.getWidth(),
+ reference.getHeight()
+ );
+ /** @type {number} */ var difference = tcuFuzzyImageCompare.fuzzyCompare(
+ params,
+ reference,
+ result,
+ tcuTexture.PixelBufferAccess.newFromTextureLevel(errorMask)
+ );
+ /** @type {boolean} */ var isOk = difference <= threshold;
+ /** @type {Array<number>} */ var pixelBias = [0.0, 0.0, 0.0, 0.0];
+ /** @type {Array<number>} */ var pixelScale = [1.0, 1.0, 1.0, 1.0];
+
+ if (!isOk) {
+ debug('Fuzzy image comparison failed: difference = ' + difference + ', threshold = ' + threshold);
+ tcuImageCompare.displayImages(result, reference, errorMask.getAccess());
+ }
+
+ /*
+ if (!isOk || logMode == COMPARE_LOG_EVERYTHING) {
+ // Generate more accurate error mask.
+ params.maxSampleSkip = 0;
+ tcuImageCompare.fuzzyCompare(params, reference, result, errorMask.getAccess());
+
+ if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) && reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
+ computeScaleAndBias(reference, result, pixelScale, pixelBias);
+
+ if (!isOk)
+ log << TestLog::Message << "Image comparison failed: difference = " << difference << ", threshold = " << threshold << TestLog::EndMessage;
+
+ log << TestLog::ImageSet(imageSetName, imageSetDesc)
+ << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
+ << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
+ << TestLog::Image("ErrorMask", "Error mask", errorMask)
+ << TestLog::EndImageSet;
+ } else if (logMode == COMPARE_LOG_RESULT) {
+ if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
+ computePixelScaleBias(result, pixelScale, pixelBias);
+
+ log << TestLog::ImageSet(imageSetName, imageSetDesc)
+ << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
+ << TestLog::EndImageSet;
+ }
+ */
+ return isOk;
+};
+
+tcuImageCompare.unitTest = function() {
+ var width = 128;
+ var height = 128;
+
+ var weirdLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SNORM_INT32), width, height);
+ var access = weirdLevel.getAccess();
+ access.clear([0.1, 0.5, 0, 0]);
+ access.clear([0.11, 0.52, 0, 0], [0, width], [0, height / 2]);
+ access.clear([0.12, 0.52, 0, 0], [0, width], [height / 2, height / 2 + height / 8]);
+ var limits = tcuTextureUtil.computePixelScaleBias(access);
+ debug('Scale: ' + limits.scale);
+ debug('Bias: ' + limits.bias);
+ tcuLogImage.logImage('Weird', 'weird format without scaling', access);
+ tcuLogImage.logImage('Weird', 'weird format', access, limits.scale, limits.bias);
+
+ var srcLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height);
+ var dstLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height);
+ var src = srcLevel.getAccess();
+ var dst = dstLevel.getAccess();
+
+ src.clear();
+ dst.clear();
+
+ for (var i = 0; i < width - 1; i++) {
+ for (var j = 0; j < height - 1; j++) {
+ src.setPixelInt([i, j, 90, 255], i, j);
+ dst.setPixelInt([i, j, 90, 255], i + 1, j + 1);
+ }
+ }
+
+ debug('Src format: ' + src.getFormat());
+ debug('Destination: ' + dst);
+ debug(src);
+ tcuLogImage.logImage('Source', 'Source image', src);
+
+ if (!tcuImageCompare.fuzzyCompare('compare', 'compare similar images', src, dst, 0.05))
+ throw new Error('Compare should return true');
+
+ src.clear();
+ dst.clear();
+
+ for (var i = 0; i < width - 2; i++) {
+ for (var j = 0; j < height - 2; j++) {
+ src.setPixelInt([i, j, 90, 255], i, j);
+ dst.setPixelInt([i, j, 90, 255], i + 2, j + 2);
+ }
+ }
+
+ if (tcuImageCompare.fuzzyCompare('compare', 'compare different images', src, dst, 0.05))
+ throw new Error('Compare should return false');
+
+ debug('Passed');
+};
+
+tcuImageCompare.unitTest2 = function() {
+ var width = 128;
+ var height = 128;
+ var srcLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height);
+ var dstLevel = new tcuTexture.TextureLevel(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), width, height);
+ var src = srcLevel.getAccess();
+ var dst = dstLevel.getAccess();
+ var threshold = tcuRGBA.newRGBAComponents(1, 1, 1, 1);
+ debug('Threshold: ' + threshold);
+
+ src.clear();
+ dst.clear();
+
+ for (var i = 0; i < width - 1; i++) {
+ for (var j = 0; j < height - 1; j++) {
+ src.setPixelInt([i, j, 90, 255], i, j);
+ dst.setPixelInt([i, j, 90, 255], i, j);
+ }
+ }
+ if (!tcuImageCompare.bilinearCompare('compare', 'compare similar images', src, dst, threshold))
+ throw new Error('Compare should return true');
+ debug('bilinear compare the same images passed');
+
+ src.clear();
+ dst.clear();
+
+ for (var i = 0; i < width - 1; i++) {
+ for (var j = 0; j < height - 1; j++) {
+ src.setPixelInt([i, j, 90, 255], i, j);
+ dst.setPixelInt([i, j + 1, 90, 255], i, j + 1);
+ }
+ }
+ if (!tcuImageCompare.bilinearCompare('compare', 'compare similar images', src, dst, threshold))
+ throw new Error('Compare should return true');
+ debug('bilinear compare very similar images passed');
+
+ src.clear();
+ dst.clear();
+
+ for (var i = 0; i < width - 2; i++) {
+ for (var j = 0; j < height - 2; j++) {
+ src.setPixelInt([i, j, 90, 255], i, j);
+ // dst.setPixelInt([i, j, 90, 255], i + 2, j + 2);
+ }
+ }
+
+ if (tcuImageCompare.bilinearCompare('compare', 'compare different images', src, dst, threshold))
+ throw new Error('Compare should return false');
+
+ debug('bilinear compare very different images passed');
+};
+
+/**
+ * Bilinear image comparison
+ * On failure error image is generated that shows where the failing pixels
+ * are.
+ * Currently supports only RGBA, UNORM_INT8 formats
+ *
+ * @param {string} imageSetName Name for image set when logging results
+ * @param {string} imageSetDesc Description for image set
+ * @param {tcuTexture.ConstPixelBufferAccess} reference Reference image
+ * @param {tcuTexture.ConstPixelBufferAccess} result Result image
+ * @param {tcuRGBA.RGBA} threshold Maximum local difference
+ * @param {tcuImageCompare.CompareLogMode=} logMode Logging mode
+ * @return {boolean} if comparison passes, false otherwise
+ */
+tcuImageCompare.bilinearCompare = function(imageSetName, imageSetDesc, reference, result, threshold, logMode) {
+ /** @type {tcuTexture.TextureLevel} */
+ var errorMask = new tcuTexture.TextureLevel(
+ new tcuTexture.TextureFormat(
+ tcuTexture.ChannelOrder.RGB,
+ tcuTexture.ChannelType.UNORM_INT8),
+ reference.getWidth(),
+ reference.getHeight());
+
+ /** @type {boolean} */
+ var isOk = tcuBilinearImageCompare.bilinearCompare(
+ reference,
+ result,
+ tcuTexture.PixelBufferAccess.newFromTextureLevel(errorMask),
+ threshold);
+
+ if (!isOk) {
+ debug('Image comparison failed: threshold = ' + threshold);
+ tcuImageCompare.displayImages(result, reference, errorMask.getAccess());
+ }
+
+ // /* @type {Array<number>} */ var pixelBias = [0.0, 0.0, 0.0, 0.0];
+ // /* @type {Array<number>} */ var pixelScale = [1.0, 1.0, 1.0, 1.0];
+ // if (!isOk || logMode == COMPARE_LOG_EVERYTHING)
+ // {
+ // if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8) && reference.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
+ // computeScaleAndBias(reference, result, pixelScale, pixelBias);
+ //
+ // if (!isOk)
+ // log << TestLog::Message << "Image comparison failed, threshold = " << threshold << TestLog::EndMessage;
+ //
+ // log << TestLog::ImageSet(imageSetName, imageSetDesc)
+ // << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
+ // << TestLog::Image("Reference", "Reference", reference, pixelScale, pixelBias)
+ // << TestLog::Image("ErrorMask", "Error mask", errorMask)
+ // << TestLog::EndImageSet;
+ // }
+ // else if (logMode == COMPARE_LOG_RESULT)
+ // {
+ // if (result.getFormat() != TextureFormat(TextureFormat::RGBA, TextureFormat::UNORM_INT8))
+ // computePixelScaleBias(result, pixelScale, pixelBias);
+ //
+ // log << TestLog::ImageSet(imageSetName, imageSetDesc)
+ // << TestLog::Image("Result", "Result", result, pixelScale, pixelBias)
+ // << TestLog::EndImageSet;
+ // }
+
+ return isOk;
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuInterval.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuInterval.js
new file mode 100644
index 0000000000..23296c1f3f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuInterval.js
@@ -0,0 +1,609 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program Tester Core
+ * ----------------------------------------
+ *
+ * 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 Interval arithmetic and floating point precisions.
+ *//*--------------------------------------------------------------------*/
+ 'use strict';
+ goog.provide('framework.common.tcuInterval');
+ goog.require('framework.delibs.debase.deMath');
+
+ goog.scope(function() {
+
+ var tcuInterval = framework.common.tcuInterval;
+ var deMath = framework.delibs.debase.deMath;
+
+ /**
+ * @typedef {function(number):number}
+ */
+ tcuInterval.DoubleFunc1;
+
+ /**
+ * @typedef {function(number, number):number}
+ */
+ tcuInterval.DoubleFunc2;
+
+ /**
+ * @typedef {function(number,number,number):number}
+ */
+ tcuInterval.DoubleFunc3;
+
+ /**
+ * @typedef {function(number):tcuInterval.Interval}
+ */
+ tcuInterval.DoubleIntervalFunc1;
+
+ /**
+ * @typedef {function(number,number):tcuInterval.Interval}
+ */
+ tcuInterval.DoubleIntervalFunc2;
+
+ /**
+ * @typedef {function(number,number,number):tcuInterval.Interval}
+ */
+ tcuInterval.DoubleIntervalFunc3;
+
+ /**
+ * @param {function(number): number} func
+ * @param {tcuInterval.Interval} arg0
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.applyMonotone1p = function(func, arg0) {
+ /**
+ * @param {number=} x
+ * @param {number=} y
+ * @return {number}
+ */
+ var body = function(x, y) {
+ x = x || 0;
+ return func(x);
+ };
+ return tcuInterval.applyMonotone1(arg0,
+ function(x) { return tcuInterval.setInterval(body, x); });
+ };
+
+ /**
+ * @param {function(number): tcuInterval.Interval} func
+ * @param {tcuInterval.Interval} arg0
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.applyMonotone1i = function(func, arg0) {
+ return tcuInterval.withIntervals(func(arg0.lo()), func(arg0.hi()));
+ };
+
+ /**
+ * @param {function(number, number): number} func
+ * @param {tcuInterval.Interval} arg0
+ * @param {tcuInterval.Interval} arg1
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.applyMonotone2p = function(func, arg0, arg1) {
+ /**
+ * @param {number=} x
+ * @param {number=} y
+ * @return {number}
+ */
+ var body = function(x, y) {
+ x = x || 0;
+ y = y || 0;
+ return func(x, y);
+ };
+ return tcuInterval.applyMonotone2(arg0, arg1,
+ function(x, y) { return tcuInterval.setInterval(body, x, y); });
+ };
+
+ /**
+ * @param {function(number, number): tcuInterval.Interval} func
+ * @param {tcuInterval.Interval} arg0
+ * @param {tcuInterval.Interval} arg1
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.applyMonotone2i = function(func, arg0, arg1) {
+ /** @type {number} */ var lo0 = arg0.lo();
+ /** @type {number} */ var hi0 = arg0.hi();
+ /** @type {number} */ var lo1 = arg1.lo();
+ /** @type {number} */ var hi1 = arg1.hi();
+ var a = tcuInterval.withIntervals(func(lo0, lo1), func(lo0, hi1));
+ var b = tcuInterval.withIntervals(func(hi0, lo1), func(hi0, hi1));
+ return tcuInterval.withIntervals(a, b);
+ };
+
+ /**
+ * @constructor
+ * @param {number=} val
+ */
+ tcuInterval.Interval = function(val) {
+ if (val === undefined) {
+ this.m_hasNaN = false;
+ this.m_lo = Number.POSITIVE_INFINITY;
+ this.m_hi = Number.NEGATIVE_INFINITY;
+ } else {
+ this.m_hasNaN = isNaN(val);
+ this.m_lo = this.m_hasNaN ? Number.POSITIVE_INFINITY : val;
+ this.m_hi = this.m_hasNaN ? Number.NEGATIVE_INFINITY : val;
+ }
+ };
+
+ tcuInterval.Interval.prototype.toString = function() {
+ var str = 'Interval(' + this.m_lo + ', ' + this.m_hi;
+ if (this.m_hasNaN)
+ str += ', hasNaN';
+ str += ')';
+ return str;
+ };
+
+ /**
+ * @param {tcuInterval.Interval} a
+ * @param {tcuInterval.Interval} b
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.withIntervals = function(a, b) {
+ /** @type {tcuInterval.Interval} */ var interval = new tcuInterval.Interval();
+ interval.m_hasNaN = (a.m_hasNaN || b.m_hasNaN);
+ interval.m_lo = Math.min(a.m_lo, b.m_lo);
+ interval.m_hi = Math.max(a.m_hi, b.m_hi);
+ return interval;
+ };
+
+ /**
+ * @param {number} a
+ * @param {number} b
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.withNumbers = function(a, b) {
+ var x = new tcuInterval.Interval(a);
+ var y = new tcuInterval.Interval(b);
+ return tcuInterval.withIntervals(x, y);
+ };
+
+ /**
+ * @param {boolean} hasNaN_
+ * @param {number} lo_
+ * @param {number} hi_
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.withParams = function(hasNaN_, lo_, hi_) {
+ /** @type {tcuInterval.Interval} */ var interval = new tcuInterval.Interval();
+ interval.m_hasNaN = hasNaN_;
+ interval.m_lo = lo_;
+ interval.m_hi = hi_;
+ return interval;
+ };
+
+ /**
+ * @return {number}
+ */
+ tcuInterval.Interval.prototype.length = function() {
+ return this.m_hi - this.m_lo;
+ };
+
+ /**
+ * @return {number}
+ */
+ tcuInterval.Interval.prototype.lo = function() {
+ return this.m_lo;
+ };
+
+ /**
+ * @return {number}
+ */
+ tcuInterval.Interval.prototype.hi = function() {
+ return this.m_hi;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ tcuInterval.Interval.prototype.hasNaN = function() {
+ return this.m_hasNaN;
+ };
+
+ /**
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.prototype.nan = function() {
+ return this.m_hasNaN ? new tcuInterval.Interval(NaN) : new tcuInterval.Interval();
+ };
+
+ /**
+ * @return {boolean}
+ */
+ tcuInterval.Interval.prototype.empty = function() {
+ return this.m_lo > this.m_hi;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ tcuInterval.Interval.prototype.isFinite = function() {
+ return isFinite(this.m_lo) && isFinite(this.m_hi);
+ };
+
+ /**
+ * @return {boolean}
+ */
+ tcuInterval.Interval.prototype.isOrdinary = function() {
+ return !this.hasNaN() && !this.empty() && this.isFinite();
+ };
+
+ /**
+ * @param {tcuInterval.Interval} other
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.prototype.operatorOrBinary = function(other) {
+ /** @type {tcuInterval.Interval} */ var temp = new tcuInterval.Interval();
+ temp.m_hasNaN = this.m_hasNaN || other.m_hasNaN;
+ temp.m_lo = Math.min(this.m_lo, other.m_lo);
+ temp.m_hi = Math.max(this.m_hi, other.m_hi);
+ return temp;
+ };
+
+ /**
+ * @param {tcuInterval.Interval} other
+ */
+ tcuInterval.Interval.prototype.operatorOrAssignBinary = function(other) {
+ /** @type {tcuInterval.Interval} */ var temp = this.operatorOrBinary(other);
+ this.m_hasNaN = temp.m_hasNaN;
+ this.m_lo = temp.m_lo;
+ this.m_hi = temp.m_hi;
+ };
+
+ /**
+ * @param {tcuInterval.Interval} other
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.prototype.operatorAndBinary = function(other) {
+ /** @type {tcuInterval.Interval} */ var temp = new tcuInterval.Interval();
+ temp.m_hasNaN = this.m_hasNaN && other.m_hasNaN;
+ temp.m_lo = Math.max(this.m_lo, other.m_lo);
+ temp.m_hi = Math.min(this.m_hi, other.m_hi);
+ return temp;
+ };
+
+ /**
+ * @param {tcuInterval.Interval} other
+ */
+ tcuInterval.Interval.prototype.operatorAndAssignBinary = function(other) {
+ /** @type {tcuInterval.Interval} */ var temp = this.operatorAndBinary(other);
+ this.m_hasNaN = temp.m_hasNaN;
+ this.m_lo = temp.m_lo;
+ this.m_hi = temp.m_hi;
+ };
+
+ /**
+ * @param {tcuInterval.Interval} other
+ * @return {boolean}
+ */
+ tcuInterval.Interval.prototype.contains = function(other) {
+ return (other.lo() >= this.lo() && other.hi() <= this.hi() &&
+ (!other.hasNaN() || this.hasNaN()));
+ };
+
+ /**
+ * @param {tcuInterval.Interval} other
+ * @return {boolean}
+ */
+ tcuInterval.Interval.prototype.intersects = function(other) {
+ return ((other.hi() >= this.lo() && other.lo() >= this.hi()) ||
+ (other.hasNaN() && this.hasNaN()));
+ };
+
+ /**
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.prototype.operatorNegative = function() {
+ /** @type {tcuInterval.Interval} */ var temp = new tcuInterval.Interval();
+ temp.m_hasNaN = this.m_hasNaN;
+ temp.m_lo = -this.m_hi;
+ temp.m_hi = -this.m_lo;
+ return temp;
+ };
+
+ /**
+ * @param {boolean=} nan
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.unbounded = function(nan) {
+ if (nan === undefined)
+ nan = false;
+ return tcuInterval.withParams(nan, Number.NEGATIVE_INFINITY, Number.POSITIVE_INFINITY);
+ };
+
+ /**
+ * @return {number}
+ */
+ tcuInterval.Interval.prototype.midpoint = function() {
+ return 0.5 * (this.hi() + this.lo()); // returns NaN when not bounded
+ };
+
+ /**
+ * @param {tcuInterval.Interval} other
+ * @return {boolean}
+ */
+ tcuInterval.Interval.prototype.operatorCompare = function(other) {
+ return ((this.m_hasNaN == other.m_hasNaN) &&
+ ((this.empty() && other.empty()) ||
+ (this.m_lo == other.m_lo && this.m_hi == other.m_hi)));
+ };
+
+ /**
+ * @param {tcuInterval.Interval} x
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.operatorPositive = function(x) {
+ return x;
+ };
+
+ /**
+ * @param {tcuInterval.Interval} x
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.exp2 = function(x) {
+ // std::pow
+ return tcuInterval.applyMonotone2p(Math.pow, new tcuInterval.Interval(2), x);
+ };
+
+ /**
+ * @param {tcuInterval.Interval} x
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.exp = function(x) {
+ // std::exp
+ return tcuInterval.applyMonotone1p(Math.exp, x);
+ };
+
+ /**
+ * @param {tcuInterval.Interval} x
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.sign = function(x) {
+ // TODO
+ throw new Error('Unimplemented');
+ };
+
+ /**
+ * @param {tcuInterval.Interval} x
+ * @param {tcuInterval.Interval} y
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.operatorSum = function(x, y) {
+ /** @type {tcuInterval.Interval} */ var ret = new tcuInterval.Interval();
+
+ if (!x.empty() && !y.empty())
+ ret = tcuInterval.setIntervalBounds(function(dummy) {return x.lo() + y.lo();}, function(dummy) {return x.hi() + y.hi();});
+ if (x.hasNaN() || y.hasNaN())
+ ret.operatorOrAssignBinary(new tcuInterval.Interval(NaN));
+
+ return ret;
+ };
+
+ /**
+ * @param {tcuInterval.Interval} x
+ * @param {tcuInterval.Interval} y
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.operatorSub = function(x, y) {
+ /** @type {tcuInterval.Interval} */ var ret = new tcuInterval.Interval();
+
+ /**
+ * @param {number=} x
+ * @param {number=} y
+ * @return {tcuInterval.Interval}
+ */
+ var body = function(x, y) {
+ return new tcuInterval.Interval(x - y);
+ };
+
+ ret = tcuInterval.applyMonotone2(x, y, body);
+ return ret;
+ };
+
+ /**
+ * @param {tcuInterval.Interval} x
+ * @param {tcuInterval.Interval} y
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.operatorMul = function(x, y) {
+ /** @type {tcuInterval.Interval} */ var ret = new tcuInterval.Interval();
+
+ /**
+ * @param {number=} x
+ * @param {number=} y
+ * @return {tcuInterval.Interval}
+ */
+ var body = function(x, y) {
+ return new tcuInterval.Interval(x * y);
+ };
+
+ ret = tcuInterval.applyMonotone2(x, y, body);
+
+ return ret;
+ };
+
+ /**
+ * @param {tcuInterval.Interval} nom
+ * @param {tcuInterval.Interval} den
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.operatorDiv = function(nom, den) {
+ if (den.contains(new tcuInterval.Interval(0))) {
+ // \todo [2014-03-21 lauri] Non-inf endpoint when one den endpoint is
+ // zero and nom doesn't cross zero?
+ return tcuInterval.unbounded();
+ } else {
+ /** @type {tcuInterval.Interval} */ var ret = new tcuInterval.Interval();
+ /**
+ * @param {number=} x
+ * @param {number=} y
+ * @return {tcuInterval.Interval}
+ */
+ var body = function(x, y) {
+ return new tcuInterval.Interval(x / y);
+ };
+
+ ret = tcuInterval.applyMonotone2(nom, den, body);
+
+ return ret;
+ }
+ };
+
+ /**
+ * @param {tcuInterval.Interval} x
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.prototype.abs = function(x) {
+ //std::abs
+ /** @type {tcuInterval.Interval} */ var mono = tcuInterval.applyMonotone1p(Math.abs, x);
+ var zero = new tcuInterval.Interval(0);
+ if (x.contains(zero))
+ return tcuInterval.withIntervals(zero, mono);
+
+ return mono;
+ };
+
+ /**
+ * @param {tcuInterval.Interval} x
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.sqrt = function(x) {
+ return tcuInterval.applyMonotone1p(Math.sqrt, x);
+ };
+
+ /**
+ * @param {tcuInterval.Interval} x
+ * @return {tcuInterval.Interval}
+ */
+ tcuInterval.Interval.inverseSqrt = function(x) {
+ var ret = new tcuInterval.Interval(1);
+ ret = tcuInterval.Interval.operatorDiv(ret, tcuInterval.Interval.sqrt(x));
+ return ret;
+ };
+
+/**
+ * @param {function(number=, number=): number} setLow
+ * @param {function(number=, number=): number} setHigh
+ * @param {number=} arg0
+ * @param {number=} arg1
+ * @return {tcuInterval.Interval}
+ */
+tcuInterval.setIntervalBounds = function(setLow, setHigh, arg0, arg1) {
+ // TODO: No support for rounding modes. Originally, setLow() was rounded down and setHigh() rounded up
+ var lo = new tcuInterval.Interval(setLow(arg0, arg1));
+ var hi = new tcuInterval.Interval(setHigh(arg0, arg1));
+ return lo.operatorOrBinary(hi);
+};
+
+/**
+ * @param {function(number=, number=): number} set
+ * @param {number=} arg0
+ * @param {number=} arg1
+ * @return {tcuInterval.Interval}
+ */
+tcuInterval.setInterval = function(set, arg0, arg1) {
+ return tcuInterval.setIntervalBounds(set, set, arg0, arg1);
+};
+
+/**
+ * @param {tcuInterval.Interval} arg
+ * @param {function(number): tcuInterval.Interval} body
+ * @return {tcuInterval.Interval}
+ */
+tcuInterval.applyMonotone1 = function(arg, body) {
+ var ret = new tcuInterval.Interval();
+
+ if (!arg.empty()) {
+ var lo = body(arg.lo());
+ var hi = body(arg.hi());
+ ret = lo.operatorOrBinary(hi);
+ }
+
+ if (arg.hasNaN()) {
+ ret = ret.operatorOrBinary(new tcuInterval.Interval(NaN));
+ }
+
+ return ret;
+};
+
+/**
+ * TODO: Check if this function works properly
+ * @param {tcuInterval.Interval} arg0
+ * @param {tcuInterval.Interval} arg1
+ * @param {function(number, number): tcuInterval.Interval} body
+ * @return {tcuInterval.Interval}
+ */
+tcuInterval.applyMonotone2 = function(arg0, arg1, body) {
+ var ret = new tcuInterval.Interval();
+
+ if (!arg0.empty() && !arg1.empty()) {
+ var lo0 = body(arg0.lo(), arg1.lo());
+ var lo1 = body(arg0.lo(), arg1.hi());
+ var hi0 = body(arg0.hi(), arg1.lo());
+ var hi1 = body(arg0.hi(), arg1.hi());
+ var a = lo0.operatorOrBinary(hi0);
+ var b = lo1.operatorOrBinary(hi1);
+ ret = a.operatorOrBinary(b);
+ }
+
+ if (arg0.hasNaN() || arg1.hasNaN()) {
+ ret = ret.operatorOrBinary(new tcuInterval.Interval(NaN));
+ }
+
+ return ret;
+};
+
+/**
+ * TODO: Check if this function works properly
+ * @param {tcuInterval.Interval} arg0
+ * @param {tcuInterval.Interval} arg1
+ * @param {tcuInterval.Interval} arg2
+ * @param {function(number, number, number): tcuInterval.Interval} body
+ * @return {tcuInterval.Interval}
+ */
+tcuInterval.applyMonotone3 = function(arg0, arg1, arg2, body) {
+ var ret = new tcuInterval.Interval();
+
+ if (!arg0.empty() && !arg1.empty() && !arg2.empty()) {
+ var i0 = body(arg0.lo(), arg1.lo(), arg2.lo());
+ var i1 = body(arg0.lo(), arg1.lo(), arg2.hi());
+ var i2 = body(arg0.lo(), arg1.hi(), arg2.lo());
+ var i3 = body(arg0.lo(), arg1.hi(), arg2.hi());
+ var i4 = body(arg0.hi(), arg1.lo(), arg2.lo());
+ var i5 = body(arg0.hi(), arg1.lo(), arg2.hi());
+ var i6 = body(arg0.hi(), arg1.hi(), arg2.lo());
+ var i7 = body(arg0.hi(), arg1.hi(), arg2.hi());
+
+ var low = Math.min(i0.lo(), i1.lo(), i2.lo(), i3.lo(), i4.lo(), i5.lo(), i6.lo(), i7.lo());
+ var high = Math.max(i0.hi(), i1.hi(), i2.hi(), i3.hi(), i4.hi(), i5.hi(), i6.hi(), i7.hi());
+ var hasNaN = i0.hasNaN() || i1.hasNaN() || i2.hasNaN() || i3.hasNaN() || i4.hasNaN() || i5.hasNaN() || i6.hasNaN() || i7.hasNaN();
+
+ ret = tcuInterval.withParams(hasNaN, low, high);
+ }
+
+ if (arg0.hasNaN() || arg1.hasNaN() || arg2.hasNaN()) {
+ ret = ret.operatorOrBinary(new tcuInterval.Interval(NaN));
+ }
+
+ return ret;
+};
+
+/** @const */ tcuInterval.POSITIVE_INFINITY = new tcuInterval.Interval(Infinity);
+/** @const */ tcuInterval.NEGATIVE_INFINITY = new tcuInterval.Interval(-Infinity);
+/** @const */ tcuInterval.ZERO = new tcuInterval.Interval(0);
+/** @const */ tcuInterval.NAN = new tcuInterval.Interval(NaN);
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuLogImage.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuLogImage.js
new file mode 100644
index 0000000000..2dabc9060b
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuLogImage.js
@@ -0,0 +1,163 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuLogImage');
+goog.require('framework.common.tcuSurface');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.delibs.debase.deMath');
+
+goog.scope(function() {
+
+var tcuLogImage = framework.common.tcuLogImage;
+var tcuTexture = framework.common.tcuTexture;
+var tcuSurface = framework.common.tcuSurface;
+var deMath = framework.delibs.debase.deMath;
+
+/** @const */ var MAX_IMAGE_SIZE_2D = 4096;
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} src
+ */
+tcuLogImage.createImage = function(ctx, src) {
+ var w = src.getWidth();
+ var h = src.getHeight();
+ var pixelSize = src.getFormat().getPixelSize();
+ var imgData = ctx.createImageData(w, h);
+ var index = 0;
+ for (var y = 0; y < h; y++) {
+ for (var x = 0; x < w; x++) {
+ var pixel = src.getPixelInt(x, h - y - 1, 0);
+ for (var i = 0; i < pixelSize; i++) {
+ imgData.data[index] = pixel[i];
+ index = index + 1;
+ }
+ if (pixelSize < 4)
+ imgData.data[index++] = 255;
+ }
+ }
+ return imgData;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} image
+ * @param {string} info
+ */
+tcuLogImage.logImageWithInfo = function(image, info) {
+ var elem = document.getElementById('console');
+ var span = document.createElement('span');
+ tcuLogImage.logImage.counter = tcuLogImage.logImage.counter || 0;
+ var i = tcuLogImage.logImage.counter++;
+ var width = image.getWidth();
+ var height = image.getHeight();
+
+ elem.appendChild(span);
+ span.innerHTML = info + '<br> <canvas id="logImage' + i + '" width=' + width + ' height=' + height + '></canvas><br>';
+
+ var imageCanvas = document.getElementById('logImage' + i);
+ var ctx = imageCanvas.getContext('2d');
+ var data = tcuLogImage.createImage(ctx, image);
+ ctx.putImageData(data, 0, 0);
+};
+
+
+/**
+ * @param {Array<number>=} scale
+ * @param {Array<number>=} bias
+ * @return {string} HTML string to add to log.
+ */
+tcuLogImage.logScaleAndBias = function(scale, bias) {
+ if (scale && bias)
+ return '<br> Image normalized with formula p * (' + scale + ') + (' + bias + ')';
+ else if (scale)
+ return '<br> Image normalized with formula p * (' + scale + ')';
+ else if (bias)
+ return '<br> Image normalized with formula p + (' + bias + ')';
+ return '';
+};
+
+/**
+ * @param {string} name
+ * @param {string} description
+ * @param {tcuTexture.ConstPixelBufferAccess} image
+ * @param {Array<number>=} scale
+ * @param {Array<number>=} bias
+ */
+tcuLogImage.logImageRGB = function(name, description, image, scale, bias) {
+ var elem = document.getElementById('console');
+ var span = document.createElement('span');
+ var info = name + ' ' + description + '<br> ' + image;
+ if (scale || bias)
+ info += tcuLogImage.logScaleAndBias(scale, bias);
+ tcuLogImage.logImageWithInfo(image, info);
+};
+
+/**
+ * @param {string} name
+ * @param {string} description
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {Array<number>=} pixelScale
+ * @param {Array<number>=} pixelBias
+ */
+tcuLogImage.logImage = function(name, description, access, pixelScale, pixelBias) {
+ pixelScale = pixelScale || [1, 1, 1, 1];
+ pixelBias = pixelBias || [0, 0, 0, 0];
+ var format = access.getFormat();
+ var width = access.getWidth();
+ var height = access.getHeight();
+ var depth = access.getDepth();
+ var needScaling = pixelBias[0] != 0 || pixelBias[1] != 0 || pixelBias[2] != 0 || pixelBias[3] != 0 ||
+ pixelScale[0] != 1 || pixelScale[1] != 1 || pixelScale[2] != 1 || pixelScale[3] != 1;
+
+ if (depth == 1 && format.type == tcuTexture.ChannelType.UNORM_INT8 &&
+ width <= MAX_IMAGE_SIZE_2D && height <= MAX_IMAGE_SIZE_2D &&
+ (format.order == tcuTexture.ChannelOrder.RGB || tcuTexture.ChannelOrder.RGBA) &&
+ !needScaling)
+ // Fast-path.
+ tcuLogImage.logImageRGB(name, description, access);
+ else if (depth == 1) {
+ var sampler = new tcuTexture.Sampler(tcuTexture.WrapMode.CLAMP_TO_EDGE, tcuTexture.WrapMode.CLAMP_TO_EDGE, tcuTexture.WrapMode.CLAMP_TO_EDGE,
+ tcuTexture.FilterMode.LINEAR, tcuTexture.FilterMode.NEAREST);
+ var logImageSize = [width, height]; /* TODO: Add scaling */
+ var logImageAccess = new tcuSurface.Surface(width, height).getAccess();
+
+ for (var y = 0; y < logImageAccess.getHeight(); y++) {
+ for (var x = 0; x < logImageAccess.getWidth(); x++) {
+ var yf = (y + 0.5) / logImageAccess.getHeight();
+ var xf = (x + 0.5) / logImageAccess.getWidth();
+ var s = access.sample2D(sampler, sampler.minFilter, xf, yf, 0);
+
+ if (needScaling)
+ s = deMath.add(deMath.multiply(s, pixelScale), pixelBias);
+
+ logImageAccess.setPixel(s, x, y);
+ }
+ }
+ var info = name + ' ' + description + '<br> ' + access;
+ if (needScaling) {
+ info += tcuLogImage.logScaleAndBias(pixelScale, pixelBias);
+ }
+
+ tcuLogImage.logImageWithInfo(logImageAccess, info);
+ } else {
+ /* TODO: Implement */
+ }
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuMatrix.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuMatrix.js
new file mode 100644
index 0000000000..e2959ecdc2
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuMatrix.js
@@ -0,0 +1,354 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuMatrix');
+goog.require('framework.delibs.debase.deMath');
+
+goog.scope(function() {
+
+ var tcuMatrix = framework.common.tcuMatrix;
+ var deMath = framework.delibs.debase.deMath;
+
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+ /**
+ * @constructor
+ * @param {number} rows
+ * @param {number} cols
+ * @param {*=} value
+ * Initialize to identity.
+ */
+ tcuMatrix.Matrix = function(rows, cols, value) {
+ value = value == undefined ? 1 : value;
+ this.rows = rows;
+ this.cols = cols;
+ this.matrix = [];
+ for (var i = 0; i < cols; i++)
+ this.matrix[i] = [];
+ for (var row = 0; row < rows; row++)
+ for (var col = 0; col < cols; col++)
+ this.set(row, col, (row == col) ? value : 0);
+ };
+
+ /**
+ * @param {number} rows
+ * @param {number} cols
+ * @param {Array<number>} vector
+ * @return {tcuMatrix.Matrix}
+ */
+ tcuMatrix.matrixFromVector = function(rows, cols, vector) {
+ var matrix = new tcuMatrix.Matrix(rows, cols);
+ for (var row = 0; row < vector.length; row++)
+ for (var col = 0; col < vector.length; col++)
+ matrix.matrix[col][row] = row == col ? vector[row] : 0;
+ return matrix;
+ };
+
+ /**
+ * @param {number} rows
+ * @param {number} cols
+ * @param {Array<number>} src
+ * @return {tcuMatrix.Matrix}
+ */
+ tcuMatrix.matrixFromDataArray = function(rows, cols, src) {
+ var matrix = new tcuMatrix.Matrix(rows, cols);
+ for (var row = 0; row < rows; row++) {
+ for (var col = 0; col < cols; col++) {
+ matrix.matrix[col][row] = src[row * cols + col];
+ }
+ }
+ return matrix;
+ };
+
+ /**
+ * Fill the Matrix with data from array
+ * @param {number} rows
+ * @param {number} cols
+ * @param {Array<number>} array
+ * @return {tcuMatrix.Matrix}
+ */
+ tcuMatrix.matrixFromArray = function(rows, cols, array) {
+ DE_ASSERT(array.length === rows * cols);
+ var matrix = new tcuMatrix.Matrix(rows, cols);
+ for (var row = 0; row < rows; row++)
+ for (var col = 0; col < cols; col++)
+ matrix.matrix[col][row] = array[row * cols + col];
+ return matrix;
+ };
+
+ tcuMatrix.Matrix.prototype.set = function(x, y, value) {
+ this.isRangeValid(x, y);
+ this.matrix[y][x] = value;
+ };
+
+ tcuMatrix.Matrix.prototype.setRow = function(row, values) {
+ if (!deMath.deInBounds32(row, 0, this.rows))
+ throw new Error('Rows out of range');
+ if (values.length > this.cols)
+ throw new Error('Too many columns');
+ for (var col = 0; col < values.length; col++)
+ this.matrix[col][row] = values[col];
+ };
+
+ tcuMatrix.Matrix.prototype.setCol = function(col, values) {
+ if (!deMath.deInBounds32(col, 0, this.cols))
+ throw new Error('Columns out of range');
+ if (values.length > this.rows)
+ throw new Error('Too many rows');
+ for (var row = 0; row < values.length; row++)
+ this.matrix[col][row] = values[row];
+ };
+
+ tcuMatrix.Matrix.prototype.get = function(x, y) {
+ this.isRangeValid(x, y);
+ return this.matrix[y][x];
+ };
+
+ tcuMatrix.Matrix.prototype.getColumn = function(y) {
+ return this.matrix[y];
+ };
+
+ tcuMatrix.Matrix.prototype.isRangeValid = function(x, y) {
+ if (!deMath.deInBounds32(x, 0, this.rows))
+ throw new Error('Rows out of range');
+ if (!deMath.deInBounds32(y, 0, this.cols))
+ throw new Error('Columns out of range');
+ };
+
+ /**
+ * @return {Array<number>}
+ */
+ tcuMatrix.Matrix.prototype.getColumnMajorData = function() {
+ /** @type {Array<number>} */ var a = [];
+ for (var col = 0; col < this.cols; col++)
+ for (var row = 0; row < this.rows; row++)
+ a.push(this.get(row, col));
+ return a;
+ };
+
+ /**
+ * @param {tcuMatrix.Matrix} matrixA
+ * @param {tcuMatrix.Matrix} matrixB
+ * @return {tcuMatrix.Matrix}
+ */
+ tcuMatrix.add = function(matrixA, matrixB) {
+ var res = new tcuMatrix.Matrix(matrixA.rows, matrixB.cols);
+ for (var col = 0; col < matrixA.cols; col++)
+ for (var row = 0; row < matrixA.rows; row++)
+ res.set(row, col, matrixA.get(row, col) + matrixB.get(row, col));
+ return res;
+ };
+
+ /**
+ * @param {tcuMatrix.Matrix} matrixA
+ * @param {tcuMatrix.Matrix} matrixB
+ * @return {tcuMatrix.Matrix}
+ */
+ tcuMatrix.subtract = function(matrixA, matrixB) {
+ var res = new tcuMatrix.Matrix(matrixA.rows, matrixB.cols);
+ for (var col = 0; col < matrixA.cols; col++)
+ for (var row = 0; row < matrixA.rows; row++)
+ res.set(row, col, matrixA.get(row, col) - matrixB.get(row, col));
+ return res;
+ };
+
+ /**
+ * @param {tcuMatrix.Matrix} matrixA
+ * @param {tcuMatrix.Matrix} matrixB
+ * @return {tcuMatrix.Matrix}
+ * Multiplication of two matrices.
+ */
+ tcuMatrix.multiply = function(matrixA, matrixB) {
+ if (matrixA.cols != matrixB.rows)
+ throw new Error('Wrong matrices sizes');
+ var res = new tcuMatrix.Matrix(matrixA.rows, matrixB.cols);
+ for (var row = 0; row < matrixA.rows; row++)
+ for (var col = 0; col < matrixB.cols; col++) {
+ var v = 0;
+ for (var ndx = 0; ndx < matrixA.cols; ndx++)
+ v += matrixA.get(row, ndx) * matrixB.get(ndx, col);
+ res.set(row, col, v);
+ }
+ return res;
+ };
+
+ /**
+ * @param {tcuMatrix.Matrix} matrixA
+ * @param {tcuMatrix.Matrix} matrixB
+ * @return {tcuMatrix.Matrix}
+ */
+ tcuMatrix.divide = function(matrixA, matrixB) {
+ var res = new tcuMatrix.Matrix(matrixA.rows, matrixA.cols);
+ for (var col = 0; col < matrixA.cols; col++)
+ for (var row = 0; row < matrixA.rows; row++)
+ res.set(row, col, matrixA.get(row, col) / matrixB.get(row, col));
+ return res;
+ };
+
+ /**
+ * @param {tcuMatrix.Matrix} mtx
+ * @param {Array<number>} vec
+ * @return {Array<number>}
+ */
+ tcuMatrix.multiplyMatVec = function(mtx, vec) {
+ /** @type {Array<number>} */ var res = [];
+ /** @type {number} */ var value;
+ for (var row = 0; row < mtx.rows; row++) {
+ value = 0;
+ for (var col = 0; col < mtx.cols; col++)
+ value += mtx.get(row, col) * vec[col];
+ res[row] = value;
+ }
+
+ return res;
+ };
+
+ /**
+ * @param {Array<number>} vec
+ * @param {tcuMatrix.Matrix} mtx
+ * @return {Array<number>}
+ */
+ tcuMatrix.multiplyVecMat = function(vec, mtx) {
+ /** @type {Array<number>} */ var res = [];
+ /** @type {number} */ var value;
+ for (var col = 0; col < mtx.cols; col++) {
+ value = 0;
+ for (var row = 0; row < mtx.rows; row++)
+ value += mtx.get(row, col) * vec[row];
+ res[col] = value;
+ }
+
+ return res;
+ };
+
+ tcuMatrix.Matrix.prototype.toString = function() {
+ var str = 'mat' + this.cols;
+ if (this.rows !== this.cols)
+ str += 'x' + this.rows;
+ str += '(';
+ for (var col = 0; col < this.cols; col++) {
+ str += '[';
+ for (var row = 0; row < this.rows; row++) {
+ str += this.matrix[col][row];
+ if (row != this.rows - 1)
+ str += ', ';
+ }
+ str += ']';
+
+ if (col != this.cols - 1)
+ str += ', ';
+ }
+ str += ')';
+ return str;
+ };
+
+ /**
+ * @param {tcuMatrix.Matrix} mtx
+ * @param {number} scalar
+ * @return {tcuMatrix.Matrix}
+ */
+ tcuMatrix.subtractMatScal = function(mtx, scalar) {
+ /** @type {tcuMatrix.Matrix} */ var res = new tcuMatrix.Matrix(mtx.rows, mtx.cols);
+ for (var col = 0; col < mtx.cols; col++)
+ for (var row = 0; row < mtx.rows; row++)
+ res.set(row, col, mtx.get(row, col) - scalar);
+
+ return res;
+ };
+
+ /**
+ * @param {tcuMatrix.Matrix} mtx
+ * @param {number} scalar
+ * @return {tcuMatrix.Matrix}
+ */
+ tcuMatrix.addMatScal = function(mtx, scalar) {
+ /** @type {tcuMatrix.Matrix} */ var res = new tcuMatrix.Matrix(mtx.rows, mtx.cols);
+ for (var col = 0; col < mtx.cols; col++)
+ for (var row = 0; row < mtx.rows; row++)
+ res.set(row, col, mtx.get(row, col) + scalar);
+
+ return res;
+ };
+
+ /**
+ * @param {tcuMatrix.Matrix} mtx
+ * @param {number} scalar
+ * @return {tcuMatrix.Matrix}
+ */
+ tcuMatrix.multiplyMatScal = function(mtx, scalar) {
+ /** @type {tcuMatrix.Matrix} */ var res = new tcuMatrix.Matrix(mtx.rows, mtx.cols);
+ for (var col = 0; col < mtx.cols; col++)
+ for (var row = 0; row < mtx.rows; row++)
+ res.set(row, col, mtx.get(row, col) * scalar);
+
+ return res;
+ };
+
+ /**
+ * @param {tcuMatrix.Matrix} mtx
+ * @param {number} scalar
+ * @return {tcuMatrix.Matrix}
+ */
+ tcuMatrix.divideMatScal = function(mtx, scalar) {
+ /** @type {tcuMatrix.Matrix} */ var res = new tcuMatrix.Matrix(mtx.rows, mtx.cols);
+ for (var col = 0; col < mtx.cols; col++)
+ for (var row = 0; row < mtx.rows; row++)
+ res.set(row, col, mtx.get(row, col) / scalar);
+
+ return res;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuMatrix.Matrix}
+ */
+ tcuMatrix.Mat2 = function() {
+ tcuMatrix.Matrix.call(this, 2, 2);
+ };
+
+ tcuMatrix.Mat2.prototype = Object.create(tcuMatrix.Matrix.prototype);
+ tcuMatrix.Mat2.prototype.constructor = tcuMatrix.Mat2;
+
+ /**
+ * @constructor
+ * @extends {tcuMatrix.Matrix}
+ */
+ tcuMatrix.Mat3 = function() {
+ tcuMatrix.Matrix.call(this, 3, 3);
+ };
+
+ tcuMatrix.Mat3.prototype = Object.create(tcuMatrix.Matrix.prototype);
+ tcuMatrix.Mat3.prototype.constructor = tcuMatrix.Mat3;
+
+ /**
+ * @constructor
+ * @extends {tcuMatrix.Matrix}
+ */
+ tcuMatrix.Mat4 = function() {
+ tcuMatrix.Matrix.call(this, 4, 4);
+ };
+
+ tcuMatrix.Mat4.prototype = Object.create(tcuMatrix.Matrix.prototype);
+ tcuMatrix.Mat4.prototype.constructor = tcuMatrix.Mat4;
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuMatrixUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuMatrixUtil.js
new file mode 100644
index 0000000000..63dcaba871
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuMatrixUtil.js
@@ -0,0 +1,70 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuMatrixUtil');
+goog.require('framework.common.tcuMatrix');
+
+goog.scope(function() {
+
+ var tcuMatrixUtil = framework.common.tcuMatrixUtil;
+ var tcuMatrix = framework.common.tcuMatrix;
+
+ /**
+ * @param {Array<number>} translation
+ * @return {tcuMatrix.Matrix}
+ */
+ tcuMatrixUtil.translationMatrix = function(translation) {
+ var len = translation.length;
+ var res = new tcuMatrix.Matrix(len + 1, len + 1);
+ for (var row = 0; row < len; row++)
+ res.set(row, len, translation[row]);
+ return res;
+ };
+
+ /**
+ * Flatten an array of arrays or matrices
+ * @param {(Array<Array<number>> | Array<tcuMatrix.Matrix>)} a
+ * @return {Array<number>}
+ */
+ tcuMatrixUtil.flatten = function(a) {
+ if (a[0] instanceof Array) {
+ var merged = [];
+ return merged.concat.apply(merged, a);
+ }
+
+ if (a[0] instanceof tcuMatrix.Matrix) {
+ /** @type {tcuMatrix.Matrix} */ var m = a[0];
+ var rows = m.rows;
+ var cols = m.cols;
+ var size = a.length;
+ var result = [];
+ for (var col = 0; col < cols; col++)
+ for (var i = 0; i < size; i++)
+ result.push(a[i].getColumn(col));
+ return [].concat.apply([], result);
+ }
+
+ if (typeof(a[0]) === 'number')
+ return a;
+
+ throw new Error('Invalid input');
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuPixelFormat.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuPixelFormat.js
new file mode 100644
index 0000000000..daf3297a93
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuPixelFormat.js
@@ -0,0 +1,79 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuPixelFormat');
+
+goog.scope(function() {
+
+var tcuPixelFormat = framework.common.tcuPixelFormat;
+
+/**
+ * @constructor
+ * @param {number=} r
+ * @param {number=} g
+ * @param {number=} b
+ * @param {number=} a
+ */
+tcuPixelFormat.PixelFormat = function(r, g, b, a) {
+ this.redBits = r || 0;
+ this.greenBits = g || 0;
+ this.blueBits = b || 0;
+ this.alphaBits = a || 0;
+};
+
+/**
+ * @param {WebGL2RenderingContext} context
+ * @return {tcuPixelFormat.PixelFormat}
+ */
+tcuPixelFormat.PixelFormatFromContext = function(context) {
+ var r = /** @type {number} */ (context.getParameter(gl.RED_BITS));
+ var g = /** @type {number} */ (context.getParameter(gl.GREEN_BITS));
+ var b = /** @type {number} */ (context.getParameter(gl.BLUE_BITS));
+ var a = /** @type {number} */ (context.getParameter(gl.ALPHA_BITS));
+
+ return new tcuPixelFormat.PixelFormat(r, g, b, a);
+};
+
+/**
+ * @param {number} r
+ * @param {number} g
+ * @param {number} b
+ * @param {number} a
+ * @return {boolean}
+ */
+tcuPixelFormat.PixelFormat.prototype.equals = function(r, g, b, a) {
+ return this.redBits === r &&
+ this.greenBits === g &&
+ this.blueBits === b &&
+ this.alphaBits === a;
+};
+
+/**
+ * @return {Array<number>}
+ */
+tcuPixelFormat.PixelFormat.prototype.getColorThreshold = function() {
+ return [1 << (8 - this.redBits),
+ 1 << (8 - this.greenBits),
+ 1 << (8 - this.blueBits),
+ (this.alphaBits > 0) ? (1 << (8 - this.alphaBits)) : 0];
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuRGBA.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuRGBA.js
new file mode 100644
index 0000000000..0bab841d1b
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuRGBA.js
@@ -0,0 +1,279 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuRGBA');
+goog.require('framework.delibs.debase.deMath');
+
+goog.scope(function() {
+
+var tcuRGBA = framework.common.tcuRGBA;
+var deMath = framework.delibs.debase.deMath;
+
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+ /**
+ * class tcuRGBA.RGBA
+ * @constructor
+ * @struct
+ * @param {goog.NumberArray=} value
+ */
+ tcuRGBA.RGBA = function(value) {
+ /** @type {goog.NumberArray} */ this.m_value = value || null;
+
+ };
+
+ /**
+ * @enum
+ * In JS, these are not shift values, but positions in a typed array
+ */
+ tcuRGBA.RGBA.Shift = {
+ RED: 0,
+ GREEN: 1,
+ BLUE: 2,
+ ALPHA: 3
+ };
+
+ /**
+ * @enum
+ * Mask used as flags
+ * Hopefully will not use typed arrays
+ */
+ tcuRGBA.RGBA.Mask = function() {
+ return {
+ RED: false,
+ GREEN: false,
+ BLUE: false,
+ ALPHA: false
+ };
+ };
+
+ /**
+ * Builds an tcuRGBA.RGBA object from color components
+ * @param {number} r
+ * @param {number} g
+ * @param {number} b
+ * @param {number} a
+ * @return {tcuRGBA.RGBA}
+ */
+ tcuRGBA.newRGBAComponents = function(r, g, b, a) {
+ DE_ASSERT(deMath.deInRange32(r, 0, 255));
+ DE_ASSERT(deMath.deInRange32(g, 0, 255));
+ DE_ASSERT(deMath.deInRange32(b, 0, 255));
+ DE_ASSERT(deMath.deInRange32(a, 0, 255));
+
+ return new tcuRGBA.RGBA([r, g, b, a]);
+ };
+
+ /**
+ * Builds an tcuRGBA.RGBA object from a number array
+ * @param {goog.NumberArray} v
+ * @return {tcuRGBA.RGBA}
+ */
+ tcuRGBA.newRGBAFromArray = function(v) {
+ return new tcuRGBA.RGBA(v.slice(0, 4));
+ };
+
+ /**
+ * @param {number} value
+ * @return {tcuRGBA.RGBA}
+ */
+ tcuRGBA.newRGBAFromValue = function(value) {
+ var rgba = new tcuRGBA.RGBA();
+ var array32 = new Uint32Array([value]);
+ rgba.m_value = (new Uint8Array(array32.buffer));
+ return rgba;
+ };
+
+ /**
+ * @param {Array<number>} v
+ * @return {tcuRGBA.RGBA}
+ */
+ tcuRGBA.newRGBAFromVec = function (v) {
+ var r = deMath.clamp(v[0] * 255.0, 0, 255);
+ var g = deMath.clamp(v[1] * 255.0, 0, 255);
+ var b = deMath.clamp(v[2] * 255.0, 0, 255);
+ var a = deMath.clamp(v[3] * 255.0, 0, 255);
+
+ return new tcuRGBA.RGBA([r, g, b, a]);
+ };
+
+ /**
+ * @param {number} v
+ */
+ tcuRGBA.RGBA.prototype.setRed = function(v) { DE_ASSERT(deMath.deInRange32(v, 0, 255)); this.m_value[tcuRGBA.RGBA.Shift.RED] = v; };
+
+ /**
+ * @param {number} v
+ */
+ tcuRGBA.RGBA.prototype.setGreen = function(v) { DE_ASSERT(deMath.deInRange32(v, 0, 255)); this.m_value[tcuRGBA.RGBA.Shift.GREEN] = v; };
+
+ /**
+ * @param {number} v
+ */
+ tcuRGBA.RGBA.prototype.setBlue = function(v) { DE_ASSERT(deMath.deInRange32(v, 0, 255)); this.m_value[tcuRGBA.RGBA.Shift.BLUE] = v; };
+
+ /**
+ * @param {number} v
+ */
+ tcuRGBA.RGBA.prototype.setAlpha = function(v) { DE_ASSERT(deMath.deInRange32(v, 0, 255)); this.m_value[tcuRGBA.RGBA.Shift.ALPHA] = v; };
+
+ /**
+ * @return {number}
+ */
+ tcuRGBA.RGBA.prototype.getRed = function() { return this.m_value[tcuRGBA.RGBA.Shift.RED]; };
+
+ /**
+ * @return {number}
+ */
+ tcuRGBA.RGBA.prototype.getGreen = function() { return this.m_value[tcuRGBA.RGBA.Shift.GREEN]; };
+
+ /**
+ * @return {number}
+ */
+ tcuRGBA.RGBA.prototype.getBlue = function() { return this.m_value[tcuRGBA.RGBA.Shift.BLUE]; };
+
+ /**
+ * @return {number}
+ */
+ tcuRGBA.RGBA.prototype.getAlpha = function() { return this.m_value[tcuRGBA.RGBA.Shift.ALPHA]; };
+
+ /**
+ * @param {tcuRGBA.RGBA} thr
+ * @return {boolean}
+ */
+ tcuRGBA.RGBA.prototype.isBelowThreshold = function(thr) { return (this.getRed() <= thr.getRed()) && (this.getGreen() <= thr.getGreen()) && (this.getBlue() <= thr.getBlue()) && (this.getAlpha() <= thr.getAlpha()); };
+
+ /**
+ * @param {Uint8Array} bytes
+ * @return {tcuRGBA.RGBA}
+ */
+ tcuRGBA.RGBA.fromBytes = function(bytes) { return tcuRGBA.newRGBAFromArray(bytes); };
+
+ /**
+ * @param {Uint8Array} bytes
+ */
+ tcuRGBA.RGBA.prototype.toBytes = function(bytes) { var result = new Uint8Array(this.m_value); bytes[0] = result[0]; bytes[1] = result[1]; bytes[2] = result[2]; bytes[3] = result[3]; };
+
+ /**
+ * @return {Array<number>}
+ */
+ tcuRGBA.RGBA.prototype.toVec = function() {
+ return [
+ this.getRed() / 255.0,
+ this.getGreen() / 255.0,
+ this.getBlue() / 255.0,
+ this.getAlpha() / 255.0
+ ];
+ };
+
+ /**
+ * @return {Array<number>}
+ */
+ tcuRGBA.RGBA.prototype.toIVec = function() {
+ return [
+ this.getRed(),
+ this.getGreen(),
+ this.getBlue(),
+ this.getAlpha()
+ ];
+ };
+
+ /**
+ * @param {tcuRGBA.RGBA} v
+ * @return {boolean}
+ */
+ tcuRGBA.RGBA.prototype.equals = function(v) {
+ return (
+ this.m_value[0] == v.m_value[0] &&
+ this.m_value[1] == v.m_value[1] &&
+ this.m_value[2] == v.m_value[2] &&
+ this.m_value[3] == v.m_value[3]
+ );
+ };
+
+ /**
+ * @param {tcuRGBA.RGBA} a
+ * @param {tcuRGBA.RGBA} b
+ * @param {tcuRGBA.RGBA} threshold
+ * @return {boolean}
+ */
+ tcuRGBA.compareThreshold = function(a, b, threshold) {
+ if (a.equals(b)) return true; // Quick-accept
+ return tcuRGBA.computeAbsDiff(a, b).isBelowThreshold(threshold);
+ };
+
+ /**
+ * @param {tcuRGBA.RGBA} a
+ * @param {tcuRGBA.RGBA} b
+ * @return {tcuRGBA.RGBA}
+ */
+ tcuRGBA.computeAbsDiff = function(a, b) {
+ return tcuRGBA.newRGBAComponents(
+ Math.abs(a.getRed() - b.getRed()),
+ Math.abs(a.getGreen() - b.getGreen()),
+ Math.abs(a.getBlue() - b.getBlue()),
+ Math.abs(a.getAlpha() - b.getAlpha())
+ );
+ };
+
+ /**
+ * @param {tcuRGBA.RGBA} a
+ * @param {number} b
+ * @return {tcuRGBA.RGBA}
+ */
+ tcuRGBA.multiply = function(a, b) {
+ return tcuRGBA.newRGBAComponents(
+ deMath.clamp(a.getRed() * b, 0, 255),
+ deMath.clamp(a.getGreen() * b, 0, 255),
+ deMath.clamp(a.getBlue() * b, 0, 255),
+ deMath.clamp(a.getAlpha() * b, 0, 255));
+ };
+
+ /**
+ * @param {tcuRGBA.RGBA} a
+ * @param {tcuRGBA.RGBA} b
+ * @return {tcuRGBA.RGBA}
+ */
+ tcuRGBA.max = function(a, b) {
+ return tcuRGBA.newRGBAComponents(
+ Math.max(a.getRed(), b.getRed()),
+ Math.max(a.getGreen(), b.getGreen()),
+ Math.max(a.getBlue(), b.getBlue()),
+ Math.max(a.getAlpha(), b.getAlpha())
+ );
+ };
+
+ tcuRGBA.RGBA.prototype.toString = function() {
+ return '[' + this.m_value[0] + ',' + this.m_value[1] + ',' + this.m_value[2] + ',' + this.m_value[3] + ']';
+ };
+
+ // Color constants
+ tcuRGBA.RGBA.red = tcuRGBA.newRGBAComponents(0xFF, 0, 0, 0xFF);
+ tcuRGBA.RGBA.green = tcuRGBA.newRGBAComponents(0, 0xFF, 0, 0xFF);
+ tcuRGBA.RGBA.blue = tcuRGBA.newRGBAComponents(0, 0, 0xFF, 0xFF);
+ tcuRGBA.RGBA.gray = tcuRGBA.newRGBAComponents(0x80, 0x80, 0x80, 0xFF);
+ tcuRGBA.RGBA.white = tcuRGBA.newRGBAComponents(0xFF, 0xFF, 0xFF, 0xFF);
+ tcuRGBA.RGBA.black = tcuRGBA.newRGBAComponents(0, 0, 0, 0xFF);
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuSkipList.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuSkipList.js
new file mode 100644
index 0000000000..286b1956be
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuSkipList.js
@@ -0,0 +1,245 @@
+/*
+Copyright (c) 2019 The Khronos Group Inc.
+Use of this source code is governed by an MIT-style license that can be
+found in the LICENSE.txt file.
+*/
+
+/**
+ * This class defines the individual tests which are skipped because
+ * of graphics driver bugs which simply can not be worked around in
+ * WebGL 2.0 implementations.
+ *
+ * The intent is that this list be kept as small as possible; and that
+ * bugs are filed with the respective GPU vendors for entries in this
+ * list.
+ *
+ * Pass the query argument "runSkippedTests" in the URL in order to
+ * force the skipped tests to be run. So, for example:
+ *
+ * http://localhost:8080/sdk/tests/deqp/functional/gles3/transformfeedback.html?filter=transform_feedback.basic_types.separate.points&runSkippedTests
+ */
+'use strict';
+goog.provide('framework.common.tcuSkipList');
+
+goog.scope(function() {
+
+ var tcuSkipList = framework.common.tcuSkipList;
+
+ var _skipEntries = {};
+ var _wildcardSkipEntries = {};
+ var _reason = "";
+
+ function _setReason(reason) {
+ _reason = reason;
+ }
+
+ function _skip(testName) {
+ if(testName.indexOf("*") >= 0){
+ testName = testName.split("*")[0];
+ _wildcardSkipEntries[testName] = _reason;
+ }else{
+ _skipEntries[testName] = _reason;
+ }
+ }
+
+ var runSkippedTests = false;
+ var queryVars = window.location.search.substring(1).split('&');
+ for (var i = 0; i < queryVars.length; i++) {
+ var value = queryVars[i].split('=');
+ if (decodeURIComponent(value[0]) === 'runSkippedTests') {
+ // Assume that presence of this query arg implies to run
+ // the skipped tests; the value is ignored.
+ runSkippedTests = true;
+ break;
+ }
+ }
+
+ if (!runSkippedTests) {
+ // Example usage:
+ //
+ // _setReason("Bugs in FooVendor 30.03 driver");
+ // _skip("transform_feedback.basic_types.separate.points.lowp_mat2");
+
+ // Please see https://android.googlesource.com/platform/external/deqp/+/7c5323116bb164d64bfecb68e8da1af634317b24
+ _setReason("Native dEQP also fails on these tests and suppresses them");
+ _skip("texture_functions.textureoffset.sampler3d_fixed_fragment");
+ _skip("texture_functions.textureoffset.isampler3d_fragment");
+ _skip("texture_functions.textureoffset.usampler3d_fragment");
+ _skip("texture_functions.textureprojoffset.sampler3d_fixed_fragment");
+ _skip("texture_functions.textureprojoffset.isampler3d_fragment");
+ _skip("texture_functions.textureprojoffset.usampler3d_fragment");
+ // Please see https://android.googlesource.com/platform/external/deqp/+/master/android/cts/master/src/gles3-hw-issues.txt
+ _skip("texture_functions.textureprojlod.isampler3d_vertex");
+ _skip("texture_functions.textureprojlod.usampler3d_vertex");
+ // Please see https://android.googlesource.com/platform/external/deqp/+/master/android/cts/master/src/gles3-test-issues.txt
+ _skip("texture_functions.textureprojlodoffset.usampler3d_vertex");
+ _skip("texture_functions.textureoffset.sampler3d_float_fragment");
+ _skip("texture_functions.textureprojoffset.sampler3d_float_fragment");
+ // Please see https://android.googlesource.com/platform/external/deqp/+/master/android/cts/master/src/gles3-driver-issues.txt
+ _skip("texture_functions.textureprojlodoffset.isampler3d_vertex");
+ _skip("texture_functions.texturegrad.samplercubeshadow*");
+ // Please see https://android.googlesource.com/platform/external/deqp/+/40ff528%5E%21/
+ // and https://bugs.chromium.org/p/angleproject/issues/detail?id=3094
+ _skip("texture_functions.texturelodoffset.sampler3d_float_vertex");
+
+ // https://android.googlesource.com/platform/external/deqp/+/0c1f83aee4709eef7ef2a3edd384f9c192f476fd/android/cts/master/src/gles3-hw-issues.txt#801
+ _setReason("Tricky blit rects can result in imperfect copies on some HW.");
+ _skip("blit.rect.nearest_consistency_mag");
+ _skip("blit.rect.nearest_consistency_mag_reverse_dst_x");
+ _skip("blit.rect.nearest_consistency_mag_reverse_src_dst_x");
+ _skip("blit.rect.nearest_consistency_mag_reverse_src_x");
+ _skip("blit.rect.nearest_consistency_mag_reverse_src_y");
+ _skip("blit.rect.nearest_consistency_min");
+ _skip("blit.rect.nearest_consistency_min_reverse_dst_x");
+ _skip("blit.rect.nearest_consistency_min_reverse_src_dst_x");
+ _skip("blit.rect.nearest_consistency_min_reverse_src_x");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_mag");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_mag_reverse_dst_x");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_mag_reverse_src_dst_x");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_mag_reverse_src_x");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_mag_reverse_src_y");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_min");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_min_reverse_dst_x");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_min_reverse_src_dst_x");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_min_reverse_src_x");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_min_reverse_src_y");
+
+ // https://android.googlesource.com/platform/external/deqp/+/0c1f83aee4709eef7ef2a3edd384f9c192f476fd/android/cts/master/src/gles3-driver-issues.txt#381
+ _setReason("Tricky blit rects can result in imperfect copies on some drivers.");
+ _skip("blit.rect.out_of_bounds_linear");
+ _skip("blit.rect.out_of_bounds_reverse_src_x_linear");
+ _skip("blit.rect.out_of_bounds_reverse_src_y_linear");
+ _skip("blit.rect.out_of_bounds_reverse_dst_x_linear");
+ _skip("blit.rect.out_of_bounds_reverse_dst_y_linear");
+ _skip("blit.rect.out_of_bounds_reverse_src_dst_x_linear");
+ _skip("blit.rect.out_of_bounds_reverse_src_dst_y_linear");
+
+ // https://android.googlesource.com/platform/external/deqp/+/0c1f83aee4709eef7ef2a3edd384f9c192f476fd/android/cts/master/src/gles3-driver-issues.txt#368
+ _skip("blit.rect.nearest_consistency_out_of_bounds_mag_reverse_dst_y");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_mag_reverse_src_dst_y");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_min_reverse_dst_y");
+ _skip("blit.rect.nearest_consistency_out_of_bounds_min_reverse_src_dst_y");
+
+ _setReason("Missing shadow sampler functions in D3D11");
+ // https://github.com/KhronosGroup/WebGL/issues/1870
+ // deqp/functional/gles3/shadertexturefunction/texture.html
+ _skip("texture_functions.texture.sampler2darrayshadow_vertex");
+ // deqp/functional/gles3/shadertexturefunction/texturelod.html
+ _skip("texture_functions.texturelod.sampler2dshadow_vertex");
+ _skip("texture_functions.texturelod.sampler2dshadow_fragment");
+ // deqp/functional/gles3/shadertexturefunction/texturelodoffset.html
+ _skip("texture_functions.texturelodoffset.sampler2dshadow_vertex");
+ _skip("texture_functions.texturelodoffset.sampler2dshadow_fragment");
+ // deqp/functional/gles3/shadertexturefunction/textureprojlod.html
+ _skip("texture_functions.textureprojlod.sampler2dshadow_vertex");
+ _skip("texture_functions.textureprojlod.sampler2dshadow_fragment");
+ // deqp/functional/gles3/shadertexturefunction/textureprojlodoffset.html
+ _skip("texture_functions.textureprojlodoffset.sampler2dshadow_vertex");
+ _skip("texture_functions.textureprojlodoffset.sampler2dshadow_fragment");
+ // deqp/functional/gles3/shadertexturefunction/texturegrad.html
+ _skip("texture_functions.texturegrad.sampler2dshadow_vertex");
+ _skip("texture_functions.texturegrad.sampler2dshadow_fragment");
+ _skip("texture_functions.texturegrad.sampler2darrayshadow_vertex");
+ _skip("texture_functions.texturegrad.sampler2darrayshadow_fragment");
+ // deqp/functional/gles3/shadertexturefunction/texturegradoffset.html
+ _skip("texture_functions.texturegradoffset.sampler2dshadow_vertex");
+ _skip("texture_functions.texturegradoffset.sampler2dshadow_fragment");
+ _skip("texture_functions.texturegradoffset.sampler2darrayshadow_vertex");
+ _skip("texture_functions.texturegradoffset.sampler2darrayshadow_fragment");
+ // deqp/functional/gles3/shadertexturefunction/textureprojgrad.html
+ _skip("texture_functions.textureprojgrad.sampler2dshadow_vertex");
+ _skip("texture_functions.textureprojgrad.sampler2dshadow_fragment");
+ // deqp/functional/gles3/shadertexturefunction/textureprojgradoffset.html
+ _skip("texture_functions.textureprojgradoffset.sampler2dshadow_vertex");
+ _skip("texture_functions.textureprojgradoffset.sampler2dshadow_fragment");
+
+ _setReason("MacOSX drivers share namespaces where they should not");
+ // https://github.com/KhronosGroup/WebGL/issues/1890
+ // deqp/data/gles3/shaders/scoping.html
+ _skip("scoping.valid.local_int_variable_hides_struct_type_vertex");
+ _skip("scoping.valid.local_int_variable_hides_struct_type_fragment");
+ _skip("scoping.valid.local_struct_variable_hides_struct_type_vertex");
+ _skip("scoping.valid.local_struct_variable_hides_struct_type_fragment");
+ _skip("scoping.valid.function_parameter_hides_struct_type_vertex");
+ _skip("scoping.valid.function_parameter_hides_struct_type_fragment");
+
+ _setReason("NVidia Linux drivers does not clamp gl_FragDepth to [0.0, 1.0]");
+ // Standalone Test case:
+ // https://github.com/Kangz/GLDriverBugs/blob/master/frag_depth_clamp_32f_depth/Main.cpp
+ // deqp/functional/gles3/fbodepthbuffer.html
+ _skip("depth.depth_write_clamp.depth_component32f");
+ _skip("depth.depth_write_clamp.depth32f_stencil8");
+ _skip("depth.depth_test_clamp.depth_component32f");
+ _skip("depth.depth_test_clamp.depth32f_stencil8");
+
+ _setReason("NVidia Linux driver bug in nested uniform block location assignment");
+ // crbug.com/621178
+ // deqp/functional/gles3/uniformapi/random.html
+ _skip("uniform_api.random.64");
+
+ _setReason("Mac AMD / Linux AMD / older mesa handles clipping of wide points incorrectly");
+ // crbug.com/642822
+ // deqp/functional/gles3/clipping.html
+ _skip("clipping.wide_points_full_viewport");
+ _skip("clipping.wide_points_partial_viewport");
+
+ _setReason("Some Windows AMD D3D11 drivers have issues with blit and depth/stencil formats.");
+ // crbug.com/638323
+ // deqp/functional/gles3/framebufferblit/depth_stencil.html
+ // Also see conformance2/rendering/blitframebuffer-stencil-only.html for 2.0.1 test.
+ _skip("blit.depth_stencil.depth24_stencil8_scale");
+ _skip("blit.depth_stencil.depth24_stencil8_stencil_only");
+
+ _setReason("Removed from native dEQP mustpass. Not passable on Adreno.");
+ // These tests have been skipped in native dEQP since 2015:
+ // https://android.googlesource.com/platform/external/deqp/+/ea026b329e6bf73f109cda914c90f08d5f7a5b8d
+ // They do not pass on Android/Qualcomm (Google Pixel 1, Pixel 3).
+ // It's not clear if the tests or the hardware are out-of-spec, but there's nothing we can do about it right now.
+ // See also: crbug.com/695679
+ _skip("derivate.dfdy.fbo_float.float_highp");
+ _skip("derivate.dfdy.fbo_float.vec2_highp");
+ _skip("derivate.dfdy.fbo_float.vec3_highp");
+ _skip("derivate.dfdy.fbo_float.vec4_highp");
+ _skip("derivate.dfdy.nicest.fbo_float.float_highp");
+ _skip("derivate.dfdy.nicest.fbo_float.vec2_highp");
+ _skip("derivate.dfdy.nicest.fbo_float.vec3_highp");
+ _skip("derivate.dfdy.nicest.fbo_float.vec4_highp");
+ _skip("derivate.dfdy.fastest.fbo_float.float_highp");
+ _skip("derivate.dfdy.fastest.fbo_float.vec2_highp");
+ _skip("derivate.dfdy.fastest.fbo_float.vec3_highp");
+ _skip("derivate.dfdy.fastest.fbo_float.vec4_highp");
+ } // if (!runSkippedTests)
+
+ /*
+ * Gets the skip status of the given test. Returns an
+ * object with the properties "skip", a boolean, and "reason", a
+ * string.
+ */
+ tcuSkipList.getSkipStatus = function(testName) {
+ var skipEntry = _skipEntries[testName];
+ if (skipEntry === undefined) {
+ return this._getWildcardSkipStatus(testName);
+ } else {
+ return { 'skip': true, 'reason': skipEntry };
+ }
+ }
+
+ /*
+ * Gets the skip status of the given tests like testpath*
+ * object with the properties "skip", a boolean, and "reason", a
+ * string.
+ */
+ tcuSkipList._getWildcardSkipStatus = function(testName) {
+ var skipEntry;
+ for (var key in _wildcardSkipEntries) {
+ if (testName.indexOf(key) >=0 ) {
+ skipEntry = _wildcardSkipEntries[key];
+ if (skipEntry != undefined) {
+ return { 'skip': true, 'reason': skipEntry };
+ }
+ }
+ }
+ return { 'skip': false, 'reason': '' };
+ }
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuStringTemplate.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuStringTemplate.js
new file mode 100644
index 0000000000..d70056733b
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuStringTemplate.js
@@ -0,0 +1,42 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuStringTemplate');
+
+goog.scope(function() {
+
+var tcuStringTemplate = framework.common.tcuStringTemplate;
+
+tcuStringTemplate.escapeRegExp = function(string) {
+ return string.replace(/([.*+?^=!:$ {}()|\[\]\/\\])/g, '\\$1');
+};
+
+tcuStringTemplate.specialize = function(str, params) {
+ var dst = str;
+ for (var key in params) {
+ var value = params[key];
+ var re = new RegExp(tcuStringTemplate.escapeRegExp('\$\{' + key + '\}'), 'g');
+ dst = dst.replace(re, value);
+ }
+ return dst;
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuSurface.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuSurface.js
new file mode 100644
index 0000000000..47d3634aad
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuSurface.js
@@ -0,0 +1,184 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuSurface');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.opengl.gluTextureUtil');
+
+goog.scope(function() {
+
+var tcuSurface = framework.common.tcuSurface;
+var tcuTexture = framework.common.tcuTexture;
+var deMath = framework.delibs.debase.deMath;
+var gluTextureUtil = framework.opengl.gluTextureUtil;
+
+var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+};
+
+/**
+ * \brief RGBA8888 surface
+ *
+ * tcuSurface.Surface provides basic pixel storage functionality. Only single format
+ * (RGBA8888) is supported.
+ *
+ * PixelBufferAccess (see tcuTexture.h) provides much more flexible API
+ * for handling various pixel formats. This is mainly a convinience class.
+ * @constructor
+ * @param {number=} width
+ * @param {number=} height
+ */
+tcuSurface.Surface = function(width, height) {
+ width = width || 0;
+ height = height || 0;
+ this.setSize(width, height);
+};
+
+/**
+ * @param {number} width
+ * @param {number} height
+ */
+tcuSurface.Surface.prototype.setSize = function(width, height) {
+ this.m_width = width;
+ this.m_height = height;
+ if (width * height > 0) {
+ this.m_data = new ArrayBuffer(4 * width * height);
+ this.m_pixels = new Uint8Array(this.m_data);
+ } else {
+ this.m_data = null;
+ this.m_pixels = null;
+ }
+};
+
+/**
+ * @return {number}
+ */
+tcuSurface.Surface.prototype.getWidth = function() { return this.m_width; };
+
+/**
+ * @return {number}
+ */
+tcuSurface.Surface.prototype.getHeight = function() { return this.m_height; };
+
+/**
+ * @param {number} x
+ * @param {number} y
+ * @param {Array<number>} color Vec4 color
+ */
+tcuSurface.Surface.prototype.setPixel = function(x, y, color) {
+ DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
+ DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
+
+ var offset = 4 * (x + y * this.m_width);
+ for (var i = 0; i < 4; i++)
+ this.m_pixels[offset + i] = color[i];
+};
+
+/**
+ * @param {number} x
+ * @param {number} y
+ * @return {Array<number>}
+ */
+tcuSurface.Surface.prototype.getPixel = function(x, y) {
+ DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
+ DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
+
+ var color = [];
+ color.length = 4;
+
+ var offset = 4 * (x + y * this.m_width);
+ for (var i = 0; i < 4; i++)
+ color[i] = this.m_pixels[offset + i];
+
+ return color;
+};
+
+/**
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+tcuSurface.Surface.prototype.getPixelUintRGB8 = function(x, y) {
+ DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
+ DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
+
+ var offset = 4 * (x + y * this.m_width);
+ return (this.m_pixels[offset] << 16) +
+ (this.m_pixels[offset + 1] << 8) +
+ this.m_pixels[offset + 2];
+};
+
+/**
+ * Read the viewport contents into this surface
+ * @param {*=} ctx WebGL or ref context
+ * @param {(Array<number>|{x: number, y: number, width: number, height: number})=} view
+ */
+tcuSurface.Surface.prototype.readViewport = function(ctx, view) {
+ ctx = ctx || gl;
+ var v = view || /** @type {Array<number>} */ (ctx.getParameter(gl.VIEWPORT));
+ /** @type {number} */ var x;
+ /** @type {number} */ var y;
+ /** @type {number} */ var width;
+ /** @type {number} */ var height;
+ if (v instanceof Array || ArrayBuffer.isView(v)) {
+ x = v[0];
+ y = v[1];
+ width = v[2];
+ height = v[3];
+ } else {
+ x = v.x;
+ y = v.y;
+ width = v.width;
+ height = v.height;
+ }
+ if (width != this.m_width || height != this.m_height)
+ this.setSize(width, height);
+ ctx.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, this.m_pixels);
+};
+
+/**
+ * @return {Uint8Array}
+ */
+tcuSurface.Surface.prototype.getPixels = function() { return this.m_pixels || null; };
+
+/**
+ * @return {tcuTexture.PixelBufferAccess} Pixel Buffer Access object
+ */
+tcuSurface.Surface.prototype.getAccess = function() {
+ return new tcuTexture.PixelBufferAccess({
+ format: new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8),
+ width: this.m_width,
+ height: this.m_height,
+ data: this.m_data
+ });
+
+};
+
+tcuSurface.Surface.prototype.getSubAccess = function(x, y, width, height) {
+ /* TODO: Implement. the deqp getSubAccess() looks broken. It will probably fail if
+ * x != 0 or width != m_width
+ */
+ throw new Error('Unimplemented');
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTestCase.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTestCase.js
new file mode 100644
index 0000000000..ec08eea5ca
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTestCase.js
@@ -0,0 +1,491 @@
+/*-------------------------------------------------------------------------
+ * 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.
+ *
+ */
+
+/**
+ * This class allows one to create a hierarchy of tests and iterate over them.
+ * It replaces TestCase and TestCaseGroup classes.
+ */
+'use strict';
+goog.provide('framework.common.tcuTestCase');
+goog.require('framework.common.tcuSkipList');
+
+goog.scope(function() {
+
+ var tcuTestCase = framework.common.tcuTestCase;
+ var tcuSkipList = framework.common.tcuSkipList;
+
+ tcuTestCase.getQueryVal = function(key) {
+ const queryVars = window.location.search.substring(1).split('&');
+ for (let kv of queryVars) {
+ kv = kv.split('=');
+ if (decodeURIComponent(kv[0]) === key)
+ return decodeURIComponent(kv[1]);
+ }
+ return null;
+ };
+
+ tcuTestCase.isQuickMode = () => tcuTestCase.getQueryVal('quick') === '1';
+ tcuTestCase.isQuietMode = () => tcuTestCase.getQueryVal('quiet') === '1';
+
+ /**
+ * Reads the filter parameter from the URL to filter tests.
+ * @return {?string }
+ */
+ tcuTestCase.getFilter = () => tcuTestCase.getQueryVal('filter');
+
+ /**
+ * Indicates the state of an iteration operation.
+ * @enum {number}
+ */
+ tcuTestCase.IterateResult = {
+ STOP: 0,
+ CONTINUE: 1
+ };
+
+ /****************************************
+ * Runner
+ ***************************************/
+
+ /**
+ * A simple state machine.
+ * The purpose of this this object is to break
+ * long tests into small chunks that won't cause a timeout
+ * @constructor
+ */
+ tcuTestCase.Runner = function() {
+ /** @type {tcuTestCase.DeqpTest} */ this.currentTest = null;
+ /** @type {tcuTestCase.DeqpTest} */ this.nextTest = null;
+ /** @type {tcuTestCase.DeqpTest} */ this.testCases = null;
+ /** @type {?string } */ this.filter = tcuTestCase.getFilter();
+ };
+
+ /**
+ * @param {tcuTestCase.DeqpTest} root The root test of the test tree.
+ */
+ tcuTestCase.Runner.prototype.setRoot = function(root) {
+ this.currentTest = null;
+ this.testCases = root;
+ };
+
+ tcuTestCase.Runner.prototype.setRange = function(range) {
+ this.range = range;
+ };
+
+ /**
+ * Searches the test tree for the next executable test
+ * @return {?tcuTestCase.DeqpTest }
+ */
+ tcuTestCase.Runner.prototype.next = function() {
+
+ // First time? Use root test
+ if (!this.currentTest) {
+ this.currentTest = this.testCases;
+
+ // Root is executable? Use it
+ if (this.currentTest.isExecutable())
+ return this.currentTest;
+ }
+
+ // Should we proceed with the next test?
+ if (tcuTestCase.lastResult == tcuTestCase.IterateResult.STOP) {
+ // Look for next executable test
+ do {
+ if (this.range)
+ this.currentTest = this.currentTest.nextInRange(this.filter, this.range);
+ else
+ this.currentTest = this.currentTest.next(this.filter);
+ } while (this.currentTest && !this.currentTest.isExecutable());
+ }
+
+ return this.currentTest;
+ };
+
+ /**
+ * Schedule the callback to be run ASAP
+ * @param {function()} callback Callback to schedule
+ */
+ tcuTestCase.Runner.prototype.runCallback = function(callback) {
+ setTimeout(function() {
+ callback();
+ }.bind(this), 0);
+ };
+
+ /**
+ * Call this function at the end of the test
+ */
+ tcuTestCase.Runner.prototype.terminate = function() {
+ finishTest();
+ if (!tcuTestCase.isQuietMode()) {
+ console.log('finishTest() after (in ms):', performance.now());
+ }
+ };
+
+ tcuTestCase.runner = new tcuTestCase.Runner();
+
+ /** @type {tcuTestCase.IterateResult} */ tcuTestCase.lastResult = tcuTestCase.IterateResult.STOP;
+
+ /***************************************
+ * DeqpTest
+ ***************************************/
+
+ /**
+ * Assigns name, description and specification to test
+ * @constructor
+ * @param {?string} name
+ * @param {?string} description
+ * @param {Object=} spec
+ */
+ tcuTestCase.DeqpTest = function(name, description, spec) {
+ this.name = name || '';
+ this.description = description || '';
+ this.spec = spec;
+ this.currentTestNdx = 0;
+ this.parentTest = null;
+ this.childrenTests = [];
+ this.executeAlways = false;
+ };
+
+ /**
+ * Abstract init function(each particular test will implement it, or not)
+ */
+ tcuTestCase.DeqpTest.prototype.init = function() {};
+
+ /**
+ * Abstract deinit function(each particular test will implement it, or not)
+ */
+ tcuTestCase.DeqpTest.prototype.deinit = function() {};
+
+ /**
+ * Abstract iterate function(each particular test will implement it, or not)
+ * @return {tcuTestCase.IterateResult}
+ */
+ tcuTestCase.DeqpTest.prototype.iterate = function() { return tcuTestCase.IterateResult.STOP; };
+
+ /**
+ * Checks if the test is executable
+ * @return {boolean}
+ */
+ tcuTestCase.DeqpTest.prototype.isExecutable = function() {
+ return this.childrenTests.length == 0 || this.executeAlways;
+ };
+
+ /**
+ * Checks if the test is a leaf
+ */
+ tcuTestCase.DeqpTest.prototype.isLeaf = function() {
+ return this.childrenTests.length == 0;
+ };
+
+ /**
+ * Marks the test as always executable
+ */
+ tcuTestCase.DeqpTest.prototype.makeExecutable = function() {
+ this.executeAlways = true;
+ };
+
+ /**
+ * Adds a child test to the test's children
+ * @param {tcuTestCase.DeqpTest} test
+ */
+ tcuTestCase.DeqpTest.prototype.addChild = function(test) {
+ test.parentTest = this;
+ this.childrenTests.push(test);
+ };
+
+ /**
+ * Sets the whole children tests array
+ * @param {Array<tcuTestCase.DeqpTest>} tests
+ */
+ tcuTestCase.DeqpTest.prototype.setChildren = function(tests) {
+ for (var test in tests)
+ tests[test].parentTest = this;
+ this.childrenTests = tests;
+ };
+
+ /**
+ * Returns the next test in the hierarchy of tests
+ *
+ * @param {?string } pattern Optional pattern to search for
+ * @return {tcuTestCase.DeqpTest}
+ */
+ tcuTestCase.DeqpTest.prototype.next = function(pattern) {
+ return this._nextHonoringSkipList(pattern);
+ };
+
+ /**
+ * Returns the next test in the hierarchy of tests, honoring the
+ * skip list, and reporting skipped tests.
+ *
+ * @param {?string } pattern Optional pattern to search for
+ * @return {tcuTestCase.DeqpTest}
+ */
+ tcuTestCase.DeqpTest.prototype._nextHonoringSkipList = function(pattern) {
+ var tryAgain = false;
+ var test = null;
+ do {
+ tryAgain = false;
+ test = this._nextIgnoringSkipList(pattern);
+ if (test != null) {
+ // See whether the skip list vetoes the execution of
+ // this test.
+ var fullTestName = test.fullName();
+ var skipDisposition = tcuSkipList.getSkipStatus(fullTestName);
+ if (skipDisposition.skip) {
+ tryAgain = true;
+ setCurrentTestName(fullTestName);
+ checkMessage(false, 'Skipping test due to tcuSkipList: ' + fullTestName);
+ }
+ }
+ } while (tryAgain);
+ return test;
+ };
+
+
+ /**
+ * Returns the next test in the hierarchy of tests, ignoring the
+ * skip list.
+ *
+ * @param {?string } pattern Optional pattern to search for
+ * @return {tcuTestCase.DeqpTest}
+ */
+ tcuTestCase.DeqpTest.prototype._nextIgnoringSkipList = function(pattern) {
+ if (pattern)
+ return this._findIgnoringSkipList(pattern);
+
+ var test = null;
+
+ //Look for the next child
+ if (this.currentTestNdx < this.childrenTests.length) {
+ test = this.childrenTests[this.currentTestNdx];
+ this.currentTestNdx++;
+ }
+
+ // If no more children, get the next brother
+ if (test == null && this.parentTest != null) {
+ test = this.parentTest._nextIgnoringSkipList(null);
+ }
+
+ return test;
+ };
+
+ /**
+ * Returns the next test in the hierarchy of tests
+ * whose 1st level is in the given range
+ *
+ * @param {?string } pattern Optional pattern to search for
+ * @param {Array<number>} range
+ * @return {tcuTestCase.DeqpTest}
+ */
+ tcuTestCase.DeqpTest.prototype.nextInRange = function(pattern, range) {
+ while (true) {
+ var test = this._nextHonoringSkipList(pattern);
+ if (!test)
+ return null;
+ var topLevelId = tcuTestCase.runner.testCases.currentTestNdx - 1;
+ if (topLevelId >= range[0] && topLevelId < range[1])
+ return test;
+ }
+ };
+
+ /**
+ * Returns the full name of the test
+ *
+ * @return {string} Full test name.
+ */
+ tcuTestCase.DeqpTest.prototype.fullName = function() {
+ if (this.parentTest) {
+ var parentName = this.parentTest.fullName();
+ if (parentName)
+ return parentName + '.' + this.name;
+ }
+ return this.name;
+ };
+
+ /**
+ * Returns the description of the test
+ *
+ * @return {string} Test description.
+ */
+ tcuTestCase.DeqpTest.prototype.getDescription = function() {
+ return this.description;
+ };
+
+ /**
+ * Find a test with a matching name. Fast-forwards to a test whose
+ * full name matches the given pattern.
+ *
+ * @param {string} pattern Regular expression to search for
+ * @return {?tcuTestCase.DeqpTest } Found test or null.
+ */
+ tcuTestCase.DeqpTest.prototype.find = function(pattern) {
+ return this._findHonoringSkipList(pattern);
+ };
+
+ /**
+ * Find a test with a matching name. Fast-forwards to a test whose
+ * full name matches the given pattern, honoring the skip list, and
+ * reporting skipped tests.
+ *
+ * @param {string} pattern Regular expression to search for
+ * @return {?tcuTestCase.DeqpTest } Found test or null.
+ */
+ tcuTestCase.DeqpTest.prototype._findHonoringSkipList = function(pattern) {
+ var tryAgain = false;
+ var test = null;
+ do {
+ tryAgain = false;
+ test = this._findIgnoringSkipList(pattern);
+ if (test != null) {
+ // See whether the skip list vetoes the execution of
+ // this test.
+ var fullTestName = test.fullName();
+ var skipDisposition = tcuSkipList.getSkipStatus(fullTestName);
+ if (skipDisposition.skip) {
+ tryAgain = true;
+ checkMessage(false, 'Skipping test due to tcuSkipList: ' + fullTestName);
+ }
+ }
+ } while (tryAgain);
+ return test;
+ };
+
+ /**
+ * Find a test with a matching name. Fast-forwards to a test whose
+ * full name matches the given pattern.
+ *
+ * @param {string} pattern Regular expression to search for
+ * @return {?tcuTestCase.DeqpTest } Found test or null.
+ */
+ tcuTestCase.DeqpTest.prototype._findIgnoringSkipList = function(pattern) {
+ var test = this;
+ while (true) {
+ test = test._nextIgnoringSkipList(null);
+ if (!test)
+ break;
+ if (test.fullName().match(pattern) || test.executeAlways)
+ break;
+ }
+ return test;
+ };
+
+ /**
+ * Reset the iterator.
+ */
+ tcuTestCase.DeqpTest.prototype.reset = function() {
+ this.currentTestNdx = 0;
+
+ for (var i = 0; i < this.childrenTests.length; i++)
+ this.childrenTests[i].reset();
+ };
+
+ /**
+ * Defines a new test
+ *
+ * @param {?string} name Short test name
+ * @param {?string} description Description of the test
+ * @param {Object=} spec Test specification
+ *
+ * @return {tcuTestCase.DeqpTest} The new test
+ */
+ tcuTestCase.newTest = function(name, description, spec) {
+ var test = new tcuTestCase.DeqpTest(name, description, spec);
+
+ return test;
+ };
+
+ /**
+ * Defines a new executable test so it gets run even if it's not a leaf
+ *
+ * @param {string} name Short test name
+ * @param {string} description Description of the test
+ * @param {Object=} spec Test specification
+ *
+ * @return {tcuTestCase.DeqpTest} The new test
+ */
+ tcuTestCase.newExecutableTest = function(name, description, spec) {
+ var test = tcuTestCase.newTest(name, description, spec);
+ test.makeExecutable();
+
+ return test;
+ };
+
+ /**
+ * Run through the test cases giving time to system operation.
+ */
+ tcuTestCase.runTestCases = function() {
+ var state = tcuTestCase.runner;
+
+ if (state.next()) {
+ try {
+ // If proceeding with the next test, prepare it.
+ var fullTestName = state.currentTest.fullName();
+ var inited = true;
+ if (tcuTestCase.lastResult == tcuTestCase.IterateResult.STOP) {
+ // Update current test name
+ setCurrentTestName(fullTestName);
+ bufferedLogToConsole('Init testcase: ' + fullTestName); //Show also in console so we can see which test crashed the browser's tab
+
+ // Initialize particular test
+ inited = state.currentTest.init();
+ inited = inited === undefined ? true : inited;
+
+ //If it's a leaf test, notify of it's execution.
+ if (state.currentTest.isLeaf() && inited)
+ debug('<hr/><br/>Start testcase: ' + fullTestName);
+ }
+
+ if (inited) {
+ // Run the test, save the result.
+ tcuTestCase.lastResult = state.currentTest.iterate();
+ } else {
+ // Skip uninitialized test.
+ tcuTestCase.lastResult = tcuTestCase.IterateResult.STOP;
+ }
+
+ // Cleanup
+ if (tcuTestCase.lastResult == tcuTestCase.IterateResult.STOP)
+ state.currentTest.deinit();
+ }
+ catch (err) {
+ // If the exception was not thrown by a test check, log it, but don't throw it again
+ if (!(err instanceof TestFailedException)) {
+ //Stop execution of current test.
+ tcuTestCase.lastResult = tcuTestCase.IterateResult.STOP;
+ try {
+ // Cleanup
+ if (tcuTestCase.lastResult == tcuTestCase.IterateResult.STOP)
+ state.currentTest.deinit();
+ } catch (cerr) {
+ bufferedLogToConsole('Error while cleaning up test: ' + cerr);
+ }
+ var msg = err;
+ if (err.message)
+ msg = err.message;
+ testFailedOptions(msg, false);
+ }
+ bufferedLogToConsole(err);
+ }
+
+ tcuTestCase.runner.runCallback(tcuTestCase.runTestCases);
+ } else
+ tcuTestCase.runner.terminate();
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexCompareVerifier.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexCompareVerifier.js
new file mode 100644
index 0000000000..254963ae66
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexCompareVerifier.js
@@ -0,0 +1,1356 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuTexCompareVerifier');
+goog.require('framework.common.tcuTexVerifierUtil');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.common.tcuTextureUtil');
+goog.require('framework.delibs.debase.deMath');
+
+goog.scope(function() {
+
+var tcuTexCompareVerifier = framework.common.tcuTexCompareVerifier;
+var tcuTexture = framework.common.tcuTexture;
+var deMath = framework.delibs.debase.deMath;
+var tcuTextureUtil = framework.common.tcuTextureUtil;
+var tcuTexVerifierUtil = framework.common.tcuTexVerifierUtil;
+
+/**
+ * \brief Texture compare (shadow) lookup precision parameters.
+ * @constructor
+ * @struct
+ * @param {Array<number>=} coordBits
+ * @param {Array<number>=} uvwBits
+ * @param {number=} pcfBits
+ * @param {number=} referenceBits
+ * @param {number=} resultBits
+ */
+tcuTexCompareVerifier.TexComparePrecision = function(coordBits, uvwBits, pcfBits, referenceBits, resultBits) {
+ this.coordBits = coordBits === undefined ? [22, 22, 22] : coordBits;
+ this.uvwBits = uvwBits === undefined ? [22, 22, 22] : uvwBits;
+ this.pcfBits = pcfBits === undefined ? 16 : pcfBits;
+ this.referenceBits = referenceBits === undefined ? 16 : referenceBits;
+ this.resultBits = resultBits === undefined ? 16 : resultBits;
+};
+
+/**
+ * @constructor
+ * @struct
+ */
+tcuTexCompareVerifier.CmpResultSet = function() {
+ this.isTrue = false;
+ this.isFalse = false;
+};
+
+/**
+ * @param {tcuTexture.CompareMode} compareMode
+ * @param {number} cmpValue_
+ * @param {number} cmpReference_
+ * @param {number} referenceBits
+ * @param {boolean} isFixedPoint
+ * @return {tcuTexCompareVerifier.CmpResultSet}
+ */
+tcuTexCompareVerifier.execCompare = function(compareMode,
+ cmpValue_,
+ cmpReference_,
+ referenceBits,
+ isFixedPoint) {
+ var clampValues = isFixedPoint; // if comparing against a floating point texture, ref (and value) is not clamped
+ var cmpValue = (clampValues) ? (deMath.clamp(cmpValue_, 0, 1)) : (cmpValue_);
+ var cmpReference = (clampValues) ? (deMath.clamp(cmpReference_, 0, 1)) : (cmpReference_);
+ var err = tcuTexVerifierUtil.computeFixedPointError(referenceBits);
+ var res = new tcuTexCompareVerifier.CmpResultSet();
+
+ switch (compareMode) {
+ case tcuTexture.CompareMode.COMPAREMODE_LESS:
+ res.isTrue = cmpReference - err < cmpValue;
+ res.isFalse = cmpReference + err >= cmpValue;
+ break;
+
+ case tcuTexture.CompareMode.COMPAREMODE_LESS_OR_EQUAL:
+ res.isTrue = cmpReference - err <= cmpValue;
+ res.isFalse = cmpReference + err > cmpValue;
+ break;
+
+ case tcuTexture.CompareMode.COMPAREMODE_GREATER:
+ res.isTrue = cmpReference + err > cmpValue;
+ res.isFalse = cmpReference - err <= cmpValue;
+ break;
+
+ case tcuTexture.CompareMode.COMPAREMODE_GREATER_OR_EQUAL:
+ res.isTrue = cmpReference + err >= cmpValue;
+ res.isFalse = cmpReference - err < cmpValue;
+ break;
+
+ case tcuTexture.CompareMode.COMPAREMODE_EQUAL:
+ res.isTrue = deMath.deInRange32(cmpValue, cmpReference - err, cmpReference + err);
+ res.isFalse = err != 0 || cmpValue != cmpReference;
+ break;
+
+ case tcuTexture.CompareMode.COMPAREMODE_NOT_EQUAL:
+ res.isTrue = err != 0 || cmpValue != cmpReference;
+ res.isFalse = deMath.deInRange32(cmpValue, cmpReference - err, cmpReference + err);
+ break;
+
+ case tcuTexture.CompareMode.COMPAREMODE_ALWAYS:
+ res.isTrue = true;
+ break;
+
+ case tcuTexture.CompareMode.COMPAREMODE_NEVER:
+ res.isFalse = true;
+ break;
+
+ default:
+ throw new Error('Invalid compare mode:' + compareMode);
+ }
+
+ assertMsgOptions(res.isTrue || res.isFalse, 'Both tests failed!', false, true);
+ return res;
+};
+
+/**
+ * @param {tcuTexture.TextureFormat} format
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isFixedPointDepthTextureFormat = function(format) {
+ var channelClass = tcuTexture.getTextureChannelClass(format.type);
+
+ if (format.order == tcuTexture.ChannelOrder.D) {
+ // depth internal formats cannot be non-normalized integers
+ return channelClass != tcuTexture.TextureChannelClass.FLOATING_POINT;
+ } else if (format.order == tcuTexture.ChannelOrder.DS) {
+ // combined formats have no single channel class, detect format manually
+ switch (format.type) {
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: return false;
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8: return true;
+
+ default:
+ throw new Error('Invalid texture format: ' + format);
+ }
+ }
+
+ return false;
+};
+
+/**
+ * @param {tcuTexture.CompareMode} compareMode
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} depths
+ * @param {Array<number>} fBounds
+ * @param {number} cmpReference
+ * @param {number} result
+ * @param {boolean} isFixedPointDepth
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isLinearCompareValid = function(compareMode, prec, depths, fBounds, cmpReference, result, isFixedPointDepth) {
+ assertMsgOptions(fBounds[0] >= 0 && fBounds[0] <= fBounds[1] && fBounds[1] <= 1, 'Invalid fBounds', false, true);
+
+ var d0 = depths[0];
+ var d1 = depths[1];
+
+ var cmp0 = tcuTexCompareVerifier.execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
+ var cmp1 = tcuTexCompareVerifier.execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
+ var cmp = [cmp0, cmp1];
+
+ var isTrue = getMask(cmp, function(x) {return x.isTrue;});
+ var isFalse = getMask(cmp, function(x) {return x.isFalse;});
+
+ var f0 = fBounds[0];
+ var f1 = fBounds[1];
+
+ var pcfErr = tcuTexVerifierUtil.computeFixedPointError(prec.pcfBits);
+ var resErr = tcuTexVerifierUtil.computeFixedPointError(prec.resultBits);
+ var totalErr = pcfErr + resErr;
+
+ for (var comb = 0; comb < 4; comb++) {
+ if (((comb & isTrue) | (~comb & isFalse )) != 3)
+ continue;
+
+ var cmp0True = ((comb >> 0) & 1) != 0;
+ var cmp1True = ((comb >> 1) & 1) != 0;
+
+ var ref0 = cmp0True ? 1 : 0;
+ var ref1 = cmp1True ? 1 : 0;
+
+ var v0 = ref0 * (1 - f0) + ref1 * f0;
+ var v1 = ref0 * (1 - f1) + ref1 * f1;
+ var minV = Math.min(v0, v1);
+ var maxV = Math.max(v0, v1);
+ var minR = minV - totalErr;
+ var maxR = maxV + totalErr;
+
+ if (deMath.deInRange32(result, minR, maxR))
+ return true;
+ }
+ return false;
+};
+
+/**
+ * @param {number} val
+ * @param {number} offset
+ * @return {Array<boolean>}
+ */
+tcuTexCompareVerifier.extractBVec4 = function(val, offset) {
+ return [
+ ((val >> (offset + 0)) & 1) != 0,
+ ((val >> (offset + 1)) & 1) != 0,
+ ((val >> (offset + 2)) & 1) != 0,
+ ((val >> (offset + 3)) & 1) != 0];
+};
+
+/**
+ * Values are in order (0,0), (1,0), (0,1), (1,1)
+ * @param {Array<number>} values
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+tcuTexCompareVerifier.bilinearInterpolate = function(values, x, y) {
+ var v00 = values[0];
+ var v10 = values[1];
+ var v01 = values[2];
+ var v11 = values[3];
+ var res = v00 * (1 - x) * (1 - y) + v10 * x * (1 - y) + v01 * (1 - x) * y + v11 * x * y;
+ return res;
+};
+
+/**
+ * @param {tcuTexture.CompareMode} compareMode
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} depths vec4
+ * @param {number} cmpReference
+ * @param {number} result
+ * @param {boolean} isFixedPointDepth
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isBilinearAnyCompareValid = function(compareMode,
+ prec,
+ depths,
+ cmpReference,
+ result,
+ isFixedPointDepth) {
+ assertMsgOptions(prec.pcfBits === 0, 'PCF bits must be 0', false, true);
+
+ var d0 = depths[0];
+ var d1 = depths[1];
+ var d2 = depths[2];
+ var d3 = depths[3];
+
+ var cmp0 = tcuTexCompareVerifier.execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
+ var cmp1 = tcuTexCompareVerifier.execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
+ var cmp2 = tcuTexCompareVerifier.execCompare(compareMode, d2, cmpReference, prec.referenceBits, isFixedPointDepth);
+ var cmp3 = tcuTexCompareVerifier.execCompare(compareMode, d3, cmpReference, prec.referenceBits, isFixedPointDepth);
+
+ var canBeTrue = cmp0.isTrue || cmp1.isTrue || cmp2.isTrue || cmp3.isTrue;
+ var canBeFalse = cmp0.isFalse || cmp1.isFalse || cmp2.isFalse || cmp3.isFalse;
+
+ var resErr = tcuTexVerifierUtil.computeFixedPointError(prec.resultBits);
+
+ var minBound = canBeFalse ? 0 : 1;
+ var maxBound = canBeTrue ? 1 : 0;
+
+ return deMath.deInRange32(result, minBound - resErr, maxBound + resErr);
+};
+
+/**
+ * @param {Array<tcuTexCompareVerifier.CmpResultSet>} arr
+ * @param {function(tcuTexCompareVerifier.CmpResultSet): boolean} getValue
+ * @return {number}
+ */
+var getMask = function(arr, getValue) {
+ var mask = 0;
+ for (var i = 0; i < arr.length; i++) {
+ var val = getValue(arr[i]);
+ if (val)
+ mask |= 1 << i;
+ }
+ return mask;
+};
+
+/**
+ * @param {tcuTexture.CompareMode} compareMode
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} depths vec4
+ * @param {Array<number>} xBounds vec2
+ * @param {Array<number>} yBounds vec2
+ * @param {number} cmpReference
+ * @param {number} result
+ * @param {boolean} isFixedPointDepth
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isBilinearPCFCompareValid = function(compareMode,
+ prec,
+ depths,
+ xBounds,
+ yBounds,
+ cmpReference,
+ result,
+ isFixedPointDepth) {
+ assertMsgOptions(0.0 <= xBounds[0] && xBounds[0] <= xBounds[1] && xBounds[1] <= 1.0, 'x coordinate out of bounds', false, true);
+ assertMsgOptions(0.0 <= yBounds[0] && yBounds[0] <= yBounds[1] && yBounds[1] <= 1.0, 'y coordinate out of bounds', false, true);
+ assertMsgOptions(prec.pcfBits > 0, 'PCF bits must be > 0', false, true);
+
+ var d0 = depths[0];
+ var d1 = depths[1];
+ var d2 = depths[2];
+ var d3 = depths[3];
+
+ /** @type {Array<tcuTexCompareVerifier.CmpResultSet>} */ var cmp = [];
+ cmp[0] = tcuTexCompareVerifier.execCompare(compareMode, d0, cmpReference, prec.referenceBits, isFixedPointDepth);
+ cmp[1] = tcuTexCompareVerifier.execCompare(compareMode, d1, cmpReference, prec.referenceBits, isFixedPointDepth);
+ cmp[2] = tcuTexCompareVerifier.execCompare(compareMode, d2, cmpReference, prec.referenceBits, isFixedPointDepth);
+ cmp[3] = tcuTexCompareVerifier.execCompare(compareMode, d3, cmpReference, prec.referenceBits, isFixedPointDepth);
+
+ var isTrue = getMask(cmp, function(x) {return x.isTrue});
+ var isFalse = getMask(cmp, function(x) {return x.isFalse});
+
+ // Interpolation parameters
+ var x0 = xBounds[0];
+ var x1 = xBounds[1];
+ var y0 = yBounds[0];
+ var y1 = yBounds[1];
+
+ // Error parameters
+ var pcfErr = tcuTexVerifierUtil.computeFixedPointError(prec.pcfBits);
+ var resErr = tcuTexVerifierUtil.computeFixedPointError(prec.resultBits);
+ var totalErr = pcfErr + resErr;
+
+ // Iterate over all valid combinations.
+ // \note It is not enough to compute minmax over all possible result sets, as ranges may
+ // not necessarily overlap, i.e. there are gaps between valid ranges.
+ for (var comb = 0; comb < (1 << 4); comb++) {
+ // Filter out invalid combinations:
+ // 1) True bit is set in comb but not in isTrue => sample can not be true
+ // 2) True bit is NOT set in comb and not in isFalse => sample can not be false
+ if (((comb & isTrue) | (~comb & isFalse)) != (1 << 4) - 1)
+ continue;
+
+ var cmpTrue = tcuTexCompareVerifier.extractBVec4(comb, 0);
+ var refVal = tcuTextureUtil.select([1, 1, 1, 1], [0, 0, 0, 0], cmpTrue);
+
+ var v0 = tcuTexCompareVerifier.bilinearInterpolate(refVal, x0, y0);
+ var v1 = tcuTexCompareVerifier.bilinearInterpolate(refVal, x1, y0);
+ var v2 = tcuTexCompareVerifier.bilinearInterpolate(refVal, x0, y1);
+ var v3 = tcuTexCompareVerifier.bilinearInterpolate(refVal, x1, y1);
+ var minV = Math.min(v0, v1, v2, v3);
+ var maxV = Math.max(v0, v1, v2, v3);
+ var minR = minV - totalErr;
+ var maxR = maxV + totalErr;
+
+ if (deMath.deInRange32(result, minR, maxR))
+ return true;
+ }
+
+ return false;
+};
+
+/**
+ * @param {tcuTexture.CompareMode} compareMode
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} depths vec4
+ * @param {Array<number>} xBounds vec2
+ * @param {Array<number>} yBounds vec2
+ * @param {number} cmpReference
+ * @param {number} result
+ * @param {boolean} isFixedPointDepth
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isBilinearCompareValid = function(compareMode,
+ prec,
+ depths,
+ xBounds,
+ yBounds,
+ cmpReference,
+ result,
+ isFixedPointDepth) {
+ if (prec.pcfBits > 0)
+ return tcuTexCompareVerifier.isBilinearPCFCompareValid(compareMode, prec, depths, xBounds, yBounds, cmpReference, result, isFixedPointDepth);
+ else
+ return tcuTexCompareVerifier.isBilinearAnyCompareValid(compareMode, prec, depths, cmpReference, result, isFixedPointDepth);
+};
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} coord vec2 texture coordinates
+ * @param {number} coordZ
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isLinearCompareResultValid = function(level,
+ sampler,
+ prec,
+ coord,
+ coordZ,
+ cmpReference,
+ result) {
+ var isFixedPointDepth = tcuTexCompareVerifier.isFixedPointDepthTextureFormat(level.getFormat());
+ var uBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ var vBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord[1], prec.coordBits[1], prec.uvwBits[1]);
+
+ // Integer coordinate bounds for (x0,y0) - without wrap mode
+ var minI = Math.floor(uBounds[0] - 0.5);
+ var maxI = Math.floor(uBounds[1] - 0.5);
+ var minJ = Math.floor(vBounds[0] - 0.5);
+ var maxJ = Math.floor(vBounds[1] - 0.5);
+
+ var w = level.getWidth();
+ var h = level.getHeight();
+
+ // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
+
+ for (var j = minJ; j <= maxJ; j++) {
+ for (var i = minI; i <= maxI; i++) {
+ // Wrapped coordinates
+ var x0 = tcuTexVerifierUtil.wrap(sampler.wrapS, i, w);
+ var x1 = tcuTexVerifierUtil.wrap(sampler.wrapS, i + 1, w);
+ var y0 = tcuTexVerifierUtil.wrap(sampler.wrapT, j, h);
+ var y1 = tcuTexVerifierUtil.wrap(sampler.wrapT, j + 1, h);
+
+ // Bounds for filtering factors
+ var minA = deMath.clamp((uBounds[0] - 0.5) - i, 0, 1);
+ var maxA = deMath.clamp((uBounds[1] - 0.5) - i, 0, 1);
+ var minB = deMath.clamp((vBounds[0] - 0.5) - j, 0, 1);
+ var maxB = deMath.clamp((vBounds[1] - 0.5) - j, 0, 1);
+
+ var depths = [
+ level.getPixDepth(x0, y0, coordZ),
+ level.getPixDepth(x1, y0, coordZ),
+ level.getPixDepth(x0, y1, coordZ),
+ level.getPixDepth(x1, y1, coordZ)
+ ];
+
+ if (tcuTexCompareVerifier.isBilinearCompareValid(sampler.compare, prec, depths, [minA, maxA], [minB, maxB], cmpReference, result, isFixedPointDepth))
+ return true;
+ }
+ }
+
+ return false;
+};
+
+/**
+ * @param {tcuTexCompareVerifier.CmpResultSet} resultSet
+ * @param {number} result
+ * @param {number} resultBits
+ */
+tcuTexCompareVerifier.isResultInSet = function(resultSet, result, resultBits) {
+ var err = tcuTexVerifierUtil.computeFixedPointError(resultBits);
+ var minR = result - err;
+ var maxR = result + err;
+
+ return (resultSet.isTrue && deMath.deInRange32(1, minR, maxR)) ||
+ (resultSet.isFalse && deMath.deInRange32(0, minR, maxR));
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} coord vec2 texture coordinates
+ * @param {number} coordZ
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isNearestCompareResultValid = function(level,
+ sampler,
+ prec,
+ coord,
+ coordZ,
+ cmpReference,
+ result) {
+ var isFixedPointDepth = tcuTexCompareVerifier.isFixedPointDepthTextureFormat(level.getFormat());
+ var uBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ var vBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord[1], prec.coordBits[1], prec.uvwBits[1]);
+
+ // Integer coordinates - without wrap mode
+ var minI = Math.floor(uBounds[0]);
+ var maxI = Math.floor(uBounds[1]);
+ var minJ = Math.floor(vBounds[0]);
+ var maxJ = Math.floor(vBounds[1]);
+
+ for (var j = minJ; j <= maxJ; j++) {
+ for (var i = minI; i <= maxI; i++) {
+ var x = tcuTexVerifierUtil.wrap(sampler.wrapS, i, level.getWidth());
+ var y = tcuTexVerifierUtil.wrap(sampler.wrapT, j, level.getHeight());
+ var depth = level.getPixDepth(x, y, coordZ);
+ var resSet = tcuTexCompareVerifier.execCompare(sampler.compare, depth, cmpReference, prec.referenceBits, isFixedPointDepth);
+
+ if (tcuTexCompareVerifier.isResultInSet(resSet, result, prec.resultBits))
+ return true;
+ }
+ }
+
+ return false;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} filterMode
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} coord vec2 texture coordinates
+ * @param {number} coordZ
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isLevelCompareResultValid = function(level,
+ sampler,
+ filterMode,
+ prec,
+ coord,
+ coordZ,
+ cmpReference,
+ result) {
+ if (filterMode == tcuTexture.FilterMode.LINEAR)
+ return tcuTexCompareVerifier.isLinearCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
+ else
+ return tcuTexCompareVerifier.isNearestCompareResultValid(level, sampler, prec, coord, coordZ, cmpReference, result);
+};
+
+/**
+ * @param {tcuTexture.CompareMode} compareMode
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} depths0 vec4
+ * @param {Array<number>} depths1 vec4
+ * @param {number} cmpReference
+ * @param {number} result
+ * @param {boolean} isFixedPointDepth
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isTrilinearAnyCompareValid = function(compareMode,
+ prec,
+ depths0,
+ depths1,
+ cmpReference,
+ result,
+ isFixedPointDepth) {
+ assertMsgOptions(prec.pcfBits === 0, 'PCF bits must be 0', false, true);
+
+ var cmp00 = tcuTexCompareVerifier.execCompare(compareMode, depths0[0], cmpReference, prec.referenceBits, isFixedPointDepth);
+ var cmp01 = tcuTexCompareVerifier.execCompare(compareMode, depths0[1], cmpReference, prec.referenceBits, isFixedPointDepth);
+ var cmp02 = tcuTexCompareVerifier.execCompare(compareMode, depths0[2], cmpReference, prec.referenceBits, isFixedPointDepth);
+ var cmp03 = tcuTexCompareVerifier.execCompare(compareMode, depths0[3], cmpReference, prec.referenceBits, isFixedPointDepth);
+ var cmp10 = tcuTexCompareVerifier.execCompare(compareMode, depths1[0], cmpReference, prec.referenceBits, isFixedPointDepth);
+ var cmp11 = tcuTexCompareVerifier.execCompare(compareMode, depths1[1], cmpReference, prec.referenceBits, isFixedPointDepth);
+ var cmp12 = tcuTexCompareVerifier.execCompare(compareMode, depths1[2], cmpReference, prec.referenceBits, isFixedPointDepth);
+ var cmp13 = tcuTexCompareVerifier.execCompare(compareMode, depths1[3], cmpReference, prec.referenceBits, isFixedPointDepth);
+
+ var canBeTrue = cmp00.isTrue ||
+ cmp01.isTrue ||
+ cmp02.isTrue ||
+ cmp03.isTrue ||
+ cmp10.isTrue ||
+ cmp11.isTrue ||
+ cmp12.isTrue ||
+ cmp13.isTrue;
+ var canBeFalse = cmp00.isFalse ||
+ cmp01.isFalse ||
+ cmp02.isFalse ||
+ cmp03.isFalse ||
+ cmp10.isFalse ||
+ cmp11.isFalse ||
+ cmp12.isFalse ||
+ cmp13.isFalse;
+
+ var resErr = tcuTexVerifierUtil.computeFixedPointError(prec.resultBits);
+
+ var minBound = canBeFalse ? 0 : 1;
+ var maxBound = canBeTrue ? 1 : 0;
+
+ return deMath.deInRange32(result, minBound - resErr, maxBound + resErr);
+};
+
+/**
+ * @param {tcuTexture.CompareMode} compareMode
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} depths0 vec4
+ * @param {Array<number>} depths1 vec4
+ * @param {Array<number>} xBounds0
+ * @param {Array<number>} yBounds0
+ * @param {Array<number>} xBounds1
+ * @param {Array<number>} yBounds1
+ * @param {Array<number>} fBounds
+ * @param {number} cmpReference
+ * @param {number} result
+ * @param {boolean} isFixedPointDepth
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isTrilinearPCFCompareValid = function(compareMode,
+ prec,
+ depths0,
+ depths1,
+ xBounds0,
+ yBounds0,
+ xBounds1,
+ yBounds1,
+ fBounds,
+ cmpReference,
+ result,
+ isFixedPointDepth) {
+ assertMsgOptions(0.0 <= xBounds0[0] && xBounds0[0] <= xBounds0[1] && xBounds0[1] <= 1.0, 'x0 coordinate out of bounds', false, true);
+ assertMsgOptions(0.0 <= yBounds0[0] && yBounds0[0] <= yBounds0[1] && yBounds0[1] <= 1.0, 'y0 coordinate out of bounds', false, true);
+ assertMsgOptions(0.0 <= xBounds1[0] && xBounds1[0] <= xBounds1[1] && xBounds1[1] <= 1.0, 'x1 coordinate out of bounds', false, true);
+ assertMsgOptions(0.0 <= yBounds1[0] && yBounds1[0] <= yBounds1[1] && yBounds1[1] <= 1.0, 'y1 coordinate out of bounds', false, true);
+ assertMsgOptions(0.0 <= fBounds[0] && fBounds[0] <= fBounds[1] && fBounds[1] <= 1.0, 'linear factor out of bounds', false, true);
+ assertMsgOptions(prec.pcfBits > 0, 'PCF bits must be > 0', false, true);
+
+ /** @type {Array<tcuTexCompareVerifier.CmpResultSet>} */ var cmp = [];
+ cmp.push(tcuTexCompareVerifier.execCompare(compareMode, depths0[0], cmpReference, prec.referenceBits, isFixedPointDepth));
+ cmp.push(tcuTexCompareVerifier.execCompare(compareMode, depths0[1], cmpReference, prec.referenceBits, isFixedPointDepth));
+ cmp.push(tcuTexCompareVerifier.execCompare(compareMode, depths0[2], cmpReference, prec.referenceBits, isFixedPointDepth));
+ cmp.push(tcuTexCompareVerifier.execCompare(compareMode, depths0[3], cmpReference, prec.referenceBits, isFixedPointDepth));
+ cmp.push(tcuTexCompareVerifier.execCompare(compareMode, depths1[0], cmpReference, prec.referenceBits, isFixedPointDepth));
+ cmp.push(tcuTexCompareVerifier.execCompare(compareMode, depths1[1], cmpReference, prec.referenceBits, isFixedPointDepth));
+ cmp.push(tcuTexCompareVerifier.execCompare(compareMode, depths1[2], cmpReference, prec.referenceBits, isFixedPointDepth));
+ cmp.push(tcuTexCompareVerifier.execCompare(compareMode, depths1[3], cmpReference, prec.referenceBits, isFixedPointDepth));
+
+ var isTrue = getMask(cmp, function(x) {return x.isTrue});
+ var isFalse = getMask(cmp, function(x) {return x.isFalse});
+
+ // Error parameters
+ var pcfErr = tcuTexVerifierUtil.computeFixedPointError(prec.pcfBits);
+ var resErr = tcuTexVerifierUtil.computeFixedPointError(prec.resultBits);
+ var totalErr = pcfErr + resErr;
+
+ // Iterate over all valid combinations.
+ for (var comb = 0; comb < (1 << 8); comb++) {
+ // Filter out invalid combinations.
+ if (((comb & isTrue) | (~comb & isFalse)) != (1 << 8) - 1)
+ continue;
+
+ var cmpTrue0 = tcuTexCompareVerifier.extractBVec4(comb, 0);
+ var cmpTrue1 = tcuTexCompareVerifier.extractBVec4(comb, 4);
+ var refVal0 = tcuTextureUtil.select([1, 1, 1, 1], [0, 0, 0, 0], cmpTrue0);
+ var refVal1 = tcuTextureUtil.select([1, 1, 1, 1], [0, 0, 0, 0], cmpTrue1);
+
+ // Bilinear interpolation within levels.
+ var v00 = tcuTexCompareVerifier.bilinearInterpolate(refVal0, xBounds0[0], yBounds0[0]);
+ var v01 = tcuTexCompareVerifier.bilinearInterpolate(refVal0, xBounds0[1], yBounds0[0]);
+ var v02 = tcuTexCompareVerifier.bilinearInterpolate(refVal0, xBounds0[0], yBounds0[1]);
+ var v03 = tcuTexCompareVerifier.bilinearInterpolate(refVal0, xBounds0[1], yBounds0[1]);
+ var minV0 = Math.min(v00, v01, v02, v03);
+ var maxV0 = Math.max(v00, v01, v02, v03);
+
+ var v10 = tcuTexCompareVerifier.bilinearInterpolate(refVal1, xBounds1[0], yBounds1[0]);
+ var v11 = tcuTexCompareVerifier.bilinearInterpolate(refVal1, xBounds1[1], yBounds1[0]);
+ var v12 = tcuTexCompareVerifier.bilinearInterpolate(refVal1, xBounds1[0], yBounds1[1]);
+ var v13 = tcuTexCompareVerifier.bilinearInterpolate(refVal1, xBounds1[1], yBounds1[1]);
+ var minV1 = Math.min(v10, v11, v12, v13);
+ var maxV1 = Math.max(v10, v11, v12, v13);
+
+ // Compute min-max bounds by filtering between minimum bounds and maximum bounds between levels.
+ // HW can end up choosing pretty much any of samples between levels, and thus interpolating
+ // between minimums should yield lower bound for range, and same for upper bound.
+ // \todo [2013-07-17 pyry] This seems separable? Can this be optimized? At least ranges could be pre-computed and later combined.
+ var minF0 = minV0 * (1 - fBounds[0]) + minV1 * fBounds[0];
+ var minF1 = minV0 * (1 - fBounds[1]) + minV1 * fBounds[1];
+ var maxF0 = maxV0 * (1 - fBounds[0]) + maxV1 * fBounds[0];
+ var maxF1 = maxV0 * (1 - fBounds[1]) + maxV1 * fBounds[1];
+
+ var minF = Math.min(minF0, minF1);
+ var maxF = Math.max(maxF0, maxF1);
+
+ var minR = minF - totalErr;
+ var maxR = maxF + totalErr;
+
+ if (deMath.deInRange32(result, minR, maxR))
+ return true;
+ }
+
+ return false;
+
+};
+
+/**
+ * @param {tcuTexture.CompareMode} compareMode
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} depths0 vec4
+ * @param {Array<number>} depths1 vec4
+ * @param {Array<number>} xBounds0
+ * @param {Array<number>} yBounds0
+ * @param {Array<number>} xBounds1
+ * @param {Array<number>} yBounds1
+ * @param {Array<number>} fBounds
+ * @param {number} cmpReference
+ * @param {number} result
+ * @param {boolean} isFixedPointDepth
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isTrilinearCompareValid = function(compareMode,
+ prec,
+ depths0,
+ depths1,
+ xBounds0,
+ yBounds0,
+ xBounds1,
+ yBounds1,
+ fBounds,
+ cmpReference,
+ result,
+ isFixedPointDepth) {
+ if (prec.pcfBits > 0)
+ return tcuTexCompareVerifier.isTrilinearPCFCompareValid(compareMode, prec, depths0, depths1, xBounds0, yBounds0, xBounds1, yBounds1, fBounds, cmpReference, result, isFixedPointDepth);
+ else
+ return tcuTexCompareVerifier.isTrilinearAnyCompareValid(compareMode, prec, depths0, depths1, cmpReference, result, isFixedPointDepth);
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} level0
+ * @param {tcuTexture.ConstPixelBufferAccess} level1
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} coord vec2 texture coordinates
+ * @param {number} coordZ
+ * @param {Array<number>} fBounds vec2
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isLinearMipmapLinearCompareResultValid = function(level0,
+ level1,
+ sampler,
+ prec,
+ coord,
+ coordZ,
+ fBounds,
+ cmpReference,
+ result) {
+ var isFixedPointDepth = tcuTexCompareVerifier.isFixedPointDepthTextureFormat(level0.getFormat());
+
+ // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
+ // Right now this allows pairing any two valid bilinear quads.
+
+ var w0 = level0.getWidth();
+ var w1 = level1.getWidth();
+ var h0 = level0.getHeight();
+ var h1 = level1.getHeight();
+
+ var uBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ var uBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ var vBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord[1], prec.coordBits[1], prec.uvwBits[1]);
+ var vBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord[1], prec.coordBits[1], prec.uvwBits[1]);
+
+ // Integer coordinates - without wrap mode
+ var minI0 = Math.floor(uBounds0[0] - 0.5);
+ var maxI0 = Math.floor(uBounds0[1] - 0.5);
+ var minI1 = Math.floor(uBounds1[0] - 0.5);
+ var maxI1 = Math.floor(uBounds1[1] - 0.5);
+ var minJ0 = Math.floor(vBounds0[0] - 0.5);
+ var maxJ0 = Math.floor(vBounds0[1] - 0.5);
+ var minJ1 = Math.floor(vBounds1[0] - 0.5);
+ var maxJ1 = Math.floor(vBounds1[1] - 0.5);
+
+ for (var j0 = minJ0; j0 <= maxJ0; j0++) {
+ for (var i0 = minI0; i0 <= maxI0; i0++) {
+ var minA0 = deMath.clamp((uBounds0[0] - 0.5) - i0, 0, 1);
+ var maxA0 = deMath.clamp((uBounds0[1] - 0.5) - i0, 0, 1);
+ var minB0 = deMath.clamp((vBounds0[0] - 0.5) - j0, 0, 1);
+ var maxB0 = deMath.clamp((vBounds0[1] - 0.5) - j0, 0, 1);
+ var depths0 = [];
+
+ var x0 = tcuTexVerifierUtil.wrap(sampler.wrapS, i0, w0);
+ var x1 = tcuTexVerifierUtil.wrap(sampler.wrapS, i0 + 1, w0);
+ var y0 = tcuTexVerifierUtil.wrap(sampler.wrapT, j0, h0);
+ var y1 = tcuTexVerifierUtil.wrap(sampler.wrapT, j0 + 1, h0);
+
+ depths0[0] = level0.getPixDepth(x0, y0, coordZ);
+ depths0[1] = level0.getPixDepth(x1, y0, coordZ);
+ depths0[2] = level0.getPixDepth(x0, y1, coordZ);
+ depths0[3] = level0.getPixDepth(x1, y1, coordZ);
+
+ for (var j1 = minJ1; j1 <= maxJ1; j1++) {
+ for (var i1 = minI1; i1 <= maxI1; i1++) {
+ var minA1 = deMath.clamp((uBounds1[0] - 0.5) - i1, 0, 1);
+ var maxA1 = deMath.clamp((uBounds1[1] - 0.5) - i1, 0, 1);
+ var minB1 = deMath.clamp((vBounds1[0] - 0.5) - j1, 0, 1);
+ var maxB1 = deMath.clamp((vBounds1[1] - 0.5) - j1, 0, 1);
+ var depths1 = [];
+
+ x0 = tcuTexVerifierUtil.wrap(sampler.wrapS, i1, w1);
+ x1 = tcuTexVerifierUtil.wrap(sampler.wrapS, i1 + 1, w1);
+ y0 = tcuTexVerifierUtil.wrap(sampler.wrapT, j1, h1);
+ y1 = tcuTexVerifierUtil.wrap(sampler.wrapT, j1 + 1, h1);
+
+ depths1[0] = level1.getPixDepth(x0, y0, coordZ);
+ depths1[1] = level1.getPixDepth(x1, y0, coordZ);
+ depths1[2] = level1.getPixDepth(x0, y1, coordZ);
+ depths1[3] = level1.getPixDepth(x1, y1, coordZ);
+
+ if (tcuTexCompareVerifier.isTrilinearCompareValid(sampler.compare, prec, depths0, depths1,
+ [minA0, maxA0], [minB0, maxB0],
+ [minA1, maxA1], [minB1, maxB1],
+ fBounds, cmpReference, result, isFixedPointDepth))
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} level0
+ * @param {tcuTexture.ConstPixelBufferAccess} level1
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} coord vec2 texture coordinates
+ * @param {number} coordZ
+ * @param {Array<number>} fBounds vec2
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isNearestMipmapLinearCompareResultValid = function(level0,
+ level1,
+ sampler,
+ prec,
+ coord,
+ coordZ,
+ fBounds,
+ cmpReference,
+ result) {
+ var isFixedPointDepth = tcuTexCompareVerifier.isFixedPointDepthTextureFormat(level0.getFormat());
+
+ var w0 = level0.getWidth();
+ var w1 = level1.getWidth();
+ var h0 = level0.getHeight();
+ var h1 = level1.getHeight();
+
+ var uBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, w0, coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ var uBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, w1, coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ var vBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, h0, coord[1], prec.coordBits[1], prec.uvwBits[1]);
+ var vBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, h1, coord[1], prec.coordBits[1], prec.uvwBits[1]);
+
+ var minI0 = Math.floor(uBounds0[0]);
+ var maxI0 = Math.floor(uBounds0[1]);
+ var minI1 = Math.floor(uBounds1[0]);
+ var maxI1 = Math.floor(uBounds1[1]);
+ var minJ0 = Math.floor(vBounds0[0]);
+ var maxJ0 = Math.floor(vBounds0[1]);
+ var minJ1 = Math.floor(vBounds1[0]);
+ var maxJ1 = Math.floor(vBounds1[1]);
+
+ for (var j0 = minJ0; j0 <= maxJ0; j0++) {
+ for (var i0 = minI0; i0 <= maxI0; i0++) {
+ var x0 = tcuTexVerifierUtil.wrap(sampler.wrapS, i0, w0);
+ var y0 = tcuTexVerifierUtil.wrap(sampler.wrapT, j0, h0);
+
+ // Derivated from C++ dEQP function lookupDepth()
+ // Since x0 and y0 are wrapped, here lookupDepth() returns the same result as getPixDepth()
+ assertMsgOptions(deMath.deInBounds32(x0, 0, level0.getWidth()) && deMath.deInBounds32(y0, 0, level0.getHeight()) && deMath.deInBounds32(coordZ, 0, level0.getDepth()), 'x0, y0 or coordZ out of bound.', false, true);
+ var depth0 = level0.getPixDepth(x0, y0, coordZ);
+
+ for (var j1 = minJ1; j1 <= maxJ1; j1++) {
+ for (var i1 = minI1; i1 <= maxI1; i1++) {
+ var x1 = tcuTexVerifierUtil.wrap(sampler.wrapS, i1, w1);
+ var y1 = tcuTexVerifierUtil.wrap(sampler.wrapT, j1, h1);
+
+ // Derivated from C++ dEQP function lookupDepth()
+ // Since x1 and y1 are wrapped, here lookupDepth() returns the same result as getPixDepth()
+ assertMsgOptions(deMath.deInBounds32(x1, 0, level1.getWidth()) && deMath.deInBounds32(y1, 0, level1.getHeight()), 'x1 or y1 out of bound.', false, true);
+ var depth1 = level1.getPixDepth(x1, y1, coordZ);
+
+ if (tcuTexCompareVerifier.isLinearCompareValid(sampler.compare, prec, [depth0, depth1], fBounds, cmpReference, result, isFixedPointDepth))
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} level0
+ * @param {tcuTexture.ConstPixelBufferAccess} level1
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} levelFilter
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} coord vec2 texture coordinates
+ * @param {number} coordZ
+ * @param {Array<number>} fBounds vec2
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isMipmapLinearCompareResultValid = function(level0,
+ level1,
+ sampler,
+ levelFilter,
+ prec,
+ coord,
+ coordZ,
+ fBounds,
+ cmpReference,
+ result) {
+ if (levelFilter == tcuTexture.FilterMode.LINEAR)
+ return tcuTexCompareVerifier.isLinearMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
+ else
+ return tcuTexCompareVerifier.isNearestMipmapLinearCompareResultValid(level0, level1, sampler, prec, coord, coordZ, fBounds, cmpReference, result);
+};
+
+/**
+ * @param {tcuTexture.Texture2DView} texture
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} coord vec2 texture coordinates
+ * @param {Array<number>} lodBounds vec2 level-of-detail bounds
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isTexCompareResultValid2D = function(texture, sampler, prec, coord, lodBounds, cmpReference, result) {
+ var minLod = lodBounds[0];
+ var maxLod = lodBounds[1];
+ var canBeMagnified = minLod <= sampler.lodThreshold;
+ var canBeMinified = maxLod > sampler.lodThreshold;
+
+ if (canBeMagnified) {
+ if (tcuTexCompareVerifier.isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, coord, 0, cmpReference, result))
+ return true;
+ }
+
+ if (canBeMinified) {
+ var isNearestMipmap = tcuTexVerifierUtil.isNearestMipmapFilter(sampler.minFilter);
+ var isLinearMipmap = tcuTexVerifierUtil.isLinearMipmapFilter(sampler.minFilter);
+ var minTexLevel = 0;
+ var maxTexLevel = texture.getNumLevels() - 1;
+
+ assertMsgOptions(minTexLevel < maxTexLevel, 'Invalid texture levels.', false, true);
+
+ if (isLinearMipmap) {
+ var minLevel = deMath.clamp(Math.floor(minLod), minTexLevel, maxTexLevel - 1);
+ var maxLevel = deMath.clamp(Math.floor(maxLod), minTexLevel, maxTexLevel - 1);
+
+ assertMsgOptions(minLevel <= maxLevel, 'Invalid texture levels.', false, true);
+
+ for (var level = minLevel; level <= maxLevel; level++) {
+ var minF = deMath.clamp(minLod - level, 0, 1);
+ var maxF = deMath.clamp(maxLod - level, 0, 1);
+
+ if (tcuTexCompareVerifier.isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level + 1), sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, coord, 0, [minF, maxF], cmpReference, result))
+ return true;
+ }
+ } else if (isNearestMipmap) {
+ // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
+ // decision to allow floor(lod + 0.5) as well.
+ var minLevel = deMath.clamp(Math.ceil(minLod + 0.5) - 1, minTexLevel, maxTexLevel);
+ var maxLevel = deMath.clamp(Math.floor(maxLod + 0.5), minTexLevel, maxTexLevel);
+
+ assertMsgOptions(minLevel <= maxLevel, 'Invalid texture levels.', false, true);
+
+ for (var level = minLevel; level <= maxLevel; level++) {
+ if (tcuTexCompareVerifier.isLevelCompareResultValid(texture.getLevel(level), sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, coord, 0, cmpReference, result))
+ return true;
+ }
+ } else {
+ if (tcuTexCompareVerifier.isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, coord, 0, cmpReference, result))
+ return true;
+ }
+ }
+
+ return false;
+};
+
+/**
+ * @param {tcuTexture.TextureCubeView} texture
+ * @param {number} baseLevelNdx
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {tcuTexture.CubeFaceCoords} coords
+ * @param {Array<number>} fBounds vec2
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isSeamplessLinearMipmapLinearCompareResultValid = function(texture,
+ baseLevelNdx,
+ sampler,
+ prec,
+ coords,
+ fBounds,
+ cmpReference,
+ result) {
+ var isFixedPointDepth = tcuTexCompareVerifier.isFixedPointDepthTextureFormat(texture.getLevelFace(baseLevelNdx, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X).getFormat());
+ var size0 = texture.getLevelFace(baseLevelNdx, coords.face).getWidth();
+ var size1 = texture.getLevelFace(baseLevelNdx + 1, coords.face).getWidth();
+
+ var uBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0, coords.s, prec.coordBits[0], prec.uvwBits[0]);
+ var uBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1, coords.s, prec.coordBits[0], prec.uvwBits[0]);
+ var vBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0, coords.t, prec.coordBits[1], prec.uvwBits[1]);
+ var vBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1, coords.t, prec.coordBits[1], prec.uvwBits[1]);
+
+ // Integer coordinates - without wrap mode
+ var minI0 = Math.floor(uBounds0[0] - 0.5);
+ var maxI0 = Math.floor(uBounds0[1] - 0.5);
+ var minI1 = Math.floor(uBounds1[0] - 0.5);
+ var maxI1 = Math.floor(uBounds1[1] - 0.5);
+ var minJ0 = Math.floor(vBounds0[0] - 0.5);
+ var maxJ0 = Math.floor(vBounds0[1] - 0.5);
+ var minJ1 = Math.floor(vBounds1[0] - 0.5);
+ var maxJ1 = Math.floor(vBounds1[1] - 0.5);
+
+ /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faces0 = [];
+ /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faces1 = [];
+
+ for (var key in tcuTexture.CubeFace) {
+ var face = tcuTexture.CubeFace[key];
+ faces0[face] = texture.getLevelFace(baseLevelNdx, face);
+ faces1[face] = texture.getLevelFace(baseLevelNdx + 1, face);
+ }
+
+ for (var j0 = minJ0; j0 <= maxJ0; j0++) {
+ for (var i0 = minI0; i0 <= maxI0; i0++) {
+ var minA0 = deMath.clamp((uBounds0[0] - 0.5) - i0, 0, 1);
+ var maxA0 = deMath.clamp((uBounds0[1] - 0.5) - i0, 0, 1);
+ var minB0 = deMath.clamp((vBounds0[0] - 0.5) - j0, 0, 1);
+ var maxB0 = deMath.clamp((vBounds0[1] - 0.5) - j0, 0, 1);
+ var depths0 = [];
+
+ var c00 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i0 + 0, j0 + 0]), size0);
+ var c10 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i0 + 1, j0 + 0]), size0);
+ var c01 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i0 + 0, j0 + 1]), size0);
+ var c11 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i0 + 1, j0 + 1]), size0);
+
+ // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
+ // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
+ if (c00 == null || c01 == null || c10 == null || c11 == null)
+ return true;
+
+ depths0[0] = faces0[c00.face].getPixDepth(c00.s, c00.t);
+ depths0[1] = faces0[c10.face].getPixDepth(c10.s, c10.t);
+ depths0[2] = faces0[c01.face].getPixDepth(c01.s, c01.t);
+ depths0[3] = faces0[c11.face].getPixDepth(c11.s, c11.t);
+
+ for (var j1 = minJ1; j1 <= maxJ1; j1++) {
+ for (var i1 = minI1; i1 <= maxI1; i1++) {
+ var minA1 = deMath.clamp((uBounds1[0] - 0.5) - i1, 0, 1);
+ var maxA1 = deMath.clamp((uBounds1[1] - 0.5) - i1, 0, 1);
+ var minB1 = deMath.clamp((vBounds1[0] - 0.5) - j1, 0, 1);
+ var maxB1 = deMath.clamp((vBounds1[1] - 0.5) - j1, 0, 1);
+ var depths1 = [];
+
+ c00 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i1 + 0, j1 + 0]), size1);
+ c10 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i1 + 1, j1 + 0]), size1);
+ c01 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i1 + 0, j1 + 1]), size1);
+ c11 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i1 + 1, j1 + 1]), size1);
+
+ if (c00 == null || c01 == null || c10 == null || c11 == null)
+ return true;
+
+ depths1[0] = faces1[c00.face].getPixDepth(c00.s, c00.t);
+ depths1[1] = faces1[c10.face].getPixDepth(c10.s, c10.t);
+ depths1[2] = faces1[c01.face].getPixDepth(c01.s, c01.t);
+ depths1[3] = faces1[c11.face].getPixDepth(c11.s, c11.t);
+
+ if (tcuTexCompareVerifier.isTrilinearCompareValid(sampler.compare, prec, depths0, depths1,
+ [minA0, maxA0], [minB0, maxB0],
+ [minA1, maxA1], [minB1, maxB1],
+ fBounds, cmpReference, result, isFixedPointDepth))
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+};
+
+/**
+ * @param {tcuTexture.TextureCubeView} texture
+ * @param {number} levelNdx
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {tcuTexture.CubeFaceCoords} coords
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+
+tcuTexCompareVerifier.isSeamlessLinearCompareResultValid = function(texture,
+ levelNdx,
+ sampler,
+ prec,
+ coords,
+ cmpReference,
+ result) {
+ var isFixedPointDepth = tcuTexCompareVerifier.isFixedPointDepthTextureFormat(texture.getLevelFace(levelNdx, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X).getFormat());
+ var size = texture.getLevelFace(levelNdx, coords.face).getWidth();
+
+ var uBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits[0], prec.uvwBits[0]);
+ var vBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits[1], prec.uvwBits[1]);
+
+ // Integer coordinate bounds for (x0,y0) - without wrap mode
+ var minI = Math.floor(uBounds[0] - 0.5);
+ var maxI = Math.floor(uBounds[1] - 0.5);
+ var minJ = Math.floor(vBounds[0] - 0.5);
+ var maxJ = Math.floor(vBounds[1] - 0.5);
+
+ // Face accesses
+ /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faces = [];
+
+ for (var key in tcuTexture.CubeFace) {
+ var face = tcuTexture.CubeFace[key];
+ faces[face] = texture.getLevelFace(levelNdx, face);
+ }
+
+ for (var j = minJ; j <= maxJ; j++) {
+ for (var i = minI; i <= maxI; i++) {
+ var c00 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i + 0, j + 0]), size);
+ var c10 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i + 1, j + 0]), size);
+ var c01 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i + 0, j + 1]), size);
+ var c11 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i + 1, j + 1]), size);
+
+ // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
+ // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
+ if (!c00 || !c01 || !c10 || !c11)
+ return true;
+
+ // Bounds for filtering factors
+ var minA = deMath.clamp((uBounds[0] - 0.5) - i, 0, 1);
+ var maxA = deMath.clamp((uBounds[1] - 0.5) - i, 0, 1);
+ var minB = deMath.clamp((vBounds[0] - 0.5) - j, 0, 1);
+ var maxB = deMath.clamp((vBounds[1] - 0.5) - j, 0, 1);
+
+ var depths = [];
+ depths[0] = faces[c00.face].getPixDepth(c00.s, c00.t);
+ depths[1] = faces[c10.face].getPixDepth(c10.s, c10.t);
+ depths[2] = faces[c01.face].getPixDepth(c01.s, c01.t);
+ depths[3] = faces[c11.face].getPixDepth(c11.s, c11.t);
+
+ if (tcuTexCompareVerifier.isBilinearCompareValid(sampler.compare, prec, depths, [minA, maxA], [minB, maxB], cmpReference, result, isFixedPointDepth))
+ return true;
+ }
+ }
+
+ return false;
+};
+
+/**
+ * @param {tcuTexture.TextureCubeView} texture
+ * @param {number} levelNdx
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} filterMode
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {tcuTexture.CubeFaceCoords} coords
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isCubeLevelCompareResultValid = function(texture,
+ levelNdx,
+ sampler,
+ filterMode,
+ prec,
+ coords,
+ cmpReference,
+ result) {
+ if (filterMode == tcuTexture.FilterMode.LINEAR) {
+ if (sampler.seamlessCubeMap)
+ return tcuTexCompareVerifier.isSeamlessLinearCompareResultValid(texture, levelNdx, sampler, prec, coords, cmpReference, result);
+ else
+ return tcuTexCompareVerifier.isLinearCompareResultValid(texture.getLevelFace(levelNdx, coords.face), sampler, prec, [coords.s, coords.t], 0, cmpReference, result);
+ } else
+ return tcuTexCompareVerifier.isNearestCompareResultValid(texture.getLevelFace(levelNdx, coords.face), sampler, prec, [coords.s, coords.t], 0, cmpReference, result);
+};
+
+/**
+ * @param {tcuTexture.TextureCubeView} texture
+ * @param {number} baseLevelNdx
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} levelFilter
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {tcuTexture.CubeFaceCoords} coords
+ * @param {Array<number>} fBounds vec2
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isCubeMipmapLinearCompareResultValid = function(texture,
+ baseLevelNdx,
+ sampler,
+ levelFilter,
+ prec,
+ coords,
+ fBounds,
+ cmpReference,
+ result) {
+ if (levelFilter == tcuTexture.FilterMode.LINEAR) {
+ if (sampler.seamlessCubeMap)
+ return tcuTexCompareVerifier.isSeamplessLinearMipmapLinearCompareResultValid(texture, baseLevelNdx, sampler, prec, coords, fBounds, cmpReference, result);
+ else
+ return tcuTexCompareVerifier.isLinearMipmapLinearCompareResultValid(texture.getLevelFace(baseLevelNdx, coords.face),
+ texture.getLevelFace(baseLevelNdx + 1, coords.face),
+ sampler, prec, [coords.s, coords.t], 0, fBounds, cmpReference, result);
+ } else
+ return tcuTexCompareVerifier.isNearestMipmapLinearCompareResultValid(texture.getLevelFace(baseLevelNdx, coords.face),
+ texture.getLevelFace(baseLevelNdx + 1, coords.face),
+ sampler, prec, [coords.s, coords.t], 0, fBounds, cmpReference, result);
+};
+
+/**
+ * @param {tcuTexture.TextureCubeView} texture
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} coord vec2 texture coordinates
+ * @param {Array<number>} lodBounds vec2 level-of-detail bounds
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isTexCompareResultValidCube = function(texture, sampler, prec, coord, lodBounds, cmpReference, result) {
+ /** @type {Array<tcuTexture.CubeFace>} */var possibleFaces = tcuTexVerifierUtil.getPossibleCubeFaces(coord, prec.coordBits);
+
+ if (!possibleFaces)
+ return true; // Result is undefined.
+
+ for (var tryFaceNdx = 0; tryFaceNdx < possibleFaces.length; tryFaceNdx++) {
+ var face = possibleFaces[tryFaceNdx];
+ var faceCoords = new tcuTexture.CubeFaceCoords(face, tcuTexture.projectToFace(face, coord));
+ var minLod = lodBounds[0];
+ var maxLod = lodBounds[1];
+ var canBeMagnified = minLod <= sampler.lodThreshold;
+ var canBeMinified = maxLod > sampler.lodThreshold;
+
+ if (canBeMagnified) {
+ if (tcuTexCompareVerifier.isCubeLevelCompareResultValid(texture, 0, sampler, sampler.magFilter, prec, faceCoords, cmpReference, result))
+ return true;
+ }
+
+ if (canBeMinified) {
+ var isNearestMipmap = tcuTexVerifierUtil.isNearestMipmapFilter(sampler.minFilter);
+ var isLinearMipmap = tcuTexVerifierUtil.isLinearMipmapFilter(sampler.minFilter);
+ var minTexLevel = 0;
+ var maxTexLevel = texture.getNumLevels() - 1;
+
+ assertMsgOptions(minTexLevel < maxTexLevel, 'Invalid texture levels.', false, true);
+
+ if (isLinearMipmap) {
+ var minLevel = deMath.clamp(Math.floor(minLod), minTexLevel, maxTexLevel - 1);
+ var maxLevel = deMath.clamp(Math.floor(maxLod), minTexLevel, maxTexLevel - 1);
+
+ assertMsgOptions(minLevel <= maxLevel, 'Invalid texture levels.', false, true);
+
+ for (var level = minLevel; level <= maxLevel; level++) {
+ var minF = deMath.clamp(minLod - level, 0, 1);
+ var maxF = deMath.clamp(maxLod - level, 0, 1);
+
+ if (tcuTexCompareVerifier.isCubeMipmapLinearCompareResultValid(texture, level, sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, faceCoords, [minF, maxF], cmpReference, result))
+ return true;
+ }
+ } else if (isNearestMipmap) {
+ // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
+ // decision to allow floor(lod + 0.5) as well.
+ var minLevel = deMath.clamp(Math.ceil(minLod + 0.5) - 1, minTexLevel, maxTexLevel);
+ var maxLevel = deMath.clamp(Math.floor(maxLod + 0.5), minTexLevel, maxTexLevel);
+
+ assertMsgOptions(minLevel <= maxLevel, 'Invalid texture levels.', false, true);
+
+ for (var level = minLevel; level <= maxLevel; level++) {
+ if (tcuTexCompareVerifier.isCubeLevelCompareResultValid(texture, level, sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, faceCoords, cmpReference, result))
+ return true;
+ }
+ } else {
+ if (tcuTexCompareVerifier.isCubeLevelCompareResultValid(texture, 0, sampler, sampler.minFilter, prec, faceCoords, cmpReference, result))
+ return true;
+ }
+ }
+ }
+
+ return false;
+};
+
+/**
+ * @param {tcuTexture.Texture2DArrayView} texture
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexCompareVerifier.TexComparePrecision} prec
+ * @param {Array<number>} coord vec3 texture coordinates
+ * @param {Array<number>} lodBounds vec2 level-of-detail bounds
+ * @param {number} cmpReference
+ * @param {number} result
+ * @return {boolean}
+ */
+tcuTexCompareVerifier.isTexCompareResultValid2DArray = function(texture, sampler, prec, coord, lodBounds, cmpReference, result) {
+ var depthErr = tcuTexVerifierUtil.computeFloatingPointError(coord[2], prec.coordBits[2]) + tcuTexVerifierUtil.computeFixedPointError(prec.uvwBits[2]);
+ var minZ = coord[2] - depthErr;
+ var maxZ = coord[2] + depthErr;
+ var minLayer = deMath.clamp(Math.floor(minZ + 0.5), 0, texture.getNumLayers() - 1);
+ var maxLayer = deMath.clamp(Math.floor(maxZ + 0.5), 0, texture.getNumLayers() - 1);
+
+ for (var layer = minLayer; layer <= maxLayer; layer++) {
+ var minLod = lodBounds[0];
+ var maxLod = lodBounds[1];
+ var canBeMagnified = minLod <= sampler.lodThreshold;
+ var canBeMinified = maxLod > sampler.lodThreshold;
+
+ if (canBeMagnified) {
+ if (tcuTexCompareVerifier.isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.magFilter, prec, deMath.swizzle(coord, [0, 1]), layer, cmpReference, result))
+ return true;
+ }
+
+ if (canBeMinified) {
+ var isNearestMipmap = tcuTexVerifierUtil.isNearestMipmapFilter(sampler.minFilter);
+ var isLinearMipmap = tcuTexVerifierUtil.isLinearMipmapFilter(sampler.minFilter);
+ var minTexLevel = 0;
+ var maxTexLevel = texture.getNumLevels() - 1;
+
+ assertMsgOptions(minTexLevel < maxTexLevel, 'Invalid texture levels.', false, true);
+
+ if (isLinearMipmap) {
+ var minLevel = deMath.clamp(Math.floor(minLod), minTexLevel, maxTexLevel - 1);
+ var maxLevel = deMath.clamp(Math.floor(maxLod), minTexLevel, maxTexLevel - 1);
+
+ assertMsgOptions(minLevel <= maxLevel, 'Invalid texture levels.', false, true);
+
+ for (var level = minLevel; level <= maxLevel; level++) {
+ var minF = deMath.clamp(minLod - level, 0, 1);
+ var maxF = deMath.clamp(maxLod - level, 0, 1);
+
+ if (tcuTexCompareVerifier.isMipmapLinearCompareResultValid(texture.getLevel(level), texture.getLevel(level + 1), sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, deMath.swizzle(coord, [0, 1]), layer, [minF, maxF], cmpReference, result))
+ return true;
+ }
+ } else if (isNearestMipmap) {
+ // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
+ // decision to allow floor(lod + 0.5) as well.
+ var minLevel = deMath.clamp(Math.ceil(minLod + 0.5) - 1, minTexLevel, maxTexLevel);
+ var maxLevel = deMath.clamp(Math.floor(maxLod + 0.5), minTexLevel, maxTexLevel);
+
+ assertMsgOptions(minLevel <= maxLevel, 'Invalid texture levels.', false, true);
+
+ for (var level = minLevel; level <= maxLevel; level++) {
+ if (tcuTexCompareVerifier.isLevelCompareResultValid(texture.getLevel(level), sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, deMath.swizzle(coord, [0, 1]), layer, cmpReference, result))
+ return true;
+ }
+ } else {
+ if (tcuTexCompareVerifier.isLevelCompareResultValid(texture.getLevel(0), sampler, sampler.minFilter, prec, deMath.swizzle(coord, [0, 1]), layer, cmpReference, result))
+ return true;
+ }
+ }
+ }
+
+ return false;
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexLookupVerifier.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexLookupVerifier.js
new file mode 100644
index 0000000000..6b471998aa
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexLookupVerifier.js
@@ -0,0 +1,2225 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuTexLookupVerifier');
+goog.require('framework.common.tcuTexVerifierUtil');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.common.tcuTextureUtil');
+goog.require('framework.delibs.debase.deMath');
+
+goog.scope(function() {
+
+ var tcuTexLookupVerifier = framework.common.tcuTexLookupVerifier;
+ var tcuTexture = framework.common.tcuTexture;
+ var tcuTextureUtil = framework.common.tcuTextureUtil;
+ var tcuTexVerifierUtil = framework.common.tcuTexVerifierUtil;
+ var deMath = framework.delibs.debase.deMath;
+
+ /** @typedef {(tcuTexLookupVerifier.LookupPrecision|{tcuTexLookupVerifier.LookupPrecision})} */
+ tcuTexLookupVerifier.PrecType;
+
+ /**
+ * Generic lookup precision parameters
+ * @constructor
+ * @struct
+ * @param {Array<number>=} coordBits
+ * @param {Array<number>=} uvwBits
+ * @param {Array<number>=} colorThreshold
+ * @param {Array<boolean>=} colorMask
+ */
+ tcuTexLookupVerifier.LookupPrecision = function(coordBits, uvwBits, colorThreshold, colorMask) {
+ /** @type {Array<number>} */ this.coordBits = coordBits || [22, 22, 22];
+ /** @type {Array<number>} */ this.uvwBits = uvwBits || [16, 16, 16];
+ /** @type {Array<number>} */ this.colorThreshold = colorThreshold || [0, 0, 0, 0];
+ /** @type {Array<boolean>} */ this.colorMask = colorMask || [true, true, true, true];
+ };
+
+ /**
+ * Lod computation precision parameters
+ * @constructor
+ * @struct
+ * @param {number=} derivateBits
+ * @param {number=} lodBits
+ */
+ tcuTexLookupVerifier.LodPrecision = function(derivateBits, lodBits) {
+ /** @type {number} */ this.derivateBits = derivateBits === undefined ? 22 : derivateBits;
+ /** @type {number} */ this.lodBits = lodBits === undefined ? 16 : lodBits;
+ };
+
+ /**
+ * @enum {number}
+ */
+ tcuTexLookupVerifier.TexLookupScaleMode = {
+ MINIFY: 0,
+ MAGNIFY: 1
+ };
+
+ // Generic utilities
+
+ /**
+ * @param {tcuTexture.Sampler} sampler
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isSamplerSupported = function(sampler) {
+ return sampler.compare == tcuTexture.CompareMode.COMPAREMODE_NONE &&
+ tcuTexVerifierUtil.isWrapModeSupported(sampler.wrapS) &&
+ tcuTexVerifierUtil.isWrapModeSupported(sampler.wrapT) &&
+ tcuTexVerifierUtil.isWrapModeSupported(sampler.wrapR);
+ };
+
+ // Color read & compare utilities
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.coordsInBounds = function(access, x, y, z) {
+ return deMath.deInBounds32(x, 0, access.getWidth()) && deMath.deInBounds32(y, 0, access.getHeight()) && deMath.deInBounds32(z, 0, access.getDepth());
+ };
+
+ /**
+ * @param {tcuTexture.TextureFormat} format
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isSRGB = function(format) {
+ return format.order == tcuTexture.ChannelOrder.sRGB || format.order == tcuTexture.ChannelOrder.sRGBA;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} i
+ * @param {number} j
+ * @param {number} k
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.lookupScalar = function(access, sampler, i, j, k) {
+ if (tcuTexLookupVerifier.coordsInBounds(access, i, j, k))
+ return access.getPixel(i, j, k);
+ else
+ return deMath.toIVec(sampler.borderColor);
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} i
+ * @param {number} j
+ * @param {number} k
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.lookupFloat = function(access, sampler, i, j, k) {
+ // Specialization for float lookups: sRGB conversion is performed as specified in format.
+ if (tcuTexLookupVerifier.coordsInBounds(access, i, j, k)) {
+ /** @type {Array<number>} */ var p = access.getPixel(i, j, k);
+ return tcuTexLookupVerifier.isSRGB(access.getFormat()) ? tcuTextureUtil.sRGBToLinear(p) : p;
+ } else
+ return sampler.borderColor;
+ };
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} ref
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isColorValid = function(prec, ref, result) {
+ return deMath.boolAll(
+ deMath.logicalOrBool(
+ deMath.lessThanEqual(deMath.absDiff(ref, result), prec.colorThreshold),
+ deMath.logicalNotBool(prec.colorMask)));
+ };
+
+ /**
+ * @constructor
+ * @struct
+ * @param {Array<number>=} p00
+ * @param {Array<number>=} p01
+ * @param {Array<number>=} p10
+ * @param {Array<number>=} p11
+ */
+ tcuTexLookupVerifier.ColorQuad = function(p00, p01, p10, p11) {
+ /** @type {Array<number>} */ this.p00 = p00 || null; //!< (0, 0)
+ /** @type {Array<number>} */ this.p01 = p01 || null; //!< (1, 0)
+ /** @type {Array<number>} */ this.p10 = p10 || null; //!< (0, 1)
+ /** @type {Array<number>} */ this.p11 = p11 || null; //!< (1, 1)
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} x0
+ * @param {number} x1
+ * @param {number} y0
+ * @param {number} y1
+ * @param {number} z
+ * @return {tcuTexLookupVerifier.ColorQuad}
+ */
+ tcuTexLookupVerifier.lookupQuad = function(level, sampler, x0, x1, y0, y1, z) {
+ var p00 = tcuTexLookupVerifier.lookupFloat(level, sampler, x0, y0, z);
+ var p10 = tcuTexLookupVerifier.lookupFloat(level, sampler, x1, y0, z);
+ var p01 = tcuTexLookupVerifier.lookupFloat(level, sampler, x0, y1, z);
+ var p11 = tcuTexLookupVerifier.lookupFloat(level, sampler, x1, y1, z);
+ return new tcuTexLookupVerifier.ColorQuad(p00, p01, p10, p11);
+ };
+
+ /**
+ * @constructor
+ * @struct
+ * @param {Array<number>=} p0
+ * @param {Array<number>=} p1
+ */
+ tcuTexLookupVerifier.ColorLine = function(p0, p1) {
+ /** @type {Array<number>} */ this.p0 = p0 || null; //!< 0
+ /** @type {Array<number>} */ this.p1 = p1 || null; //!< 1
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} x0
+ * @param {number} x1
+ * @param {number} y
+ * @return {tcuTexLookupVerifier.ColorLine}
+ */
+ tcuTexLookupVerifier.lookupLine = function(level, sampler, x0, x1, y) {
+ return new tcuTexLookupVerifier.ColorLine(
+ tcuTexLookupVerifier.lookupFloat(level, sampler, x0, y, 0),
+ tcuTexLookupVerifier.lookupFloat(level, sampler, x1, y, 0)
+ );
+ };
+
+ /**
+ * @param {Array<number>} vec
+ * @return {number}
+ */
+ tcuTexLookupVerifier.minComp = function(vec) {
+ /** @type {number} */ var minVal = vec[0];
+ for (var ndx = 1; ndx < vec.length; ndx++)
+ minVal = Math.min(minVal, vec[ndx]);
+ return minVal;
+ };
+
+ /**
+ * @param {Array<number>} vec
+ * @return {number}
+ */
+ tcuTexLookupVerifier.maxComp = function(vec) {
+ /** @type {number} */ var maxVal = vec[0];
+ for (var ndx = 1; ndx < vec.length; ndx++)
+ maxVal = Math.max(maxVal, vec[ndx]);
+ return maxVal;
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexLookupVerifier.ColorLine} line
+ * @return {number}
+ */
+ tcuTexLookupVerifier.computeBilinearSearchStepFromFloatLine = function(prec, line) {
+ assertMsgOptions(deMath.boolAll(deMath.greaterThan(prec.colorThreshold, [0, 0, 0, 0])), 'Threshold not greater than 0.', false, true);
+
+ /** @type {number} */ var maxSteps = 1 << 16;
+ /** @type {Array<number>} */ var d = deMath.absDiff(line.p1, line.p0);
+ /** @type {Array<number>} */ var stepCount = deMath.divide([d, d, d, d], prec.colorThreshold);
+ /** @type {Array<number>} */
+ var minStep = deMath.divide([1, 1, 1, 1], deMath.add(stepCount, [1, 1, 1, 1]));
+ /** @type {number} */ var step = Math.max(tcuTexLookupVerifier.minComp(minStep), 1 / maxSteps);
+
+ return step;
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexLookupVerifier.ColorQuad} quad
+ * @return {number}
+ */
+ tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad = function(prec, quad) {
+ assertMsgOptions(deMath.boolAll(deMath.greaterThan(prec.colorThreshold, [0, 0, 0, 0])), 'Threshold not greater than 0.', false, true);
+
+ /** @type {number} */ var maxSteps = 1 << 16;
+ /** @type {Array<number>} */ var d0 = deMath.absDiff(quad.p10, quad.p00);
+ /** @type {Array<number>} */ var d1 = deMath.absDiff(quad.p01, quad.p00);
+ /** @type {Array<number>} */ var d2 = deMath.absDiff(quad.p11, quad.p10);
+ /** @type {Array<number>} */ var d3 = deMath.absDiff(quad.p11, quad.p01);
+ /** @type {Array<number>} */ var maxD = deMath.max(d0, deMath.max(d1, deMath.max(d2, d3)));
+ /** @type {Array<number>} */ var stepCount = deMath.divide(maxD, prec.colorThreshold);
+ /** @type {Array<number>} */ var minStep = deMath.divide([1, 1, 1, 1], deMath.add(stepCount, [1, 1, 1, 1]));
+ /** @type {number} */ var step = Math.max(tcuTexLookupVerifier.minComp(minStep), 1 / maxSteps);
+
+ return step;
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @return {number}
+ */
+ tcuTexLookupVerifier.computeBilinearSearchStepForUnorm = function(prec) {
+ assertMsgOptions(deMath.boolAll(deMath.greaterThan(prec.colorThreshold, [0, 0, 0, 0])), 'Threshold not greater than 0.', false, true);
+
+ /** @type {Array<number>} */ var stepCount = deMath.divide([1, 1, 1, 1], prec.colorThreshold);
+ /** @type {Array<number>} */ var minStep = deMath.divide([1, 1, 1, 1], (deMath.add(stepCount, [1, 1, 1, 1])));
+ /** @type {number} */ var step = tcuTexLookupVerifier.minComp(minStep);
+
+ return step;
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @return {number}
+ */
+ tcuTexLookupVerifier.computeBilinearSearchStepForSnorm = function(prec) {
+ assertMsgOptions(deMath.boolAll(deMath.greaterThan(prec.colorThreshold, [0, 0, 0, 0])), 'Threshold not greater than 0.', false, true);
+
+ /** @type {Array<number>} */ var stepCount = deMath.divide([2.0, 2.0, 2.0, 2.0], prec.colorThreshold);
+ /** @type {Array<number>} */ var minStep = deMath.divide([1, 1, 1, 1], deMath.add(stepCount, [1, 1, 1, 1]));
+ /** @type {number} */ var step = tcuTexLookupVerifier.minComp(minStep);
+
+ return step;
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.ColorLine} line
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.minLine = function(line) {
+ return deMath.min(line.p0, line.p1);
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.ColorLine} line
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.maxLine = function(line) {
+ var max = deMath.max;
+ return max(line.p0, line.p1);
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.ColorQuad} quad
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.minQuad = function(quad) {
+ var min = deMath.min;
+ return min(quad.p00, min(quad.p10, min(quad.p01, quad.p11)));
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.ColorQuad} quad
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.maxQuad = function(quad) {
+ var max = deMath.max;
+ return max(quad.p00, max(quad.p10, max(quad.p01, quad.p11)));
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexLookupVerifier.ColorQuad} quad
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isInColorBounds_1Quad = function(prec, quad, result) {
+ var quadMin = tcuTexLookupVerifier.minQuad;
+ var quadMax = tcuTexLookupVerifier.maxQuad;
+ /** @type {Array<number>} */ var minVal = deMath.subtract(quadMin(quad), prec.colorThreshold);
+ /** @type {Array<number>} */ var maxVal = deMath.add(quadMax(quad), prec.colorThreshold);
+ return deMath.boolAll(
+ deMath.logicalOrBool(
+ deMath.logicalAndBool(
+ deMath.greaterThanEqual(result, minVal),
+ deMath.lessThanEqual(result, maxVal)),
+ deMath.logicalNotBool(prec.colorMask)));
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexLookupVerifier.ColorQuad} quad0
+ * @param {tcuTexLookupVerifier.ColorQuad} quad1
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isInColorBounds_2Quad = function(prec, quad0, quad1, result) {
+ var min = deMath.min;
+ var max = deMath.max;
+ var quadMin = tcuTexLookupVerifier.minQuad;
+ var quadMax = tcuTexLookupVerifier.maxQuad;
+ /** @type {Array<number>} */ var minVal = deMath.subtract(min(quadMin(quad0), quadMin(quad1)), prec.colorThreshold);
+ /** @type {Array<number>} */ var maxVal = deMath.add(max(quadMax(quad0), quadMax(quad1)), prec.colorThreshold);
+ return deMath.boolAll(
+ deMath.logicalOrBool(
+ deMath.logicalAndBool(
+ deMath.greaterThanEqual(result, minVal),
+ deMath.lessThanEqual(result, maxVal)),
+ deMath.logicalNotBool(prec.colorMask)));
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexLookupVerifier.ColorLine} line0
+ * @param {tcuTexLookupVerifier.ColorLine} line1
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isInColorBounds_2Line = function(prec, line0, line1, result) {
+ var min = deMath.min;
+ var max = deMath.max;
+ var lineMin = tcuTexLookupVerifier.minLine;
+ var lineMax = tcuTexLookupVerifier.maxLine;
+ /** @type {Array<number>} */ var minVal = deMath.subtract(min(lineMin(line0), lineMin(line1)), prec.colorThreshold);
+ /** @type {Array<number>} */ var maxVal = deMath.add(max(lineMax(line0), lineMax(line1)), prec.colorThreshold);
+ return deMath.boolAll(
+ deMath.logicalOrBool(
+ deMath.logicalAndBool(
+ deMath.greaterThanEqual(result, minVal),
+ deMath.lessThanEqual(result, maxVal)),
+ deMath.logicalNotBool(prec.colorMask)));
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexLookupVerifier.ColorQuad} quad00
+ * @param {tcuTexLookupVerifier.ColorQuad} quad01
+ * @param {tcuTexLookupVerifier.ColorQuad} quad10
+ * @param {tcuTexLookupVerifier.ColorQuad} quad11
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isInColorBounds_4Quad = function(prec, quad00, quad01, quad10, quad11, result) {
+ var min = deMath.min;
+ var max = deMath.max;
+ var quadMin = tcuTexLookupVerifier.minQuad;
+ var quadMax = tcuTexLookupVerifier.maxQuad;
+ /** @type {Array<number>} */ var minVal = deMath.subtract(min(quadMin(quad00), min(quadMin(quad01), min(quadMin(quad10), quadMin(quad11)))), prec.colorThreshold);
+ /** @type {Array<number>} */ var maxVal = deMath.add(max(quadMax(quad00), max(quadMax(quad01), max(quadMax(quad10), quadMax(quad11)))), prec.colorThreshold);
+ return deMath.boolAll(
+ deMath.logicalOrBool(
+ deMath.logicalAndBool(
+ deMath.greaterThanEqual(result, minVal),
+ deMath.lessThanEqual(result, maxVal)),
+ deMath.logicalNotBool(prec.colorMask)));
+ };
+
+ // Range search utilities
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} c0
+ * @param {Array<number>} c1
+ * @param {Array<number>} fBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLinearRangeValid = function(prec, c0, c1, fBounds, result) {
+ // This is basically line segment - AABB test. Valid interpolation line is checked
+ // against result AABB constructed by applying threshold.
+
+ /** @type {Array<number>} */ var rMin = deMath.subtract(result, prec.colorThreshold);
+ /** @type {Array<number>} */ var rMax = deMath.add(result, prec.colorThreshold);
+
+ // Algorithm: For each component check whether segment endpoints are inside, or intersect with slab.
+ // If all intersect or are inside, line segment intersects the whole 4D AABB.
+ for (var compNdx = 0; compNdx < 4; compNdx++) {
+ if (!prec.colorMask[compNdx])
+ continue;
+
+ /** @type {number} */ var i0 = c0[compNdx] * (1 - fBounds[0]) + c1[compNdx] * fBounds[0];
+ /** @type {number} */ var i1 = c0[compNdx] * (1 - fBounds[1]) + c1[compNdx] * fBounds[1];
+ if ((i0 > rMax[compNdx] && i1 > rMax[compNdx]) ||
+ (i0 < rMin[compNdx] && i1 < rMin[compNdx])) {
+ return false;
+ }
+ }
+
+ return true;
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexLookupVerifier.ColorQuad} quad
+ * @param {Array<number>} xBounds
+ * @param {Array<number>} yBounds
+ * @param {number} searchStep
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isBilinearRangeValid = function(prec, quad, xBounds, yBounds, searchStep, result) {
+ assertMsgOptions(xBounds[0] <= xBounds[1], 'Out of bounds: X direction.', false, true);
+ assertMsgOptions(yBounds[0] <= yBounds[1], 'Out of bounds: Y direction.', false, true);
+
+ if (!tcuTexLookupVerifier.isInColorBounds_1Quad(prec, quad, result))
+ return false;
+
+ for (var x = xBounds[0]; x < xBounds[1] + searchStep; x += searchStep) {
+ /** @type {number} */ var a = Math.min(x, xBounds[1]);
+ /** @type {Array<number>} */ var c0 = deMath.add(deMath.scale(quad.p00, (1 - a)), deMath.scale(quad.p10, a));
+ /** @type {Array<number>} */ var c1 = deMath.add(deMath.scale(quad.p01, (1 - a)), deMath.scale(quad.p11, a));
+
+ if (tcuTexLookupVerifier.isLinearRangeValid(prec, c0, c1, yBounds, result))
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexLookupVerifier.ColorQuad} quad0
+ * @param {tcuTexLookupVerifier.ColorQuad} quad1
+ * @param {Array<number>} xBounds
+ * @param {Array<number>} yBounds
+ * @param {Array<number>} zBounds
+ * @param {number} searchStep
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isTrilinearRangeValid = function(prec, quad0, quad1, xBounds, yBounds, zBounds, searchStep, result) {
+ assertMsgOptions(xBounds[0] <= xBounds[1], 'Out of bounds: X direction.', false, true);
+ assertMsgOptions(yBounds[0] <= yBounds[1], 'Out of bounds: Y direction.', false, true);
+ assertMsgOptions(zBounds[0] <= zBounds[1], 'Out of bounds: Z direction.', false, true);
+
+ if (!tcuTexLookupVerifier.isInColorBounds_2Quad(prec, quad0, quad1, result))
+ return false;
+
+ for (var x = xBounds[0]; x < xBounds[1] + searchStep; x += searchStep) {
+ for (var y = yBounds[0]; y < yBounds[1] + searchStep; y += searchStep) {
+ /** @type {number} */ var a = Math.min(x, xBounds[1]);
+ /** @type {number} */ var b = Math.min(y, yBounds[1]);
+ /** @type {Array<number>} */
+ var c0 = deMath.add(
+ deMath.add(
+ deMath.add(
+ deMath.scale(quad0.p00, (1 - a) * (1 - b)),
+ deMath.scale(quad0.p10, a * (1 - b))),
+ deMath.scale(quad0.p01, (1 - a) * b)),
+ deMath.scale(quad0.p11, a * b));
+ /** @type {Array<number>} */
+ var c1 = deMath.add(
+ deMath.add(
+ deMath.add(
+ deMath.scale(quad1.p00, (1 - a) * (1 - b)),
+ deMath.scale(quad1.p10, a * (1 - b))),
+ deMath.scale(quad1.p01, (1 - a) * b)),
+ deMath.scale(quad1.p11, a * b));
+
+ if (tcuTexLookupVerifier.isLinearRangeValid(prec, c0, c1, zBounds, result))
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexLookupVerifier.ColorQuad} quad0
+ * @param {tcuTexLookupVerifier.ColorQuad} quad1
+ * @param {Array<number>} xBounds0
+ * @param {Array<number>} yBounds0
+ * @param {Array<number>} xBounds1
+ * @param {Array<number>} yBounds1
+ * @param {Array<number>} zBounds
+ * @param {number} searchStep
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.is2DTrilinearFilterResultValid = function(prec, quad0, quad1, xBounds0, yBounds0, xBounds1, yBounds1, zBounds, searchStep, result) {
+ assertMsgOptions(xBounds0[0] <= xBounds0[1], 'Out of bounds: X direction.', false, true);
+ assertMsgOptions(yBounds0[0] <= yBounds0[1], 'Out of bounds: Y direction.', false, true);
+ assertMsgOptions(xBounds1[0] <= xBounds1[1], 'Out of bounds: X direction.', false, true);
+ assertMsgOptions(yBounds1[0] <= yBounds1[1], 'Out of bounds: Y direction.', false, true);
+
+ if (!tcuTexLookupVerifier.isInColorBounds_2Quad(prec, quad0, quad1, result))
+ return false;
+
+ for (var x0 = xBounds0[0]; x0 < xBounds0[1] + searchStep; x0 += searchStep) {
+ for (var y0 = yBounds0[0]; y0 < yBounds0[1] + searchStep; y0 += searchStep) {
+ /** @type {number} */ var a0 = Math.min(x0, xBounds0[1]);
+ /** @type {number} */ var b0 = Math.min(y0, yBounds0[1]);
+ /** @type {Array<number>} */
+ var c0 = deMath.add(
+ deMath.add(
+ deMath.add(
+ deMath.scale(quad0.p00, (1 - a0) * (1 - b0)),
+ deMath.scale(quad0.p10, a0 * (1 - b0))),
+ deMath.scale(quad0.p01, (1 - a0) * b0)),
+ deMath.scale(quad0.p11, a0 * b0));
+
+ for (var x1 = xBounds1[0]; x1 <= xBounds1[1]; x1 += searchStep) {
+ for (var y1 = yBounds1[0]; y1 <= yBounds1[1]; y1 += searchStep) {
+ /** @type {number} */ var a1 = Math.min(x1, xBounds1[1]);
+ /** @type {number} */ var b1 = Math.min(y1, yBounds1[1]);
+ /** @type {Array<number>} */
+ var c1 = deMath.add(
+ deMath.add(
+ deMath.add(
+ deMath.scale(quad1.p00, (1 - a1) * (1 - b1)),
+ deMath.scale(quad1.p10, a1 * (1 - b1))),
+ deMath.scale(quad1.p01, (1 - a1) * b1)),
+ deMath.scale(quad1.p11, a1 * b1));
+
+ if (tcuTexLookupVerifier.isLinearRangeValid(prec, c0, c1, zBounds, result))
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexLookupVerifier.ColorQuad} quad00
+ * @param {tcuTexLookupVerifier.ColorQuad} quad01
+ * @param {tcuTexLookupVerifier.ColorQuad} quad10
+ * @param {tcuTexLookupVerifier.ColorQuad} quad11
+ * @param {Array<number>} xBounds0
+ * @param {Array<number>} yBounds0
+ * @param {Array<number>} zBounds0
+ * @param {Array<number>} xBounds1
+ * @param {Array<number>} yBounds1
+ * @param {Array<number>} zBounds1
+ * @param {Array<number>} wBounds
+ * @param {number} searchStep
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.is3DTrilinearFilterResultValid = function(prec, quad00, quad01, quad10, quad11, xBounds0, yBounds0, zBounds0, xBounds1, yBounds1, zBounds1, wBounds, searchStep, result) {
+ assertMsgOptions(xBounds0[0] <= xBounds0[1], 'Out of bounds: X direction.', false, true);
+ assertMsgOptions(yBounds0[0] <= yBounds0[1], 'Out of bounds: Y direction.', false, true);
+ assertMsgOptions(zBounds0[0] <= zBounds0[1], 'Out of bounds: Z direction.', false, true);
+ assertMsgOptions(xBounds1[0] <= xBounds1[1], 'Out of bounds: X direction.', false, true);
+ assertMsgOptions(yBounds1[0] <= yBounds1[1], 'Out of bounds: Y direction.', false, true);
+ assertMsgOptions(zBounds1[0] <= zBounds1[1], 'Out of bounds: Z direction.', false, true);
+
+ if (!tcuTexLookupVerifier.isInColorBounds_4Quad(prec, quad00, quad01, quad10, quad11, result))
+ return false;
+
+ function biInterp(result, p00, p01, p10, p11, s00, s01, s10, s11) {
+ for (var ii = 0; ii < 4; ++ii) {
+ result[ii] = p00[ii] * s00 + p10[ii] * s10 + p01[ii] * s01 + p11[ii] * s11;
+ }
+ }
+
+ function interp(result, p0, p1, s) {
+ for (var ii = 0; ii < 4; ++ii) {
+ result[ii] = p0[ii] * (1 - s) + p1[ii] * s;
+ }
+ }
+
+ /** @type {Array<number>} */ var c00 = [0, 0, 0, 0];
+ /** @type {Array<number>} */ var c01 = [0, 0, 0, 0];
+ /** @type {Array<number>} */ var c10 = [0, 0, 0, 0];
+ /** @type {Array<number>} */ var c11 = [0, 0, 0, 0];
+ /** @type {Array<number>} */ var cz0 = [0, 0, 0, 0];
+ /** @type {Array<number>} */ var cz1 = [0, 0, 0, 0];
+
+ for (var x0 = xBounds0[0]; x0 < xBounds0[1] + searchStep; x0 += searchStep) {
+ for (var y0 = yBounds0[0]; y0 < yBounds0[1] + searchStep; y0 += searchStep) {
+ /** @type {number} */ var a0 = Math.min(x0, xBounds0[1]);
+ /** @type {number} */ var b0 = Math.min(y0, yBounds0[1]);
+
+ /** @type {number} */ var s00 = (1 - a0) * (1 - b0);
+ /** @type {number} */ var s01 = (1 - a0) * b0;
+ /** @type {number} */ var s10 = a0 * (1 - b0);
+ /** @type {number} */ var s11 = a0 * b0;
+
+ biInterp(c00, quad00.p00, quad00.p01, quad00.p10, quad00.p11, s00, s01, s10, s11);
+ biInterp(c01, quad01.p00, quad01.p01, quad01.p10, quad01.p11, s00, s01, s10, s11);
+
+ for (var z0 = zBounds0[0]; z0 < zBounds0[1] + searchStep; z0 += searchStep) {
+ /** @type {number} */ var c0 = Math.min(z0, zBounds0[1]);
+ interp(cz0, c00, c01, c0);
+
+ for (var x1 = xBounds1[0]; x1 < xBounds1[1] + searchStep; x1 += searchStep) {
+ for (var y1 = yBounds1[0]; y1 < yBounds1[1] + searchStep; y1 += searchStep) {
+ /** @type {number} */ var a1 = Math.min(x1, xBounds1[1]);
+ /** @type {number} */ var b1 = Math.min(y1, yBounds1[1]);
+
+ /** @type {number} */ var t00 = (1 - a1) * (1 - b1);
+ /** @type {number} */ var t01 = (1 - a1) * b1;
+ /** @type {number} */ var t10 = a1 * (1 - b1);
+ /** @type {number} */ var t11 = a1 * b1;
+
+ biInterp(c10, quad10.p00, quad10.p01, quad10.p10, quad10.p11, t00, t01, t10, t11);
+ biInterp(c11, quad11.p00, quad11.p01, quad11.p10, quad11.p11, t00, t01, t10, t11);
+
+ for (var z1 = zBounds1[0]; z1 < zBounds1[1] + searchStep; z1 += searchStep) {
+ /** @type {number} */ var c1 = Math.min(z1, zBounds1[1]);
+ interp(cz1, c10, c11, c1);
+
+ if (tcuTexLookupVerifier.isLinearRangeValid(prec, cz0, cz1, wBounds, result))
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {number} coordX
+ * @param {number} coordY
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isNearestSampleResultValid_CoordXYAsNumber = function(level, sampler, prec, coordX, coordY, result) {
+ assertMsgOptions(level.getDepth() == 1, 'Depth must be 1.', false, true);
+
+ /** @type {Array<number>} */
+ var uBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, level.getWidth(), coordX, prec.coordBits[0], prec.uvwBits[0]);
+
+ /** @type {number} */ var minI = Math.floor(uBounds[0]);
+ /** @type {number} */ var maxI = Math.floor(uBounds[1]);
+
+ for (var i = minI; i <= maxI; i++) {
+ /** @type {number} */ var x = tcuTexVerifierUtil.wrap(sampler.wrapS, i, level.getWidth());
+ /** @type {Array<number>} */ var color;
+ if (tcuTexLookupVerifier.isSRGB(level.getFormat())) {
+ color = tcuTexLookupVerifier.lookupFloat(level, sampler, x, coordY, 0);
+ } else {
+ color = tcuTexLookupVerifier.lookupScalar(level, sampler, x, coordY, 0);
+ }
+
+ if (tcuTexLookupVerifier.isColorValid(prec, color, result))
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord vec2
+ * @param {number} coordZ int
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isNearestSampleResultValid_CoordAsVec2AndInt = function(level, sampler, prec, coord, coordZ, result) {
+ /** @type {Array<number>} */
+ var uBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, level.getWidth(), coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */
+ var vBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, level.getHeight(), coord[1], prec.coordBits[1], prec.uvwBits[1]);
+
+ // Integer coordinates - without wrap mode
+ /** @type {number} */ var minI = Math.floor(uBounds[0]);
+ /** @type {number} */ var maxI = Math.floor(uBounds[1]);
+ /** @type {number} */ var minJ = Math.floor(vBounds[0]);
+ /** @type {number} */ var maxJ = Math.floor(vBounds[1]);
+
+ // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
+
+ for (var j = minJ; j <= maxJ; j++)
+ for (var i = minI; i <= maxI; i++) {
+ /** @type {number} */ var x = tcuTexVerifierUtil.wrap(sampler.wrapS, i, level.getWidth());
+ /** @type {number} */ var y = tcuTexVerifierUtil.wrap(sampler.wrapT, j, level.getHeight());
+ /** @type {Array<number>} */ var color;
+ if (tcuTexLookupVerifier.isSRGB(level.getFormat())) {
+ color = tcuTexLookupVerifier.lookupFloat(level, sampler, x, y, coordZ);
+ } else {
+ color = tcuTexLookupVerifier.lookupScalar(level, sampler, x, y, coordZ);
+ }
+
+ if (tcuTexLookupVerifier.isColorValid(prec, color, result))
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord vec3
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isNearestSampleResultValid_CoordAsVec3 = function(level, sampler, prec, coord, result) {
+ /** @type {Array<number>} */
+ var uBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, level.getWidth(), coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */
+ var vBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, level.getHeight(), coord[1], prec.coordBits[1], prec.uvwBits[1]);
+ /** @type {Array<number>} */
+ var wBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, level.getDepth(), coord[2], prec.coordBits[2], prec.uvwBits[2]);
+
+ // Integer coordinates - without wrap mode
+ /** @type {number} */ var minI = Math.floor(uBounds[0]);
+ /** @type {number} */ var maxI = Math.floor(uBounds[1]);
+ /** @type {number} */ var minJ = Math.floor(vBounds[0]);
+ /** @type {number} */ var maxJ = Math.floor(vBounds[1]);
+ /** @type {number} */ var minK = Math.floor(wBounds[0]);
+ /** @type {number} */ var maxK = Math.floor(wBounds[1]);
+
+ // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
+
+ for (var k = minK; k <= maxK; k++) {
+ for (var j = minJ; j <= maxJ; j++) {
+ for (var i = minI; i <= maxI; i++) {
+ /** @type {number} */ var x = tcuTexVerifierUtil.wrap(sampler.wrapS, i, level.getWidth());
+ /** @type {number} */ var y = tcuTexVerifierUtil.wrap(sampler.wrapT, j, level.getHeight());
+ /** @type {number} */ var z = tcuTexVerifierUtil.wrap(sampler.wrapR, k, level.getDepth());
+ /** @type {Array<number>} */ var color;
+ if (tcuTexLookupVerifier.isSRGB(level.getFormat())) {
+ color = tcuTexLookupVerifier.lookupFloat(level, sampler, x, y, z);
+ } else {
+ color = tcuTexLookupVerifier.lookupScalar(level, sampler, x, y, z);
+ }
+
+ if (tcuTexLookupVerifier.isColorValid(prec, color, result))
+ return true;
+ }
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {number} coordX
+ * @param {number} coordY
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLinearSampleResultValid_CoordXYAsNumber = function(level, sampler, prec, coordX, coordY, result) {
+ /** @type {Array<number>} */ var uBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coordX, prec.coordBits[0], prec.uvwBits[0]);
+
+ /** @type {number} */ var minI = Math.floor(uBounds[0] - 0.5);
+ /** @type {number} */ var maxI = Math.floor(uBounds[1] - 0.5);
+
+ /** @type {number} */ var w = level.getWidth();
+
+ for (var i = minI; i <= maxI; i++) {
+ // Wrapped coordinates
+ /** @type {number} */ var x0 = tcuTexVerifierUtil.wrap(sampler.wrapS, i, w);
+ /** @type {number} */ var x1 = tcuTexVerifierUtil.wrap(sampler.wrapS, i + 1, w);
+
+ // Bounds for filtering factors
+ /** @type {number} */ var minA = deMath.clamp((uBounds[0] - 0.5) - i, 0, 1);
+ /** @type {number} */ var maxA = deMath.clamp((uBounds[1] - 0.5) - i, 0, 1);
+
+ /** @type {Array<number>} */ var colorA = tcuTexLookupVerifier.lookupFloat(level, sampler, x0, coordY, 0);
+ /** @type {Array<number>} */ var colorB = tcuTexLookupVerifier.lookupFloat(level, sampler, x1, coordY, 0);
+
+ if (tcuTexLookupVerifier.isLinearRangeValid(prec, colorA, colorB, [minA, maxA], result))
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord vec2
+ * @param {number} coordZ int
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLinearSampleResultValid_CoordAsVec2AndInt = function(level, sampler, prec, coord, coordZ, result) {
+ /** @type {Array<number>} */ var uBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getWidth(), coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */ var vBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, level.getHeight(), coord[1], prec.coordBits[1], prec.uvwBits[1]);
+
+ // Integer coordinate bounds for (x0,y0) - without wrap mode
+ /** @type {number} */ var minI = Math.floor(uBounds[0] - 0.5);
+ /** @type {number} */ var maxI = Math.floor(uBounds[1] - 0.5);
+ /** @type {number} */ var minJ = Math.floor(vBounds[0] - 0.5);
+ /** @type {number} */ var maxJ = Math.floor(vBounds[1] - 0.5);
+
+ /** @type {number} */ var w = level.getWidth();
+ /** @type {number} */ var h = level.getHeight();
+
+ /** @type {tcuTexture.TextureChannelClass} */
+ var texClass = tcuTexture.getTextureChannelClass(level.getFormat().type);
+
+ /** @type {number} */
+ var searchStep = (texClass == tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT) ? tcuTexLookupVerifier.computeBilinearSearchStepForUnorm(prec) :
+ (texClass == tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT) ? tcuTexLookupVerifier.computeBilinearSearchStepForSnorm(prec) :
+ 0; // Step is computed for floating-point quads based on texel values.
+
+ // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
+
+ for (var j = minJ; j <= maxJ; j++)
+ for (var i = minI; i <= maxI; i++) {
+ // Wrapped coordinates
+ /** @type {number} */ var x0 = tcuTexVerifierUtil.wrap(sampler.wrapS, i, w);
+ /** @type {number} */ var x1 = tcuTexVerifierUtil.wrap(sampler.wrapS, i + 1, w);
+ /** @type {number} */ var y0 = tcuTexVerifierUtil.wrap(sampler.wrapT, j, h);
+ /** @type {number} */ var y1 = tcuTexVerifierUtil.wrap(sampler.wrapT, j + 1, h);
+
+ // Bounds for filtering factors
+ /** @type {number} */ var minA = deMath.clamp((uBounds[0] - 0.5) - i, 0, 1);
+ /** @type {number} */ var maxA = deMath.clamp((uBounds[1] - 0.5) - i, 0, 1);
+ /** @type {number} */ var minB = deMath.clamp((vBounds[0] - 0.5) - j, 0, 1);
+ /** @type {number} */ var maxB = deMath.clamp((vBounds[1] - 0.5) - j, 0, 1);
+
+ /** @type {tcuTexLookupVerifier.ColorQuad} */
+ var quad = tcuTexLookupVerifier.lookupQuad(level, sampler, x0, x1, y0, y1, coordZ);
+
+ if (texClass == tcuTexture.TextureChannelClass.FLOATING_POINT)
+ searchStep = tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad(prec, quad);
+
+ if (tcuTexLookupVerifier.isBilinearRangeValid(prec, quad, [minA, maxA], [minB, maxB], searchStep, result))
+ return true;
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord vec3
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLinearSampleResultValid_CoordAsVec3 = function(level, sampler, prec, coord, result) {
+ /** @type {Array<number>} */
+ var uBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, level.getWidth(), coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */
+ var vBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, level.getHeight(), coord[1], prec.coordBits[1], prec.uvwBits[1]);
+ /** @type {Array<number>} */
+ var wBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, level.getDepth(), coord[2], prec.coordBits[2], prec.uvwBits[2]);
+
+ // Integer coordinate bounds for (x0,y0) - without wrap mode
+ /** @type {number} */ var minI = Math.floor(uBounds[0] - 0.5);
+ /** @type {number} */ var maxI = Math.floor(uBounds[1] - 0.5);
+ /** @type {number} */ var minJ = Math.floor(vBounds[0] - 0.5);
+ /** @type {number} */ var maxJ = Math.floor(vBounds[1] - 0.5);
+ /** @type {number} */ var minK = Math.floor(wBounds[0] - 0.5);
+ /** @type {number} */ var maxK = Math.floor(wBounds[1] - 0.5);
+
+ /** @type {number} */ var w = level.getWidth();
+ /** @type {number} */ var h = level.getHeight();
+ /** @type {number} */ var d = level.getDepth();
+
+ /** @type {tcuTexture.TextureChannelClass} */
+ var texClass = tcuTexture.getTextureChannelClass(level.getFormat().type);
+ /** @type {number} */
+ var searchStep = (texClass == tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT) ? tcuTexLookupVerifier.computeBilinearSearchStepForUnorm(prec) :
+ (texClass == tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT) ? tcuTexLookupVerifier.computeBilinearSearchStepForSnorm(prec) :
+ 0; // Step is computed for floating-point quads based on texel values.
+
+ // \todo [2013-07-03 pyry] This could be optimized by first computing ranges based on wrap mode.
+
+ for (var k = minK; k <= maxK; k++) {
+ for (var j = minJ; j <= maxJ; j++) {
+ for (var i = minI; i <= maxI; i++) {
+ // Wrapped coordinates
+ /** @type {number} */ var x0 = tcuTexVerifierUtil.wrap(sampler.wrapS, i, w);
+ /** @type {number} */ var x1 = tcuTexVerifierUtil.wrap(sampler.wrapS, i + 1, w);
+ /** @type {number} */ var y0 = tcuTexVerifierUtil.wrap(sampler.wrapT, j, h);
+ /** @type {number} */ var y1 = tcuTexVerifierUtil.wrap(sampler.wrapT, j + 1, h);
+ /** @type {number} */ var z0 = tcuTexVerifierUtil.wrap(sampler.wrapR, k, d);
+ /** @type {number} */ var z1 = tcuTexVerifierUtil.wrap(sampler.wrapR, k + 1, d);
+
+ // Bounds for filtering factors
+ /** @type {number} */ var minA = deMath.clamp((uBounds[0] - 0.5) - i, 0, 1);
+ /** @type {number} */ var maxA = deMath.clamp((uBounds[1] - 0.5) - i, 0, 1);
+ /** @type {number} */ var minB = deMath.clamp((vBounds[0] - 0.5) - j, 0, 1);
+ /** @type {number} */ var maxB = deMath.clamp((vBounds[1] - 0.5) - j, 0, 1);
+ /** @type {number} */ var minC = deMath.clamp((wBounds[0] - 0.5) - k, 0, 1);
+ /** @type {number} */ var maxC = deMath.clamp((wBounds[1] - 0.5) - k, 0, 1);
+
+ /** @type {tcuTexLookupVerifier.ColorQuad} */
+ var quad0 = tcuTexLookupVerifier.lookupQuad(level, sampler, x0, x1, y0, y1, z0);
+ /** @type {tcuTexLookupVerifier.ColorQuad} */
+ var quad1 = tcuTexLookupVerifier.lookupQuad(level, sampler, x0, x1, y0, y1, z1);
+
+ if (texClass == tcuTexture.TextureChannelClass.FLOATING_POINT)
+ searchStep = Math.min(tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad(prec, quad0), tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad(prec, quad1));
+
+ if (tcuTexLookupVerifier.isTrilinearRangeValid(prec, quad0, quad1, [minA, maxA], [minB, maxB], [minC, maxC], searchStep, result))
+ return true;
+ }
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level0
+ * @param {tcuTexture.ConstPixelBufferAccess} level1
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {number} coord
+ * @param {number} coordY
+ * @param {Array<number>} fBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isNearestMipmapLinearSampleResultValid_CoordXYAsNumber = function(level0, level1, sampler, prec, coord, coordY, fBounds, result) {
+ /** @type {number} */ var w0 = level0.getWidth();
+ /** @type {number} */ var w1 = level1.getWidth();
+
+ /** @type {Array<number>} */
+ var uBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, w0, coord, prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */
+ var uBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, w1, coord, prec.coordBits[0], prec.uvwBits[0]);
+
+ // Integer coordinates - without wrap mode
+ /** @type {number} */ var minI0 = Math.floor(uBounds0[0]);
+ /** @type {number} */ var maxI0 = Math.floor(uBounds0[1]);
+ /** @type {number} */ var minI1 = Math.floor(uBounds1[0]);
+ /** @type {number} */ var maxI1 = Math.floor(uBounds1[1]);
+
+ for (var i0 = minI0; i0 <= maxI0; i0++) {
+ for (var i1 = minI1; i1 <= maxI1; i1++) {
+ /** @type {Array<number>} */
+ var c0 = tcuTexLookupVerifier.lookupFloat(level0, sampler, tcuTexVerifierUtil.wrap(sampler.wrapS, i0, w0), coordY, 0);
+ /** @type {Array<number>} */
+ var c1 = tcuTexLookupVerifier.lookupFloat(level1, sampler, tcuTexVerifierUtil.wrap(sampler.wrapS, i1, w1), coordY, 0);
+
+ if (tcuTexLookupVerifier.isLinearRangeValid(prec, c0, c1, fBounds, result))
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level0
+ * @param {tcuTexture.ConstPixelBufferAccess} level1
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {number} coordZ
+ * @param {Array<number>} fBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isNearestMipmapLinearSampleResultValid_CoordAsVec2AndInt = function(level0, level1, sampler, prec, coord, coordZ, fBounds, result) {
+ /** @type {number} */ var w0 = level0.getWidth();
+ /** @type {number} */ var w1 = level1.getWidth();
+ /** @type {number} */ var h0 = level0.getHeight();
+ /** @type {number} */ var h1 = level1.getHeight();
+
+ /** @type {Array<number>} */
+ var uBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, w0, coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */
+ var uBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, w1, coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */
+ var vBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, h0, coord[1], prec.coordBits[1], prec.uvwBits[1]);
+ /** @type {Array<number>} */
+ var vBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, h1, coord[1], prec.coordBits[1], prec.uvwBits[1]);
+
+ // Integer coordinates - without wrap mode
+ /** @type {number} */ var minI0 = Math.floor(uBounds0[0]);
+ /** @type {number} */ var maxI0 = Math.floor(uBounds0[1]);
+ /** @type {number} */ var minI1 = Math.floor(uBounds1[0]);
+ /** @type {number} */ var maxI1 = Math.floor(uBounds1[1]);
+ /** @type {number} */ var minJ0 = Math.floor(vBounds0[0]);
+ /** @type {number} */ var maxJ0 = Math.floor(vBounds0[1]);
+ /** @type {number} */ var minJ1 = Math.floor(vBounds1[0]);
+ /** @type {number} */ var maxJ1 = Math.floor(vBounds1[1]);
+
+ for (var j0 = minJ0; j0 <= maxJ0; j0++) {
+ for (var i0 = minI0; i0 <= maxI0; i0++) {
+ for (var j1 = minJ1; j1 <= maxJ1; j1++) {
+ for (var i1 = minI1; i1 <= maxI1; i1++) {
+ /** @type {Array<number>} */ var c0 = tcuTexLookupVerifier.lookupFloat(level0, sampler, tcuTexVerifierUtil.wrap(sampler.wrapS, i0, w0), tcuTexVerifierUtil.wrap(sampler.wrapT, j0, h0), coordZ);
+ /** @type {Array<number>} */ var c1 = tcuTexLookupVerifier.lookupFloat(level1, sampler, tcuTexVerifierUtil.wrap(sampler.wrapS, i1, w1), tcuTexVerifierUtil.wrap(sampler.wrapT, j1, h1), coordZ);
+
+ if (tcuTexLookupVerifier.isLinearRangeValid(prec, c0, c1, fBounds, result))
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level0
+ * @param {tcuTexture.ConstPixelBufferAccess} level1
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {Array<number>} fBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isNearestMipmapLinearSampleResultValid_CoordAsVec3 = function(level0, level1, sampler, prec, coord, fBounds, result) {
+ /** @type {number} */ var w0 = level0.getWidth();
+ /** @type {number} */ var w1 = level1.getWidth();
+ /** @type {number} */ var h0 = level0.getHeight();
+ /** @type {number} */ var h1 = level1.getHeight();
+ /** @type {number} */ var d0 = level0.getDepth();
+ /** @type {number} */ var d1 = level1.getDepth();
+
+ /** @type {Array<number>} */
+ var uBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, w0, coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */
+ var uBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, w1, coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */
+ var vBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, h0, coord[1], prec.coordBits[1], prec.uvwBits[1]);
+ /** @type {Array<number>} */
+ var vBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, h1, coord[1], prec.coordBits[1], prec.uvwBits[1]);
+ /** @type {Array<number>} */
+ var wBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, d0, coord[2], prec.coordBits[2], prec.uvwBits[2]);
+ /** @type {Array<number>} */
+ var wBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, d1, coord[2], prec.coordBits[2], prec.uvwBits[2]);
+
+ // Integer coordinates - without wrap mode
+ /** @type {number} */ var minI0 = Math.floor(uBounds0[0]);
+ /** @type {number} */ var maxI0 = Math.floor(uBounds0[1]);
+ /** @type {number} */ var minI1 = Math.floor(uBounds1[0]);
+ /** @type {number} */ var maxI1 = Math.floor(uBounds1[1]);
+ /** @type {number} */ var minJ0 = Math.floor(vBounds0[0]);
+ /** @type {number} */ var maxJ0 = Math.floor(vBounds0[1]);
+ /** @type {number} */ var minJ1 = Math.floor(vBounds1[0]);
+ /** @type {number} */ var maxJ1 = Math.floor(vBounds1[1]);
+ /** @type {number} */ var minK0 = Math.floor(wBounds0[0]);
+ /** @type {number} */ var maxK0 = Math.floor(wBounds0[1]);
+ /** @type {number} */ var minK1 = Math.floor(wBounds1[0]);
+ /** @type {number} */ var maxK1 = Math.floor(wBounds1[1]);
+
+ for (var k0 = minK0; k0 <= maxK0; k0++) {
+ for (var j0 = minJ0; j0 <= maxJ0; j0++) {
+ for (var i0 = minI0; i0 <= maxI0; i0++) {
+ for (var k1 = minK1; k1 <= maxK1; k1++) {
+ for (var j1 = minJ1; j1 <= maxJ1; j1++) {
+ for (var i1 = minI1; i1 <= maxI1; i1++) {
+ /** @type {Array<number>} */ var c0 = tcuTexLookupVerifier.lookupFloat(level0, sampler, tcuTexVerifierUtil.wrap(sampler.wrapS, i0, w0), tcuTexVerifierUtil.wrap(sampler.wrapT, j0, h0), tcuTexVerifierUtil.wrap(sampler.wrapR, k0, d0));
+ /** @type {Array<number>} */ var c1 = tcuTexLookupVerifier.lookupFloat(level1, sampler, tcuTexVerifierUtil.wrap(sampler.wrapS, i1, w1), tcuTexVerifierUtil.wrap(sampler.wrapT, j1, h1), tcuTexVerifierUtil.wrap(sampler.wrapR, k1, d1));
+
+ if (tcuTexLookupVerifier.isLinearRangeValid(prec, c0, c1, fBounds, result))
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level0
+ * @param {tcuTexture.ConstPixelBufferAccess} level1
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {number} coordZ
+ * @param {Array<number>} fBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLinearMipmapLinearSampleResultValid_CoordAsVec2AndInt = function(level0, level1, sampler, prec, coord, coordZ, fBounds, result) {
+ // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
+ // Right now this allows pairing any two valid bilinear quads.
+
+ /** @type {number} */ var w0 = level0.getWidth();
+ /** @type {number} */ var w1 = level1.getWidth();
+ /** @type {number} */ var h0 = level0.getHeight();
+ /** @type {number} */ var h1 = level1.getHeight();
+
+ /** @type {Array<number>} */
+ var uBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, w0, coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */
+ var uBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, w1, coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */
+ var vBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, h0, coord[1], prec.coordBits[1], prec.uvwBits[1]);
+ /** @type {Array<number>} */
+ var vBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, h1, coord[1], prec.coordBits[1], prec.uvwBits[1]);
+
+ // Integer coordinates - without wrap mode
+ /** @type {number} */ var minI0 = Math.floor(uBounds0[0] - 0.5);
+ /** @type {number} */ var maxI0 = Math.floor(uBounds0[1] - 0.5);
+ /** @type {number} */ var minI1 = Math.floor(uBounds1[0] - 0.5);
+ /** @type {number} */ var maxI1 = Math.floor(uBounds1[1] - 0.5);
+ /** @type {number} */ var minJ0 = Math.floor(vBounds0[0] - 0.5);
+ /** @type {number} */ var maxJ0 = Math.floor(vBounds0[1] - 0.5);
+ /** @type {number} */ var minJ1 = Math.floor(vBounds1[0] - 0.5);
+ /** @type {number} */ var maxJ1 = Math.floor(vBounds1[1] - 0.5);
+
+ /** @type {tcuTexture.TextureChannelClass} */
+ var texClass = tcuTexture.getTextureChannelClass(level0.getFormat().type);
+ /** @type {number} */ var cSearchStep = (texClass == tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT) ? tcuTexLookupVerifier.computeBilinearSearchStepForUnorm(prec) :
+ (texClass == tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT) ? tcuTexLookupVerifier.computeBilinearSearchStepForSnorm(prec) :
+ 0; // Step is computed for floating-point quads based on texel values.
+
+ /** @type {number} */ var x0;
+ /** @type {number} */ var x1;
+ /** @type {number} */ var y0;
+ /** @type {number} */ var y1;
+
+ for (var j0 = minJ0; j0 <= maxJ0; j0++) {
+ for (var i0 = minI0; i0 <= maxI0; i0++) {
+ /** @type {number} */ var searchStep0;
+
+ x0 = tcuTexVerifierUtil.wrap(sampler.wrapS, i0, w0);
+ x1 = tcuTexVerifierUtil.wrap(sampler.wrapS, i0 + 1, w0);
+ y0 = tcuTexVerifierUtil.wrap(sampler.wrapT, j0, h0);
+ y1 = tcuTexVerifierUtil.wrap(sampler.wrapT, j0 + 1, h0);
+
+ /** @type {tcuTexLookupVerifier.ColorQuad} */
+ var quad0 = tcuTexLookupVerifier.lookupQuad(level0, sampler, x0, x1, y0, y1, coordZ);
+
+ if (texClass == tcuTexture.TextureChannelClass.FLOATING_POINT)
+ searchStep0 = tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad(prec, quad0);
+ else
+ searchStep0 = cSearchStep;
+
+ /** @type {number} */ var minA0 = deMath.clamp((uBounds0[0] - 0.5) - i0, 0, 1);
+ /** @type {number} */ var maxA0 = deMath.clamp((uBounds0[1] - 0.5) - i0, 0, 1);
+ /** @type {number} */ var minB0 = deMath.clamp((vBounds0[0] - 0.5) - j0, 0, 1);
+ /** @type {number} */ var maxB0 = deMath.clamp((vBounds0[1] - 0.5) - j0, 0, 1);
+
+ for (var j1 = minJ1; j1 <= maxJ1; j1++) {
+ for (var i1 = minI1; i1 <= maxI1; i1++) {
+ /** @type {number} */ var searchStep1;
+
+ x0 = tcuTexVerifierUtil.wrap(sampler.wrapS, i1, w1);
+ x1 = tcuTexVerifierUtil.wrap(sampler.wrapS, i1 + 1, w1);
+ y0 = tcuTexVerifierUtil.wrap(sampler.wrapT, j1, h1);
+ y1 = tcuTexVerifierUtil.wrap(sampler.wrapT, j1 + 1, h1);
+
+ /** @type {tcuTexLookupVerifier.ColorQuad} */
+ var quad1 = tcuTexLookupVerifier.lookupQuad(level1, sampler, x0, x1, y0, y1, coordZ);
+
+ if (texClass == tcuTexture.TextureChannelClass.FLOATING_POINT)
+ searchStep1 = tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad(prec, quad1);
+ else
+ searchStep1 = cSearchStep;
+
+ /** @type {number} */ var minA1 = deMath.clamp((uBounds1[0] - 0.5) - i1, 0, 1);
+ /** @type {number} */ var maxA1 = deMath.clamp((uBounds1[1] - 0.5) - i1, 0, 1);
+ /** @type {number} */ var minB1 = deMath.clamp((vBounds1[0] - 0.5) - j1, 0, 1);
+ /** @type {number} */ var maxB1 = deMath.clamp((vBounds1[1] - 0.5) - j1, 0, 1);
+
+ if (tcuTexLookupVerifier.is2DTrilinearFilterResultValid(prec, quad0, quad1, [minA0, maxA0], [minB0, maxB0], [minA1, maxA1], [minB1, maxB1],
+ fBounds, Math.min(searchStep0, searchStep1), result))
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level0
+ * @param {tcuTexture.ConstPixelBufferAccess} level1
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {Array<number>} fBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLinearMipmapLinearSampleResultValid_CoordAsVec3 = function(level0, level1, sampler, prec, coord, fBounds, result) {
+ // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
+ // Right now this allows pairing any two valid bilinear quads.
+
+ /** @type {number} */ var w0 = level0.getWidth();
+ /** @type {number} */ var w1 = level1.getWidth();
+ /** @type {number} */ var h0 = level0.getHeight();
+ /** @type {number} */ var h1 = level1.getHeight();
+ /** @type {number} */ var d0 = level0.getDepth();
+ /** @type {number} */ var d1 = level1.getDepth();
+
+ /** @type {Array<number>} */
+ var uBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, w0, coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */
+ var uBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, w1, coord[0], prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */
+ var vBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, h0, coord[1], prec.coordBits[1], prec.uvwBits[1]);
+ /** @type {Array<number>} */
+ var vBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, h1, coord[1], prec.coordBits[1], prec.uvwBits[1]);
+ /** @type {Array<number>} */
+ var wBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, d0, coord[2], prec.coordBits[2], prec.uvwBits[2]);
+ /** @type {Array<number>} */
+ var wBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(
+ sampler.normalizedCoords, d1, coord[2], prec.coordBits[2], prec.uvwBits[2]);
+
+ // Integer coordinates - without wrap mode
+ /** @type {number} */ var minI0 = Math.floor(uBounds0[0] - 0.5);
+ /** @type {number} */ var maxI0 = Math.floor(uBounds0[1] - 0.5);
+ /** @type {number} */ var minI1 = Math.floor(uBounds1[0] - 0.5);
+ /** @type {number} */ var maxI1 = Math.floor(uBounds1[1] - 0.5);
+ /** @type {number} */ var minJ0 = Math.floor(vBounds0[0] - 0.5);
+ /** @type {number} */ var maxJ0 = Math.floor(vBounds0[1] - 0.5);
+ /** @type {number} */ var minJ1 = Math.floor(vBounds1[0] - 0.5);
+ /** @type {number} */ var maxJ1 = Math.floor(vBounds1[1] - 0.5);
+ /** @type {number} */ var minK0 = Math.floor(wBounds0[0] - 0.5);
+ /** @type {number} */ var maxK0 = Math.floor(wBounds0[1] - 0.5);
+ /** @type {number} */ var minK1 = Math.floor(wBounds1[0] - 0.5);
+ /** @type {number} */ var maxK1 = Math.floor(wBounds1[1] - 0.5);
+
+ /** @type {tcuTexture.TextureChannelClass} */
+ var texClass = tcuTexture.getTextureChannelClass(level0.getFormat().type);
+ /** @type {number} */ var cSearchStep = texClass == tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT ? tcuTexLookupVerifier.computeBilinearSearchStepForUnorm(prec) :
+ texClass == tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT ? tcuTexLookupVerifier.computeBilinearSearchStepForSnorm(prec) :
+ 0; // Step is computed for floating-point quads based on texel values.
+
+ /** @type {number} */ var x0;
+ /** @type {number} */ var x1;
+ /** @type {number} */ var y0;
+ /** @type {number} */ var y1;
+ /** @type {number} */ var z0;
+ /** @type {number} */ var z1;
+
+ for (var k0 = minK0; k0 <= maxK0; k0++) {
+ for (var j0 = minJ0; j0 <= maxJ0; j0++) {
+ for (var i0 = minI0; i0 <= maxI0; i0++) {
+ /** @type {number} */ var searchStep0;
+
+ x0 = tcuTexVerifierUtil.wrap(sampler.wrapS, i0, w0);
+ x1 = tcuTexVerifierUtil.wrap(sampler.wrapS, i0 + 1, w0);
+ y0 = tcuTexVerifierUtil.wrap(sampler.wrapT, j0, h0);
+ y1 = tcuTexVerifierUtil.wrap(sampler.wrapT, j0 + 1, h0);
+ z0 = tcuTexVerifierUtil.wrap(sampler.wrapR, k0, d0);
+ z1 = tcuTexVerifierUtil.wrap(sampler.wrapR, k0 + 1, d0);
+ /** @type {tcuTexLookupVerifier.ColorQuad} */
+ var quad00 = tcuTexLookupVerifier.lookupQuad(level0, sampler, x0, x1, y0, y1, z0);
+ /** @type {tcuTexLookupVerifier.ColorQuad} */
+ var quad01 = tcuTexLookupVerifier.lookupQuad(level0, sampler, x0, x1, y0, y1, z1);
+
+ if (texClass == tcuTexture.TextureChannelClass.FLOATING_POINT)
+ searchStep0 = Math.min(tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad(prec, quad00), tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad(prec, quad01));
+ else
+ searchStep0 = cSearchStep;
+
+ /** @type {number} */ var minA0 = deMath.clamp((uBounds0[0] - 0.5) - i0, 0, 1);
+ /** @type {number} */ var maxA0 = deMath.clamp((uBounds0[1] - 0.5) - i0, 0, 1);
+ /** @type {number} */ var minB0 = deMath.clamp((vBounds0[0] - 0.5) - j0, 0, 1);
+ /** @type {number} */ var maxB0 = deMath.clamp((vBounds0[1] - 0.5) - j0, 0, 1);
+ /** @type {number} */ var minC0 = deMath.clamp((wBounds0[0] - 0.5) - k0, 0, 1);
+ /** @type {number} */ var maxC0 = deMath.clamp((wBounds0[1] - 0.5) - k0, 0, 1);
+
+ for (var k1 = minK1; k1 <= maxK1; k1++) {
+ for (var j1 = minJ1; j1 <= maxJ1; j1++) {
+ for (var i1 = minI1; i1 <= maxI1; i1++) {
+
+ /** @type {number} */ var searchStep1;
+
+ x0 = tcuTexVerifierUtil.wrap(sampler.wrapS, i1, w1);
+ x1 = tcuTexVerifierUtil.wrap(sampler.wrapS, i1 + 1, w1);
+ y0 = tcuTexVerifierUtil.wrap(sampler.wrapT, j1, h1);
+ y1 = tcuTexVerifierUtil.wrap(sampler.wrapT, j1 + 1, h1);
+ z0 = tcuTexVerifierUtil.wrap(sampler.wrapR, k1, d1);
+ z1 = tcuTexVerifierUtil.wrap(sampler.wrapR, k1 + 1, d1);
+ /** @type {tcuTexLookupVerifier.ColorQuad} */
+ var quad10 = tcuTexLookupVerifier.lookupQuad(level1, sampler, x0, x1, y0, y1, z0);
+ /** @type {tcuTexLookupVerifier.ColorQuad} */
+ var quad11 = tcuTexLookupVerifier.lookupQuad(level1, sampler, x0, x1, y0, y1, z1);
+
+ if (texClass == tcuTexture.TextureChannelClass.FLOATING_POINT)
+ searchStep1 = Math.min(tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad(prec, quad10), tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad(prec, quad11));
+ else
+ searchStep1 = cSearchStep;
+
+ /** @type {number} */ var minA1 = deMath.clamp((uBounds1[0] - 0.5) - i1, 0, 1);
+ /** @type {number} */ var maxA1 = deMath.clamp((uBounds1[1] - 0.5) - i1, 0, 1);
+ /** @type {number} */ var minB1 = deMath.clamp((vBounds1[0] - 0.5) - j1, 0, 1);
+ /** @type {number} */ var maxB1 = deMath.clamp((vBounds1[1] - 0.5) - j1, 0, 1);
+ /** @type {number} */ var minC1 = deMath.clamp((wBounds1[0] - 0.5) - k1, 0, 1);
+ /** @type {number} */ var maxC1 = deMath.clamp((wBounds1[1] - 0.5) - k1, 0, 1);
+
+ if (tcuTexLookupVerifier.is3DTrilinearFilterResultValid(
+ prec, quad00, quad01, quad10, quad11,
+ [minA0, maxA0], [minB0, maxB0], [minC0, maxC0],
+ [minA1, maxA1], [minB1, maxB1], [minC1, maxC1],
+ fBounds, Math.min(searchStep0, searchStep1), result))
+ return true;
+ }
+ }
+ }
+ }
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} filterMode
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {number} coordX
+ * @param {number} coordY
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLevelSampleResultValid_CoordXYAsNumber = function(level, sampler, filterMode, prec, coordX, coordY, result) {
+ if (filterMode == tcuTexture.FilterMode.LINEAR)
+ return tcuTexLookupVerifier.isLinearSampleResultValid_CoordXYAsNumber(level, sampler, prec, coordX, coordY, result);
+ else
+ return tcuTexLookupVerifier.isNearestSampleResultValid_CoordXYAsNumber(level, sampler, prec, coordX, coordY, result);
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} filterMode
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {number} coordZ
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec2AndInt = function(level, sampler, filterMode, prec, coord, coordZ, result) {
+ if (filterMode == tcuTexture.FilterMode.LINEAR)
+ return tcuTexLookupVerifier.isLinearSampleResultValid_CoordAsVec2AndInt(level, sampler, prec, coord, coordZ, result);
+ else
+ return tcuTexLookupVerifier.isNearestSampleResultValid_CoordAsVec2AndInt(level, sampler, prec, coord, coordZ, result);
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} filterMode
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec3 = function(level, sampler, filterMode, prec, coord, result) {
+ if (filterMode == tcuTexture.FilterMode.LINEAR)
+ return tcuTexLookupVerifier.isLinearSampleResultValid_CoordAsVec3(level, sampler, prec, coord, result);
+ else
+ return tcuTexLookupVerifier.isNearestSampleResultValid_CoordAsVec3(level, sampler, prec, coord, result);
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level0
+ * @param {tcuTexture.ConstPixelBufferAccess} level1
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} levelFilter
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {number} coordZ
+ * @param {Array<number>} fBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isMipmapLinearSampleResultValid_CoordAsVec2AndInt = function(level0, level1, sampler, levelFilter, prec, coord, coordZ, fBounds, result) {
+ if (levelFilter == tcuTexture.FilterMode.LINEAR)
+ return tcuTexLookupVerifier.isLinearMipmapLinearSampleResultValid_CoordAsVec2AndInt(level0, level1, sampler, prec, coord, coordZ, fBounds, result);
+ else
+ return tcuTexLookupVerifier.isNearestMipmapLinearSampleResultValid_CoordAsVec2AndInt(level0, level1, sampler, prec, coord, coordZ, fBounds, result);
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} level0
+ * @param {tcuTexture.ConstPixelBufferAccess} level1
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} levelFilter
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {Array<number>} fBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isMipmapLinearSampleResultValid_CoordAsVec3 = function(level0, level1, sampler, levelFilter, prec, coord, fBounds, result) {
+ if (levelFilter == tcuTexture.FilterMode.LINEAR)
+ return tcuTexLookupVerifier.isLinearMipmapLinearSampleResultValid_CoordAsVec3(level0, level1, sampler, prec, coord, fBounds, result);
+ else
+ return tcuTexLookupVerifier.isNearestMipmapLinearSampleResultValid_CoordAsVec3(level0, level1, sampler, prec, coord, fBounds, result);
+ };
+
+ /**
+ * @param {tcuTexture.Texture2DView} texture
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {Array<number>} lodBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLookupResultValid_Texture2DView = function(texture, sampler, prec, coord, lodBounds, result) {
+ /** @type {number} */ var minLod = lodBounds[0];
+ /** @type {number} */ var maxLod = lodBounds[1];
+ /** @type {boolean} */ var canBeMagnified = minLod <= sampler.lodThreshold;
+ /** @type {boolean} */ var canBeMinified = maxLod > sampler.lodThreshold;
+
+ assertMsgOptions(tcuTexLookupVerifier.isSamplerSupported(sampler), 'Sampler not supported.', false, true);
+
+ /** @type {number} */ var minLevel;
+ /** @type {number} */ var maxLevel;
+
+ if (canBeMagnified)
+ if (tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec2AndInt(texture.getLevel(0), sampler, sampler.magFilter, prec, coord, 0, result))
+ return true;
+
+ if (canBeMinified) {
+ /** @type {boolean} */ var isNearestMipmap = tcuTexVerifierUtil.isNearestMipmapFilter(sampler.minFilter);
+ /** @type {boolean} */ var isLinearMipmap = tcuTexVerifierUtil.isLinearMipmapFilter(sampler.minFilter);
+ /** @type {number} */ var minTexLevel = 0;
+ /** @type {number} */ var maxTexLevel = texture.getNumLevels() - 1;
+
+ assertMsgOptions(minTexLevel <= maxTexLevel, 'minTexLevel > maxTexLevel', false, true);
+
+ if (isLinearMipmap && minTexLevel < maxTexLevel) {
+ minLevel = deMath.clamp(Math.floor(minLod), minTexLevel, maxTexLevel - 1);
+ maxLevel = deMath.clamp(Math.floor(maxLod), minTexLevel, maxTexLevel - 1);
+
+ assertMsgOptions(minLevel <= maxLevel, 'minLevel > maxLevel', false, true);
+
+ for (var level = minLevel; level <= maxLevel; level++) {
+ /** @type {number} */ var minF = deMath.clamp(minLod - level, 0, 1);
+ /** @type {number} */ var maxF = deMath.clamp(maxLod - level, 0, 1);
+
+ if (tcuTexLookupVerifier.isMipmapLinearSampleResultValid_CoordAsVec2AndInt(texture.getLevel(level), texture.getLevel(level + 1), sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, coord, 0, [minF, maxF], result))
+ return true;
+ }
+ } else if (isNearestMipmap) {
+ // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
+ // decision to allow floor(lod + 0.5) as well.
+ minLevel = deMath.clamp(Math.ceil(minLod + 0.5) - 1, minTexLevel, maxTexLevel);
+ maxLevel = deMath.clamp(Math.floor(maxLod + 0.5), minTexLevel, maxTexLevel);
+
+ assertMsgOptions(minLevel <= maxLevel, 'minLevel > maxLevel', false, true);
+
+ for (var level = minLevel; level <= maxLevel; level++) {
+ if (tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec2AndInt(texture.getLevel(level), sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, coord, 0, result))
+ return true;
+ }
+ } else {
+ if (tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec2AndInt(texture.getLevel(0), sampler, sampler.minFilter, prec, coord, 0, result))
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.TextureCubeView} texture
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {Array<number>} lodBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLookupResultValid_TextureCubeView = function(texture, sampler, prec, coord, lodBounds, result) {
+ /** @type {number} */ var numPossibleFaces = 0;
+
+ assertMsgOptions(tcuTexLookupVerifier.isSamplerSupported(sampler), 'Sampler not supported.', false, true);
+
+ /** @type {Array<tcuTexture.CubeFace>} */ var possibleFaces = tcuTexVerifierUtil.getPossibleCubeFaces(coord, prec.coordBits);
+
+ /** @type {number} */ var minLevel;
+ /** @type {number} */ var maxLevel;
+
+ if (!possibleFaces)
+ return true; // Result is undefined.
+
+ for (var tryFaceNdx = 0; tryFaceNdx < possibleFaces.length; tryFaceNdx++) {
+ /** @type {tcuTexture.CubeFaceCoords} */
+ var faceCoords = new tcuTexture.CubeFaceCoords(possibleFaces[tryFaceNdx], tcuTexture.projectToFace(possibleFaces[tryFaceNdx], coord));
+ /** @type {number} */ var minLod = lodBounds[0];
+ /** @type {number} */ var maxLod = lodBounds[1];
+ /** @type {boolean} */ var canBeMagnified = minLod <= sampler.lodThreshold;
+ /** @type {boolean} */ var canBeMinified = maxLod > sampler.lodThreshold;
+
+ /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faces = [];
+ if (canBeMagnified) {
+ tcuTexLookupVerifier.getCubeLevelFaces(texture, 0, faces);
+
+ if (tcuTexLookupVerifier.isCubeLevelSampleResultValid(faces, sampler, sampler.magFilter, prec, faceCoords, result))
+ return true;
+ }
+
+ if (canBeMinified) {
+ /** @type {boolean} */ var isNearestMipmap = tcuTexVerifierUtil.isNearestMipmapFilter(sampler.minFilter);
+ /** @type {boolean} */ var isLinearMipmap = tcuTexVerifierUtil.isLinearMipmapFilter(sampler.minFilter);
+ /** @type {number} */ var minTexLevel = 0;
+ /** @type {number} */ var maxTexLevel = texture.getNumLevels() - 1;
+
+ assertMsgOptions(minTexLevel <= maxTexLevel, 'minTexLevel > maxTexLevel', false, true);
+
+ if (isLinearMipmap && minTexLevel < maxTexLevel) {
+ minLevel = deMath.clamp(Math.floor(minLod), minTexLevel, maxTexLevel - 1);
+ maxLevel = deMath.clamp(Math.floor(maxLod), minTexLevel, maxTexLevel - 1);
+
+ assertMsgOptions(minLevel <= maxLevel, 'minLevel > maxLevel', false, true);
+
+ for (var levelNdx = minLevel; levelNdx <= maxLevel; levelNdx++) {
+ /** @type {number} */ var minF = deMath.clamp(minLod - levelNdx, 0, 1);
+ /** @type {number} */ var maxF = deMath.clamp(maxLod - levelNdx, 0, 1);
+
+ /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faces0 = [];
+ /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faces1 = [];
+
+ tcuTexLookupVerifier.getCubeLevelFaces(texture, levelNdx, faces0);
+ tcuTexLookupVerifier.getCubeLevelFaces(texture, levelNdx + 1, faces1);
+
+ if (tcuTexLookupVerifier.isCubeMipmapLinearSampleResultValid(faces0, faces1, sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, faceCoords, [minF, maxF], result))
+ return true;
+ }
+ } else if (isNearestMipmap) {
+ // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
+ // decision to allow floor(lod + 0.5) as well.
+ minLevel = deMath.clamp(Math.ceil(minLod + 0.5) - 1, minTexLevel, maxTexLevel);
+ maxLevel = deMath.clamp(Math.floor(maxLod + 0.5), minTexLevel, maxTexLevel);
+
+ assertMsgOptions(minLevel <= maxLevel, 'minLevel > maxLevel', false, true);
+
+ for (var levelNdx = minLevel; levelNdx <= maxLevel; levelNdx++) {
+ tcuTexLookupVerifier.getCubeLevelFaces(texture, levelNdx, faces);
+
+ if (tcuTexLookupVerifier.isCubeLevelSampleResultValid(faces, sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, faceCoords, result))
+ return true;
+ }
+ } else {
+ tcuTexLookupVerifier.getCubeLevelFaces(texture, 0, faces);
+
+ if (tcuTexLookupVerifier.isCubeLevelSampleResultValid(faces, sampler, sampler.minFilter, prec, faceCoords, result))
+ return true;
+ }
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.Texture2DArrayView} texture
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {Array<number>} lodBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLookupResultValid_Texture2DArrayView = function(texture, sampler, prec, coord, lodBounds, result) {
+ /** @type {Array<number>} */ var layerRange = tcuTexLookupVerifier.computeLayerRange(texture.getNumLayers(), prec.coordBits[2], coord[2]);
+ /** @type {Array<number>} */ var coordXY = deMath.swizzle(coord, [0, 1]);
+ /** @type {number} */ var minLod = lodBounds[0];
+ /** @type {number} */ var maxLod = lodBounds[1];
+ /** @type {boolean} */ var canBeMagnified = minLod <= sampler.lodThreshold;
+ /** @type {boolean} */ var canBeMinified = maxLod > sampler.lodThreshold;
+
+ assertMsgOptions(tcuTexLookupVerifier.isSamplerSupported(sampler), 'Sampler not supported.', false, true);
+ /** @type {number} */ var minLevel;
+ /** @type {number} */ var maxLevel;
+
+ for (var layer = layerRange[0]; layer <= layerRange[1]; layer++) {
+ if (canBeMagnified) {
+ if (tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec2AndInt(texture.getLevel(0), sampler, sampler.magFilter, prec, coordXY, layer, result))
+ return true;
+ }
+
+ if (canBeMinified) {
+ /** @type {boolean} */ var isNearestMipmap = tcuTexVerifierUtil.isNearestMipmapFilter(sampler.minFilter);
+ /** @type {boolean} */ var isLinearMipmap = tcuTexVerifierUtil.isLinearMipmapFilter(sampler.minFilter);
+ /** @type {number} */ var minTexLevel = 0;
+ /** @type {number} */ var maxTexLevel = texture.getNumLevels() - 1;
+
+ assertMsgOptions(minTexLevel <= maxTexLevel, 'minTexLevel > maxTexLevel', false, true);
+
+ if (isLinearMipmap && minTexLevel < maxTexLevel) {
+ minLevel = deMath.clamp(Math.floor(minLod), minTexLevel, maxTexLevel - 1);
+ maxLevel = deMath.clamp(Math.floor(maxLod), minTexLevel, maxTexLevel - 1);
+
+ assertMsgOptions(minLevel <= maxLevel, 'minLevel > maxLevel', false, true);
+
+ for (var level = minLevel; level <= maxLevel; level++) {
+ /** @type {number} */ var minF = deMath.clamp(minLod - level, 0, 1);
+ /** @type {number} */ var maxF = deMath.clamp(maxLod - level, 0, 1);
+
+ if (tcuTexLookupVerifier.isMipmapLinearSampleResultValid_CoordAsVec2AndInt(texture.getLevel(level), texture.getLevel(level + 1), sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, coordXY, layer, [minF, maxF], result))
+ return true;
+ }
+ } else if (isNearestMipmap) {
+ // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
+ // decision to allow floor(lod + 0.5) as well.
+ minLevel = deMath.clamp(Math.ceil(minLod + 0.5) - 1, minTexLevel, maxTexLevel);
+ maxLevel = deMath.clamp(Math.floor(maxLod + 0.5), minTexLevel, maxTexLevel);
+
+ assertMsgOptions(minLevel <= maxLevel, 'minLevel > maxLevel', false, true);
+
+ for (var level = minLevel; level <= maxLevel; level++) {
+ if (tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec2AndInt(texture.getLevel(level), sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, coordXY, layer, result))
+ return true;
+ }
+ } else {
+ if (tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec2AndInt(texture.getLevel(0), sampler, sampler.minFilter, prec, coordXY, layer, result))
+ return true;
+ }
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {tcuTexture.Texture3DView} texture
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {Array<number>} lodBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLookupResultValid = function(texture, sampler, prec, coord, lodBounds, result) {
+ /** @type {number} */ var minLod = lodBounds[0];
+ /** @type {number} */ var maxLod = lodBounds[1];
+ /** @type {boolean} */ var canBeMagnified = minLod <= sampler.lodThreshold;
+ /** @type {boolean} */ var canBeMinified = maxLod > sampler.lodThreshold;
+
+ assertMsgOptions(tcuTexLookupVerifier.isSamplerSupported(sampler), 'Sampler not supported.', false, true);
+
+ /** @type {number} */ var minLevel;
+ /** @type {number} */ var maxLevel;
+
+ if (canBeMagnified)
+ if (tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec3(texture.getLevel(0), sampler, sampler.magFilter, prec, coord, result))
+ return true;
+
+ if (canBeMinified) {
+ /** @type {boolean} */ var isNearestMipmap = tcuTexVerifierUtil.isNearestMipmapFilter(sampler.minFilter);
+ /** @type {boolean} */ var isLinearMipmap = tcuTexVerifierUtil.isLinearMipmapFilter(sampler.minFilter);
+ /** @type {number} */ var minTexLevel = 0;
+ /** @type {number} */ var maxTexLevel = texture.getNumLevels() - 1;
+
+ assertMsgOptions(minTexLevel <= maxTexLevel, 'minTexLevel > maxTexLevel', false, true);
+
+ if (isLinearMipmap && minTexLevel < maxTexLevel) {
+ minLevel = deMath.clamp(Math.floor(minLod), minTexLevel, maxTexLevel - 1);
+ maxLevel = deMath.clamp(Math.floor(maxLod), minTexLevel, maxTexLevel - 1);
+
+ assertMsgOptions(minLevel <= maxLevel, 'minLevel > maxLevel', false, true);
+
+ for (var level = minLevel; level <= maxLevel; level++) {
+ /** @type {number} */ var minF = deMath.clamp(minLod - level, 0, 1);
+ /** @type {number} */ var maxF = deMath.clamp(maxLod - level, 0, 1);
+
+ if (tcuTexLookupVerifier.isMipmapLinearSampleResultValid_CoordAsVec3(texture.getLevel(level), texture.getLevel(level + 1), sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, coord, [minF, maxF], result))
+ return true;
+ }
+ } else if (isNearestMipmap) {
+ // \note The accurate formula for nearest mipmapping is level = ceil(lod + 0.5) - 1 but Khronos has made
+ // decision to allow floor(lod + 0.5) as well.
+ minLevel = deMath.clamp(Math.ceil(minLod + 0.5) - 1, minTexLevel, maxTexLevel);
+ maxLevel = deMath.clamp(Math.floor(maxLod + 0.5), minTexLevel, maxTexLevel);
+
+ assertMsgOptions(minLevel <= maxLevel, 'minLevel > maxLevel', false, true);
+
+ for (var level = minLevel; level <= maxLevel; level++) {
+ if (tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec3(texture.getLevel(level), sampler, tcuTexVerifierUtil.getLevelFilter(sampler.minFilter), prec, coord, result))
+ return true;
+ }
+ } else {
+ if (tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec3(texture.getLevel(0), sampler, sampler.minFilter, prec, coord, result))
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} faces (&faces)[CUBEFACE_LAST]
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexture.CubeFaceCoords} coords
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isSeamlessLinearSampleResultValid = function(faces, sampler, prec, coords, result) {
+ /** @type {number} */ var size = faces[coords.face].getWidth();
+
+ /** @type {Array<number>} */ var uBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.s, prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */ var vBounds = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, size, coords.t, prec.coordBits[1], prec.uvwBits[1]);
+
+ // Integer coordinate bounds for (x0,y0) - without wrap mode
+ /** @type {number} */ var minI = Math.floor(uBounds[0] - 0.5);
+ /** @type {number} */ var maxI = Math.floor(uBounds[1] - 0.5);
+ /** @type {number} */ var minJ = Math.floor(vBounds[0] - 0.5);
+ /** @type {number} */ var maxJ = Math.floor(vBounds[1] - 0.5);
+
+ /** @type {tcuTexture.TextureChannelClass} */ var texClass = tcuTexture.getTextureChannelClass(faces[coords.face].getFormat().type);
+ /** @type {number} */ var searchStep = (texClass == tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT) ? tcuTexLookupVerifier.computeBilinearSearchStepForUnorm(prec) :
+ (texClass == tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT) ? tcuTexLookupVerifier.computeBilinearSearchStepForSnorm(prec) :
+ 0; // Step is computed for floating-point quads based on texel values.
+
+ for (var j = minJ; j <= maxJ; j++) {
+ for (var i = minI; i <= maxI; i++) {
+ /** @type {tcuTexture.CubeFaceCoords} */ var c00 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i + 0, j + 0]), size);
+ /** @type {tcuTexture.CubeFaceCoords} */ var c10 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i + 1, j + 0]), size);
+ /** @type {tcuTexture.CubeFaceCoords} */ var c01 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i + 0, j + 1]), size);
+ /** @type {tcuTexture.CubeFaceCoords} */ var c11 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i + 1, j + 1]), size);
+
+ // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
+ // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
+ if (c00 == null || c01 == null || c10 == null || c11 == null ||
+ c00.face == null || c01.face == null || c10.face == null || c11.face == null)
+ return true;
+
+ // Bounds for filtering factors
+ /** @type {number} */ var minA = deMath.clamp((uBounds[0] - 0.5) - i, 0, 1);
+ /** @type {number} */ var maxA = deMath.clamp((uBounds[1] - 0.5) - i, 0, 1);
+ /** @type {number} */ var minB = deMath.clamp((vBounds[0] - 0.5) - j, 0, 1);
+ /** @type {number} */ var maxB = deMath.clamp((vBounds[1] - 0.5) - j, 0, 1);
+
+ /** @type {tcuTexLookupVerifier.ColorQuad} */
+ var quad = new tcuTexLookupVerifier.ColorQuad([], [], [], []);
+ quad.p00 = tcuTexLookupVerifier.lookupFloat(faces[c00.face], sampler, c00.s, c00.t, 0);
+ quad.p10 = tcuTexLookupVerifier.lookupFloat(faces[c10.face], sampler, c10.s, c10.t, 0);
+ quad.p01 = tcuTexLookupVerifier.lookupFloat(faces[c01.face], sampler, c01.s, c01.t, 0);
+ quad.p11 = tcuTexLookupVerifier.lookupFloat(faces[c11.face], sampler, c11.s, c11.t, 0);
+
+ if (texClass == tcuTexture.TextureChannelClass.FLOATING_POINT)
+ searchStep = tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad(prec, quad);
+
+ if (tcuTexLookupVerifier.isBilinearRangeValid(prec, quad, [minA, maxA], [minB, maxB], searchStep, result))
+ return true;
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} faces0 (&faces0)[CUBEFACE_LAST]
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} faces1 (&faces1)[CUBEFACE_LAST]
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexture.CubeFaceCoords} coords
+ * @param {Array<number>} fBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isSeamplessLinearMipmapLinearSampleResultValid = function(faces0, faces1, sampler, prec, coords, fBounds, result) {
+ // \todo [2013-07-04 pyry] This is strictly not correct as coordinates between levels should be dependent.
+ // Right now this allows pairing any two valid bilinear quads.
+ /** @type {number} */ var size0 = faces0[coords.face].getWidth();
+ /** @type {number} */ var size1 = faces1[coords.face].getWidth();
+
+ /** @type {Array<number>} */ var uBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0, coords.s, prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */ var uBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1, coords.s, prec.coordBits[0], prec.uvwBits[0]);
+ /** @type {Array<number>} */ var vBounds0 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, size0, coords.t, prec.coordBits[1], prec.uvwBits[1]);
+ /** @type {Array<number>} */ var vBounds1 = tcuTexVerifierUtil.computeNonNormalizedCoordBounds(sampler.normalizedCoords, size1, coords.t, prec.coordBits[1], prec.uvwBits[1]);
+
+ // Integer coordinates - without wrap mode
+ /** @type {number} */ var minI0 = Math.floor(uBounds0[0] - 0.5);
+ /** @type {number} */ var maxI0 = Math.floor(uBounds0[1] - 0.5);
+ /** @type {number} */ var minI1 = Math.floor(uBounds1[0] - 0.5);
+ /** @type {number} */ var maxI1 = Math.floor(uBounds1[1] - 0.5);
+ /** @type {number} */ var minJ0 = Math.floor(vBounds0[0] - 0.5);
+ /** @type {number} */ var maxJ0 = Math.floor(vBounds0[1] - 0.5);
+ /** @type {number} */ var minJ1 = Math.floor(vBounds1[0] - 0.5);
+ /** @type {number} */ var maxJ1 = Math.floor(vBounds1[1] - 0.5);
+
+ /** @type {tcuTexture.TextureChannelClass} */ var texClass = tcuTexture.getTextureChannelClass(faces0[coords.face].getFormat().type);
+ /** @type {number} */ var cSearchStep = (texClass == tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT) ? tcuTexLookupVerifier.computeBilinearSearchStepForUnorm(prec) :
+ (texClass == tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT) ? tcuTexLookupVerifier.computeBilinearSearchStepForSnorm(prec) :
+ 0; // Step is computed for floating-point quads based on texel values.
+
+ /** @type {tcuTexture.CubeFaceCoords} */ var c00;
+ /** @type {tcuTexture.CubeFaceCoords} */ var c10;
+ /** @type {tcuTexture.CubeFaceCoords} */ var c01;
+ /** @type {tcuTexture.CubeFaceCoords} */ var c11;
+
+ for (var j0 = minJ0; j0 <= maxJ0; j0++) {
+ for (var i0 = minI0; i0 <= maxI0; i0++) {
+ /** @type {tcuTexLookupVerifier.ColorQuad} */
+ var quad0 = new tcuTexLookupVerifier.ColorQuad([], [], [], []);
+ /** @type {number} */ var searchStep0;
+
+ c00 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i0 + 0, j0 + 0]), size0);
+ c10 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i0 + 1, j0 + 0]), size0);
+ c01 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i0 + 0, j0 + 1]), size0);
+ c11 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i0 + 1, j0 + 1]), size0);
+
+ // If any of samples is out of both edges, implementations can do pretty much anything according to spec.
+ // \todo [2013-07-08 pyry] Test the special case where all corner pixels have exactly the same color.
+ if (c00 == null || c01 == null || c10 == null || c11 == null ||
+ c00.face == null || c01.face == null || c10.face == null || c11.face == null)
+ return true;
+
+ quad0.p00 = tcuTexLookupVerifier.lookupFloat(faces0[c00.face], sampler, c00.s, c00.t, 0);
+ quad0.p10 = tcuTexLookupVerifier.lookupFloat(faces0[c10.face], sampler, c10.s, c10.t, 0);
+ quad0.p01 = tcuTexLookupVerifier.lookupFloat(faces0[c01.face], sampler, c01.s, c01.t, 0);
+ quad0.p11 = tcuTexLookupVerifier.lookupFloat(faces0[c11.face], sampler, c11.s, c11.t, 0);
+
+ if (texClass == tcuTexture.TextureChannelClass.FLOATING_POINT)
+ searchStep0 = tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad(prec, quad0);
+ else
+ searchStep0 = cSearchStep;
+
+ /** @type {number} */ var minA0 = deMath.clamp((uBounds0[0] - 0.5) - i0, 0, 1);
+ /** @type {number} */ var maxA0 = deMath.clamp((uBounds0[1] - 0.5) - i0, 0, 1);
+ /** @type {number} */ var minB0 = deMath.clamp((vBounds0[0] - 0.5) - j0, 0, 1);
+ /** @type {number} */ var maxB0 = deMath.clamp((vBounds0[1] - 0.5) - j0, 0, 1);
+
+ for (var j1 = minJ1; j1 <= maxJ1; j1++) {
+ for (var i1 = minI1; i1 <= maxI1; i1++) {
+ /** @type {tcuTexLookupVerifier.ColorQuad} */
+ var quad1 = new tcuTexLookupVerifier.ColorQuad([], [], [], []);
+ /** @type {number} */ var searchStep1;
+
+ c00 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i1 + 0, j1 + 0]), size1);
+ c10 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i1 + 1, j1 + 0]), size1);
+ c01 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i1 + 0, j1 + 1]), size1);
+ c11 = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(coords.face, [i1 + 1, j1 + 1]), size1);
+
+ if (c00 == null || c01 == null || c10 == null || c11 == null ||
+ c00.face == null || c01.face == null || c10.face == null || c11.face == null)
+ return true;
+
+ quad1.p00 = tcuTexLookupVerifier.lookupFloat(faces1[c00.face], sampler, c00.s, c00.t, 0);
+ quad1.p10 = tcuTexLookupVerifier.lookupFloat(faces1[c10.face], sampler, c10.s, c10.t, 0);
+ quad1.p01 = tcuTexLookupVerifier.lookupFloat(faces1[c01.face], sampler, c01.s, c01.t, 0);
+ quad1.p11 = tcuTexLookupVerifier.lookupFloat(faces1[c11.face], sampler, c11.s, c11.t, 0);
+
+ if (texClass == tcuTexture.TextureChannelClass.FLOATING_POINT)
+ searchStep1 = tcuTexLookupVerifier.computeBilinearSearchStepFromFloatQuad(prec, quad1);
+ else
+ searchStep1 = cSearchStep;
+
+ /** @type {number} */ var minA1 = deMath.clamp((uBounds1[0] - 0.5) - i1, 0, 1);
+ /** @type {number} */ var maxA1 = deMath.clamp((uBounds1[1] - 0.5) - i1, 0, 1);
+ /** @type {number} */ var minB1 = deMath.clamp((vBounds1[0] - 0.5) - j1, 0, 1);
+ /** @type {number} */ var maxB1 = deMath.clamp((vBounds1[1] - 0.5) - j1, 0, 1);
+
+ if (tcuTexLookupVerifier.is2DTrilinearFilterResultValid(prec, quad0, quad1, [minA0, maxA0], [minB0, maxB0], [minA1, maxA1], [minB1, maxB1],
+ fBounds, Math.min(searchStep0, searchStep1), result))
+ return true;
+ }
+ }
+ }
+ }
+
+ return false;
+ };
+
+ /**
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} level (&level)[CUBEFACE_LAST]
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} filterMode
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexture.CubeFaceCoords} coords
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isCubeLevelSampleResultValid = function(level, sampler, filterMode, prec, coords, result) {
+ if (filterMode == tcuTexture.FilterMode.LINEAR) {
+ if (sampler.seamlessCubeMap)
+ return tcuTexLookupVerifier.isSeamlessLinearSampleResultValid(level, sampler, prec, coords, result);
+ else
+ return tcuTexLookupVerifier.isLinearSampleResultValid_CoordAsVec2AndInt(level[coords.face], sampler, prec, [coords.s, coords.t], 0, result);
+ } else
+ return tcuTexLookupVerifier.isNearestSampleResultValid_CoordAsVec2AndInt(level[coords.face], sampler, prec, [coords.s, coords.t], 0, result);
+ };
+
+ /**
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} faces0 (&faces0)[CUBEFACE_LAST]
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} faces1 (&faces1)[CUBEFACE_LAST]
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} levelFilter
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {tcuTexture.CubeFaceCoords} coords
+ * @param {Array<number>} fBounds
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isCubeMipmapLinearSampleResultValid = function(faces0, faces1, sampler, levelFilter, prec, coords, fBounds, result) {
+ if (levelFilter == tcuTexture.FilterMode.LINEAR) {
+ if (sampler.seamlessCubeMap)
+ return tcuTexLookupVerifier.isSeamplessLinearMipmapLinearSampleResultValid(faces0, faces1, sampler, prec, coords, fBounds, result);
+ else
+ return tcuTexLookupVerifier.isLinearMipmapLinearSampleResultValid_CoordAsVec2AndInt(faces0[coords.face], faces1[coords.face], sampler, prec, [coords.s, coords.t], 0, fBounds, result);
+ } else
+ return tcuTexLookupVerifier.isNearestMipmapLinearSampleResultValid_CoordAsVec2AndInt(faces0[coords.face], faces1[coords.face], sampler, prec, [coords.s, coords.t], 0, fBounds, result);
+ };
+
+ /**
+ * @param {tcuTexture.TextureCubeView} texture
+ * @param {number} levelNdx
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} out (&out)[CUBEFACE_LAST]
+ */
+ tcuTexLookupVerifier.getCubeLevelFaces = function(texture, levelNdx, out) {
+ for (var faceNdx = 0; faceNdx < 6; faceNdx++)
+ out[faceNdx] = texture.getLevelFace(levelNdx, /** @type {tcuTexture.CubeFace} */ (faceNdx));
+ };
+
+ /**
+ * @param {number} numLayers
+ * @param {number} numCoordBits
+ * @param {number} layerCoord
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.computeLayerRange = function(numLayers, numCoordBits, layerCoord) {
+ /** @type {number} */ var err = tcuTexVerifierUtil.computeFloatingPointError(layerCoord, numCoordBits);
+ /** @type {number} */ var minL = Math.floor(layerCoord - err + 0.5); // Round down
+ /** @type {number} */ var maxL = Math.ceil(layerCoord + err + 0.5) - 1; // Round up
+
+ assertMsgOptions(minL <= maxL, 'minL > maxL', false, true);
+
+ return [deMath.clamp(minL, 0, numLayers - 1), deMath.clamp(maxL, 0, numLayers - 1)];
+ };
+
+ /**
+ * @param {Array<number>} bits
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.computeFixedPointThreshold = function(bits) {
+ return tcuTexVerifierUtil.computeFixedPointError_Vector(bits);
+ };
+
+ /**
+ * @param {Array<number>} bits
+ * @param {Array<number>} value
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.computeFloatingPointThreshold = function(bits, value) {
+ return tcuTexVerifierUtil.computeFloatingPointError_Vector(value, bits);
+ };
+
+ /**
+ * @param {number} dudx
+ * @param {number} dvdx
+ * @param {number} dwdx
+ * @param {number} dudy
+ * @param {number} dvdy
+ * @param {number} dwdy
+ * @param {tcuTexLookupVerifier.LodPrecision} prec
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.computeLodBoundsFromDerivates = function(dudx, dvdx, dwdx, dudy, dvdy, dwdy, prec) {
+ /** @type {number} */ var mu = Math.max(Math.abs(dudx), Math.abs(dudy));
+ /** @type {number} */ var mv = Math.max(Math.abs(dvdx), Math.abs(dvdy));
+ /** @type {number} */ var mw = Math.max(Math.abs(dwdx), Math.abs(dwdy));
+ /** @type {number} */ var minDBound = Math.max(Math.max(mu, mv), mw);
+ /** @type {number} */ var maxDBound = mu + mv + mw;
+ /** @type {number} */ var minDErr = tcuTexVerifierUtil.computeFloatingPointError(minDBound, prec.derivateBits);
+ /** @type {number} */ var maxDErr = tcuTexVerifierUtil.computeFloatingPointError(maxDBound, prec.derivateBits);
+ /** @type {number} */ var minLod = Math.log2(minDBound - minDErr);
+ /** @type {number} */ var maxLod = Math.log2(maxDBound + maxDErr);
+ /** @type {number} */ var lodErr = tcuTexVerifierUtil.computeFixedPointError(prec.lodBits);
+
+ assertMsgOptions(minLod <= maxLod, 'Error: minLod > maxLod', false, true);
+ return [minLod - lodErr, maxLod + lodErr];
+ };
+
+ /**
+ * @param {number} dudx
+ * @param {number} dvdx
+ * @param {number} dudy
+ * @param {number} dvdy
+ * @param {tcuTexLookupVerifier.LodPrecision} prec
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV = function(dudx, dvdx, dudy, dvdy, prec) {
+ return tcuTexLookupVerifier.computeLodBoundsFromDerivates(dudx, dvdx, 0, dudy, dvdy, 0, prec);
+ };
+
+ /**
+ * @param {number} dudx
+ * @param {number} dudy
+ * @param {tcuTexLookupVerifier.LodPrecision} prec
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.computeLodBoundsFromDerivatesU = function(dudx, dudy, prec) {
+ return tcuTexLookupVerifier.computeLodBoundsFromDerivates(dudx, 0, 0, dudy, 0, 0, prec);
+ };
+
+ /**
+ * @param {Array<number>} coord
+ * @param {Array<number>} coordDx
+ * @param {Array<number>} coordDy
+ * @param {number} faceSize
+ * @param {tcuTexLookupVerifier.LodPrecision} prec
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.computeCubeLodBoundsFromDerivates = function(coord, coordDx, coordDy, faceSize, prec) {
+ /** @type {boolean} */ var allowBrokenEdgeDerivate = false;
+ /** @type {tcuTexture.CubeFace} */ var face = tcuTexture.selectCubeFace(coord);
+ /** @type {number} */ var maNdx = 0;
+ /** @type {number} */ var sNdx = 0;
+ /** @type {number} */ var tNdx = 0;
+
+ // \note Derivate signs don't matter when computing lod
+ switch (face) {
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X:
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: maNdx = 0; sNdx = 2; tNdx = 1; break;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y:
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: maNdx = 1; sNdx = 0; tNdx = 2; break;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z:
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: maNdx = 2; sNdx = 0; tNdx = 1; break;
+ default:
+ throw new Error('Invalid CubeFace.');
+ }
+
+ /** @type {number} */ var sc = coord[sNdx];
+ /** @type {number} */ var tc = coord[tNdx];
+ /** @type {number} */ var ma = Math.abs(coord[maNdx]);
+ /** @type {number} */ var scdx = coordDx[sNdx];
+ /** @type {number} */ var tcdx = coordDx[tNdx];
+ /** @type {number} */ var madx = Math.abs(coordDx[maNdx]);
+ /** @type {number} */ var scdy = coordDy[sNdx];
+ /** @type {number} */ var tcdy = coordDy[tNdx];
+ /** @type {number} */ var mady = Math.abs(coordDy[maNdx]);
+ /** @type {number} */ var dudx = faceSize * 0.5 * (scdx * ma - sc * madx) / (ma * ma);
+ /** @type {number} */ var dvdx = faceSize * 0.5 * (tcdx * ma - tc * madx) / (ma * ma);
+ /** @type {number} */ var dudy = faceSize * 0.5 * (scdy * ma - sc * mady) / (ma * ma);
+ /** @type {number} */ var dvdy = faceSize * 0.5 * (tcdy * ma - tc * mady) / (ma * ma);
+ /** @type {Array<number>} */ var bounds = tcuTexLookupVerifier.computeLodBoundsFromDerivatesUV(dudx, dvdx, dudy, dvdy, prec);
+
+ // Implementations may compute derivate from projected (s, t) resulting in incorrect values at edges.
+ if (allowBrokenEdgeDerivate) {
+ /** @type {Array<number>} */ var dxErr = tcuTexVerifierUtil.computeFloatingPointError_Vector(coordDx, [prec.derivateBits, prec.derivateBits, prec.derivateBits]);
+ /** @type {Array<number>} */ var dyErr = tcuTexVerifierUtil.computeFloatingPointError_Vector(coordDy, [prec.derivateBits, prec.derivateBits, prec.derivateBits]);
+ /** @type {Array<number>} */ var xoffs = deMath.add(deMath.abs(coordDx), dxErr);
+ /** @type {Array<number>} */ var yoffs = deMath.add(deMath.abs(coordDy), dyErr);
+
+ if (tcuTexture.selectCubeFace(deMath.add(coord, xoffs)) != face ||
+ tcuTexture.selectCubeFace(deMath.subtract(coord, xoffs)) != face ||
+ tcuTexture.selectCubeFace(deMath.add(coord, yoffs)) != face ||
+ tcuTexture.selectCubeFace(deMath.subtract(coord, yoffs)) != face) {
+ return [bounds[0], 1000];
+ }
+ }
+
+ return bounds;
+ };
+
+ /**
+ * @param {Array<number>} lodBounds
+ * @param {Array<number>} lodMinMax
+ * @param {tcuTexLookupVerifier.LodPrecision} prec
+ * @return {Array<number>}
+ */
+ tcuTexLookupVerifier.clampLodBounds = function(lodBounds, lodMinMax, prec) {
+ /** @type {number} */ var lodErr = tcuTexVerifierUtil.computeFixedPointError(prec.lodBits);
+ /** @type {number} */ var a = lodMinMax[0];
+ /** @type {number} */ var b = lodMinMax[1];
+ return [deMath.clamp(lodBounds[0], a - lodErr, b - lodErr), deMath.clamp(lodBounds[1], a + lodErr, b + lodErr)];
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.TexLookupScaleMode} scaleMode
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {number} coordZ
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLevel2DLookupResultValid = function(access, sampler, scaleMode, prec, coord, coordZ, result) {
+ /** @type {tcuTexture.FilterMode} */
+ var filterMode = (scaleMode == tcuTexLookupVerifier.TexLookupScaleMode.MAGNIFY) ? sampler.magFilter : sampler.minFilter;
+ return tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec2AndInt(access, sampler, filterMode, prec, coord, coordZ, result);
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.TexLookupScaleMode} scaleMode
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {number} coordZ
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLevel2DLookupResultValid_Int = function(access, sampler, scaleMode, prec, coord, coordZ, result) {
+ assertMsgOptions(sampler.minFilter == tcuTexture.FilterMode.NEAREST && sampler.magFilter == tcuTexture.FilterMode.NEAREST, 'minFilter and magFilter must be NEAREST', false, true);
+ return tcuTexLookupVerifier.isNearestSampleResultValid_CoordAsVec2AndInt(access, sampler, prec, coord, coordZ, result);
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.TexLookupScaleMode} scaleMode
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLevel3DLookupResultValid = function(access, sampler, scaleMode, prec, coord, result) {
+ /** @type {tcuTexture.FilterMode} */
+ var filterMode = (scaleMode == tcuTexLookupVerifier.TexLookupScaleMode.MAGNIFY) ? sampler.magFilter : sampler.minFilter;
+ return tcuTexLookupVerifier.isLevelSampleResultValid_CoordAsVec3(access, sampler, filterMode, prec, coord, result);
+ };
+
+ /**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexLookupVerifier.TexLookupScaleMode} scaleMode
+ * @param {tcuTexLookupVerifier.LookupPrecision} prec
+ * @param {Array<number>} coord
+ * @param {Array<number>} result
+ * @return {boolean}
+ */
+ tcuTexLookupVerifier.isLevel3DLookupResultValid_Int = function(access, sampler, scaleMode, prec, coord, result) {
+ assertMsgOptions(sampler.minFilter == tcuTexture.FilterMode.NEAREST && sampler.magFilter == tcuTexture.FilterMode.NEAREST, 'minFilter and magFilter must be NEAREST', false, true);
+ return tcuTexLookupVerifier.isNearestSampleResultValid_CoordAsVec3(access, sampler, prec, coord, result);
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexVerifierUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexVerifierUtil.js
new file mode 100644
index 0000000000..4c88f44608
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexVerifierUtil.js
@@ -0,0 +1,265 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuTexVerifierUtil');
+goog.require('framework.common.tcuFloat');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.delibs.debase.deUtil');
+
+goog.scope(function() {
+
+ var tcuTexVerifierUtil = framework.common.tcuTexVerifierUtil;
+ var deMath = framework.delibs.debase.deMath;
+ var deUtil = framework.delibs.debase.deUtil;
+ var tcuFloat = framework.common.tcuFloat;
+ var tcuTexture = framework.common.tcuTexture;
+
+ /**
+ * @param {number} value
+ * @param {number} numAccurateBits
+ * @return {number}
+ */
+ tcuTexVerifierUtil.computeFloatingPointError = function(value, numAccurateBits) {
+ /** @type {number} */ var numGarbageBits = 23 - numAccurateBits;
+ /** @type {number} */ var mask = (1 << numGarbageBits) - 1;
+ /** @type {number} */ var exp = tcuFloat.newFloat32(value).exponent();
+
+ /** @type {tcuFloat.deFloat} */ var v1 = new tcuFloat.deFloat();
+ /** @type {tcuFloat.deFloat} */ var v2 = new tcuFloat.deFloat();
+ return v1.construct(1, exp, 1 << 23 | mask).getValue() - v2.construct(1, exp, 1 << 23).getValue();
+ };
+
+ /**
+ * @param {number} numAccurateBits
+ * @return {number}
+ */
+ tcuTexVerifierUtil.computeFixedPointError = function(numAccurateBits) {
+ return tcuTexVerifierUtil.computeFloatingPointError(1.0, numAccurateBits);
+ };
+
+ /**
+ * @param {Array<number>} numAccurateBits
+ * @return {Array<number>}
+ */
+ tcuTexVerifierUtil.computeFixedPointError_Vector = function(numAccurateBits) {
+ /** @type {Array<number>} */ var res = [];
+ for (var ndx = 0; ndx < numAccurateBits.length; ndx++)
+ res[ndx] = tcuTexVerifierUtil.computeFixedPointError(numAccurateBits[ndx]);
+ return res;
+ };
+
+ /**
+ * @param {Array<number>} value
+ * @param {Array<number>} numAccurateBits
+ * @return {Array<number>}
+ */
+ tcuTexVerifierUtil.computeFloatingPointError_Vector = function(value, numAccurateBits) {
+ assertMsgOptions(value.length === numAccurateBits.length, '', false, true);
+ /** @type {Array<number>} */ var res = [];
+ for (var ndx = 0; ndx < value.length; ndx++)
+ res[ndx] = tcuTexVerifierUtil.computeFloatingPointError(value[ndx], numAccurateBits[ndx]);
+ return res;
+ };
+
+ // Sampler introspection
+
+ /**
+ * @param {tcuTexture.FilterMode} mode
+ * @return {boolean}
+ */
+ tcuTexVerifierUtil.isNearestMipmapFilter = function(mode) {
+ return mode == tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST || mode == tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST;
+ };
+
+ /**
+ * @param {tcuTexture.FilterMode} mode
+ * @return {boolean}
+ */
+ tcuTexVerifierUtil.isLinearMipmapFilter = function(mode) {
+ return mode == tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR || mode == tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR;
+ };
+
+ /**
+ * @param {tcuTexture.FilterMode} mode
+ * @return {boolean}
+ */
+ tcuTexVerifierUtil.isMipmapFilter = function(mode) {
+ return tcuTexVerifierUtil.isNearestMipmapFilter(mode) || tcuTexVerifierUtil.isLinearMipmapFilter(mode);
+ };
+
+ /**
+ * @param {tcuTexture.FilterMode} mode
+ * @return {boolean}
+ */
+ tcuTexVerifierUtil.isLinearFilter = function(mode) {
+ return mode == tcuTexture.FilterMode.LINEAR || mode == tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST || mode == tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR;
+ };
+
+ /**
+ * @param {tcuTexture.FilterMode} mode
+ * @return {boolean}
+ */
+ tcuTexVerifierUtil.isNearestFilter = function(mode) {
+ return !tcuTexVerifierUtil.isLinearFilter(mode);
+ };
+
+ /**
+ * @param {tcuTexture.FilterMode} mode
+ * @return {tcuTexture.FilterMode}
+ */
+ tcuTexVerifierUtil.getLevelFilter = function(mode) {
+ return tcuTexVerifierUtil.isLinearFilter(mode) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
+ };
+
+ /**
+ * @param {tcuTexture.WrapMode} mode
+ * @return {boolean}
+ */
+ tcuTexVerifierUtil.isWrapModeSupported = function(mode) {
+ return mode != tcuTexture.WrapMode.MIRRORED_REPEAT_CL && mode != tcuTexture.WrapMode.REPEAT_CL;
+ };
+
+ /**
+ *
+ * @param {boolean} normalizedCoords
+ * @param {number} dim
+ * @param {number} coord
+ * @param {number} coordBits
+ * @param {number} uvBits
+ * @return {Array<number>}
+ */
+ tcuTexVerifierUtil.computeNonNormalizedCoordBounds = function(normalizedCoords, dim, coord, coordBits, uvBits) {
+ /** @type {number} */ var coordErr = tcuTexVerifierUtil.computeFloatingPointError(coord, coordBits);
+ /** @type {number} */ var minN = coord - coordErr;
+ /** @type {number} */ var maxN = coord + coordErr;
+ /** @type {number} */ var minA = normalizedCoords ? minN * dim : minN;
+ /** @type {number} */ var maxA = normalizedCoords ? maxN * dim : maxN;
+ /** @type {number} */ var minC = minA - tcuTexVerifierUtil.computeFixedPointError(uvBits);
+ /** @type {number} */ var maxC = maxA + tcuTexVerifierUtil.computeFixedPointError(uvBits);
+ assertMsgOptions(minC <= maxC, '', false, true);
+ return [minC, maxC];
+ };
+
+ /**
+ * @param {Array<number>} coord
+ * @param {Array<number>} bits
+ * @return {?Array<tcuTexture.CubeFace>}
+ */
+ tcuTexVerifierUtil.getPossibleCubeFaces = function(coord, bits) {
+
+ /** @type {Array<tcuTexture.CubeFace>} */ var faces = [];
+
+ /** @type {number} */ var x = coord[0];
+ /** @type {number} */ var y = coord[1];
+ /** @type {number} */ var z = coord[2];
+ /** @type {number} */ var ax = Math.abs(x);
+ /** @type {number} */ var ay = Math.abs(y);
+ /** @type {number} */ var az = Math.abs(z);
+ /** @type {number} */ var ex = tcuTexVerifierUtil.computeFloatingPointError(x, bits[0]);
+ /** @type {number} */ var ey = tcuTexVerifierUtil.computeFloatingPointError(y, bits[1]);
+ /** @type {number} */ var ez = tcuTexVerifierUtil.computeFloatingPointError(z, bits[2]);
+ /** @type {number} */ var numFaces = 0;
+
+ if (ay + ey < ax - ex && az + ez < ax - ex) {
+ if (x >= ex) faces.push(tcuTexture.CubeFace.CUBEFACE_POSITIVE_X);
+ if (x <= ex) faces.push(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X);
+ } else if (ax + ex < ay - ey && az + ez < ay - ey) {
+ if (y >= ey) faces.push(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y);
+ if (y <= ey) faces.push(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y);
+ } else if (ax + ex < az - ez && ay + ey < az - ez) {
+ if (z >= ez) faces.push(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z);
+ if (z <= ez) faces.push(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z);
+ } else {
+ // One or more components are equal (or within error bounds). Allow all faces where major axis is not zero.
+ if (ax > ex) {
+ faces.push(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X);
+ faces.push(tcuTexture.CubeFace.CUBEFACE_POSITIVE_X);
+ }
+
+ if (ay > ey) {
+ faces.push(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y);
+ faces.push(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y);
+ }
+
+ if (az > ez) {
+ faces.push(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z);
+ faces.push(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z);
+ }
+ }
+
+ return faces.length == 0 ? null : faces;
+ };
+
+ /**
+ * @param {tcuTexture.Sampler} sampler
+ * @return {tcuTexture.Sampler}
+ */
+ tcuTexVerifierUtil.getUnnormalizedCoordSampler = function(sampler) {
+ var copy = /** @type {tcuTexture.Sampler} */ (deUtil.clone(sampler));
+ copy.normalizedCoords = false;
+ return copy;
+ };
+
+ /**
+ * @param {number} a
+ * @param {number} b
+ * @return {number}
+ */
+ tcuTexVerifierUtil.imod = function(a, b) {
+ return deMath.imod(a, b);
+ };
+
+ /**
+ * @param {number} a
+ * @return {number}
+ */
+ tcuTexVerifierUtil.mirror = function(a) {
+ return deMath.mirror(a);
+ };
+
+ /**
+ * @param {tcuTexture.WrapMode} mode
+ * @param {number} c
+ * @param {number} size
+ * @return {number}
+ */
+ tcuTexVerifierUtil.wrap = function(mode, c, size) {
+ switch (mode) {
+ // \note CL and GL modes are handled identically here, as verification process accounts for
+ // accuracy differences caused by different methods (wrapping vs. denormalizing first).
+ case tcuTexture.WrapMode.CLAMP_TO_EDGE:
+ return deMath.clamp(c, 0, size - 1);
+
+ case tcuTexture.WrapMode.REPEAT_GL:
+ case tcuTexture.WrapMode.REPEAT_CL:
+ return deMath.imod(c, size);
+
+ case tcuTexture.WrapMode.MIRRORED_REPEAT_GL:
+ case tcuTexture.WrapMode.MIRRORED_REPEAT_CL:
+ return (size - 1) - deMath.mirror(deMath.imod(c, 2 * size) - size);
+
+ default:
+ throw new Error('Wrap mode not supported.');
+ }
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexture.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexture.js
new file mode 100644
index 0000000000..8a3a2ed1d4
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTexture.js
@@ -0,0 +1,3636 @@
+/*-------------------------------------------------------------------------
+ * 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.common.tcuTexture');
+goog.require('framework.common.tcuFloat');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.delibs.debase.deString');
+goog.require('framework.delibs.debase.deUtil');
+
+goog.scope(function() {
+
+var tcuTexture = framework.common.tcuTexture;
+var deMath = framework.delibs.debase.deMath;
+var tcuFloat = framework.common.tcuFloat;
+var deString = framework.delibs.debase.deString;
+var deUtil = framework.delibs.debase.deUtil;
+
+var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+};
+
+/**
+ * Texture tcuTexture.channel order
+ * @enum
+ */
+tcuTexture.ChannelOrder = {
+ R: 0,
+ A: 1,
+ I: 2,
+ L: 3,
+ LA: 4,
+ RG: 5,
+ RA: 6,
+ RGB: 7,
+ RGBA: 8,
+ ARGB: 9,
+ BGRA: 10,
+
+ sRGB: 11,
+ sRGBA: 12,
+
+ D: 13,
+ S: 14,
+ DS: 15
+};
+
+/**
+ * Texture tcuTexture.channel type
+ * @enum
+ */
+tcuTexture.ChannelType = {
+ SNORM_INT8: 0,
+ SNORM_INT16: 1,
+ SNORM_INT32: 2,
+ UNORM_INT8: 3,
+ UNORM_INT16: 4,
+ UNORM_INT32: 5,
+ UNORM_SHORT_565: 6,
+ UNORM_SHORT_555: 7,
+ UNORM_SHORT_4444: 8,
+ UNORM_SHORT_5551: 9,
+ UNORM_INT_101010: 10,
+ UNORM_INT_1010102_REV: 11,
+ UNSIGNED_INT_1010102_REV: 12,
+ UNSIGNED_INT_11F_11F_10F_REV: 13,
+ UNSIGNED_INT_999_E5_REV: 14,
+ UNSIGNED_INT_24_8: 15,
+ SIGNED_INT8: 16,
+ SIGNED_INT16: 17,
+ SIGNED_INT32: 18,
+ UNSIGNED_INT8: 19,
+ UNSIGNED_INT16: 20,
+ UNSIGNED_INT32: 21,
+ HALF_FLOAT: 22,
+ FLOAT: 23,
+ FLOAT_UNSIGNED_INT_24_8_REV: 24
+};
+
+/**
+ * Enums for tcuTexture.TextureChannelClass
+ * @enum {number}
+ */
+tcuTexture.TextureChannelClass = {
+
+ SIGNED_FIXED_POINT: 0,
+ UNSIGNED_FIXED_POINT: 1,
+ SIGNED_INTEGER: 2,
+ UNSIGNED_INTEGER: 3,
+ FLOATING_POINT: 4
+};
+
+/**
+ * @param {?tcuTexture.ChannelType} channelType
+ * @return {tcuTexture.TextureChannelClass}
+ */
+tcuTexture.getTextureChannelClass = function(channelType) {
+
+ switch (channelType) {
+ case tcuTexture.ChannelType.SNORM_INT8: return tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT;
+ case tcuTexture.ChannelType.SNORM_INT16: return tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT;
+ case tcuTexture.ChannelType.UNORM_INT8: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
+ case tcuTexture.ChannelType.UNORM_INT16: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
+ case tcuTexture.ChannelType.UNORM_SHORT_565: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
+ case tcuTexture.ChannelType.UNORM_SHORT_555: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
+ case tcuTexture.ChannelType.UNORM_SHORT_4444: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
+ case tcuTexture.ChannelType.UNORM_SHORT_5551: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
+ case tcuTexture.ChannelType.UNORM_INT_101010: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
+ case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT;
+ case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return tcuTexture.TextureChannelClass.UNSIGNED_INTEGER;
+ case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: return tcuTexture.TextureChannelClass.FLOATING_POINT;
+ case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return tcuTexture.TextureChannelClass.FLOATING_POINT;
+ case tcuTexture.ChannelType.SIGNED_INT8: return tcuTexture.TextureChannelClass.SIGNED_INTEGER;
+ case tcuTexture.ChannelType.SIGNED_INT16: return tcuTexture.TextureChannelClass.SIGNED_INTEGER;
+ case tcuTexture.ChannelType.SIGNED_INT32: return tcuTexture.TextureChannelClass.SIGNED_INTEGER;
+ case tcuTexture.ChannelType.UNSIGNED_INT8: return tcuTexture.TextureChannelClass.UNSIGNED_INTEGER;
+ case tcuTexture.ChannelType.UNSIGNED_INT16: return tcuTexture.TextureChannelClass.UNSIGNED_INTEGER;
+ case tcuTexture.ChannelType.UNSIGNED_INT32: return tcuTexture.TextureChannelClass.UNSIGNED_INTEGER;
+ case tcuTexture.ChannelType.HALF_FLOAT: return tcuTexture.TextureChannelClass.FLOATING_POINT;
+ case tcuTexture.ChannelType.FLOAT: return tcuTexture.TextureChannelClass.FLOATING_POINT;
+ default: return /** @type {tcuTexture.TextureChannelClass<number>} */ (Object.keys(tcuTexture.ChannelType).length);
+ }
+};
+
+/**
+ * @param {tcuTexture.TextureFormat} format
+ */
+tcuTexture.isFixedPointDepthTextureFormat = function(format) {
+ var channelClass = tcuTexture.getTextureChannelClass(format.type);
+
+ if (format.order == tcuTexture.ChannelOrder.D) {
+ // depth internal formats cannot be non-normalized integers
+ return channelClass != tcuTexture.TextureChannelClass.FLOATING_POINT;
+ } else if (format.order == tcuTexture.ChannelOrder.DS) {
+ // combined formats have no single channel class, detect format manually
+ switch (format.type) {
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: return false;
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8: return true;
+
+ default:
+ // unknown format
+ DE_ASSERT(false);
+ return true;
+ }
+ }
+ return false;
+};
+
+/**
+ * @param {Array<number>} color
+ * @param {tcuTexture.CompareMode} compare
+ * @param {number} chanNdx
+ * @param {number} ref_
+ * @param {boolean} isFixedPoint
+ */
+tcuTexture.execCompare = function(color, compare, chanNdx, ref_, isFixedPoint) {
+ var clampValues = isFixedPoint;
+ var cmp = clampValues ? deMath.clamp(color[chanNdx], 0.0, 1.0) : color[chanNdx];
+ var ref = clampValues ? deMath.clamp(ref_, 0.0, 1.0) : ref_;
+ var res = false;
+
+ switch (compare) {
+ case tcuTexture.CompareMode.COMPAREMODE_LESS: res = ref < cmp; break;
+ case tcuTexture.CompareMode.COMPAREMODE_LESS_OR_EQUAL: res = ref <= cmp; break;
+ case tcuTexture.CompareMode.COMPAREMODE_GREATER: res = ref > cmp; break;
+ case tcuTexture.CompareMode.COMPAREMODE_GREATER_OR_EQUAL: res = ref >= cmp; break;
+ case tcuTexture.CompareMode.COMPAREMODE_EQUAL: res = ref == cmp; break;
+ case tcuTexture.CompareMode.COMPAREMODE_NOT_EQUAL: res = ref != cmp; break;
+ case tcuTexture.CompareMode.COMPAREMODE_ALWAYS: res = true; break;
+ case tcuTexture.CompareMode.COMPAREMODE_NEVER: res = false; break;
+ default:
+ DE_ASSERT(false);
+ }
+
+ return res ? 1.0 : 0.0;
+};
+
+/**
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
+ * @param {number} numLevels
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} ref
+ * @param {number} s
+ * @param {number} t
+ * @param {number} lod
+ * @param {Array<number>} offset
+ */
+tcuTexture.sampleLevelArray2DCompare = function(levels, numLevels, sampler, ref, s, t, lod, offset) {
+ var magnified = lod <= sampler.lodThreshold;
+ var filterMode = magnified ? sampler.magFilter : sampler.minFilter;
+
+ switch (filterMode) {
+ case tcuTexture.FilterMode.NEAREST: return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset);
+ case tcuTexture.FilterMode.LINEAR: return levels[0].sample2DCompare(sampler, filterMode, ref, s, t, offset);
+
+ case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST:
+ case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: {
+ var maxLevel = numLevels - 1;
+ var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel);
+ var levelFilter = filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
+
+ return levels[level].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
+ }
+
+ case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR:
+ case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: {
+ var maxLevel = numLevels - 1;
+ var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel);
+ var level1 = Math.min(maxLevel, level0 + 1);
+ var levelFilter = filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
+ var f = deMath.deFloatFrac(lod);
+ var t0 = levels[level0].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
+ var t1 = levels[level1].sample2DCompare(sampler, levelFilter, ref, s, t, offset);
+
+ return t0 * (1.0 - f) + t1 * f;
+ }
+
+ default:
+ DE_ASSERT(false);
+ return 0.0;
+ }
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} ref
+ * @param {number} u
+ * @param {number} v
+ * @param {Array<number>} offset
+ * @param {boolean} isFixedPointDepthFormat
+ * @return {number}
+ */
+tcuTexture.sampleLinear2DCompare = function(access, sampler, ref, u, v, offset, isFixedPointDepthFormat) {
+ var w = access.getWidth();
+ var h = access.getHeight();
+
+ var x0 = Math.floor(u - 0.5) + offset[0];
+ var x1 = x0 + 1;
+ var y0 = Math.floor(v - 0.5) + offset[1];
+ var y1 = y0 + 1;
+
+ var i0 = tcuTexture.wrap(sampler.wrapS, x0, w);
+ var i1 = tcuTexture.wrap(sampler.wrapS, x1, w);
+ var j0 = tcuTexture.wrap(sampler.wrapT, y0, h);
+ var j1 = tcuTexture.wrap(sampler.wrapT, y1, h);
+
+ var a = deMath.deFloatFrac(u - 0.5);
+ var b = deMath.deFloatFrac(v - 0.5);
+
+ var i0UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i0, 0, w);
+ var i1UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i1, 0, w);
+ var j0UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j0, 0, h);
+ var j1UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j1, 0, h);
+
+ // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
+ var p00Clr = (i0UseBorder || j0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j0, offset[2]);
+ var p10Clr = (i1UseBorder || j0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j0, offset[2]);
+ var p01Clr = (i0UseBorder || j1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j1, offset[2]);
+ var p11Clr = (i1UseBorder || j1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j1, offset[2]);
+
+ // Execute comparisons.
+ var p00 = tcuTexture.execCompare(p00Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
+ var p10 = tcuTexture.execCompare(p10Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
+ var p01 = tcuTexture.execCompare(p01Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
+ var p11 = tcuTexture.execCompare(p11Clr, sampler.compare, sampler.compareChannel, ref, isFixedPointDepthFormat);
+
+ // Interpolate.
+ return (p00 * (1.0 - a) * (1.0 - b)) +
+ (p10 * (a) * (1.0 - b)) +
+ (p01 * (1.0 - a) * (b)) +
+ (p11 * (a) * (b));
+};
+
+/**
+ * Construct texture format
+ * @param {?tcuTexture.ChannelOrder} order
+ * @param {?tcuTexture.ChannelType} type
+ *
+ * @constructor
+ */
+tcuTexture.TextureFormat = function(order, type) {
+ this.order = order;
+ this.type = type;
+};
+
+/**
+ * Compare two formats
+ * @param {tcuTexture.TextureFormat} format Format to compare with
+ * @return {boolean}
+ */
+tcuTexture.TextureFormat.prototype.isEqual = function(format) {
+ return this.order === format.order && this.type === format.type;
+};
+
+tcuTexture.TextureFormat.prototype.toString = function() {
+ return 'TextureFormat(' + deString.enumToString(tcuTexture.ChannelOrder, this.order) + ', ' +
+ deString.enumToString(tcuTexture.ChannelType, this.type) + ')';
+};
+
+/**
+ * Is format sRGB?
+ * @return {boolean}
+ */
+tcuTexture.TextureFormat.prototype.isSRGB = function() {
+ return this.order === tcuTexture.ChannelOrder.sRGB || this.order === tcuTexture.ChannelOrder.sRGBA;
+};
+
+tcuTexture.TextureFormat.prototype.getNumStencilBits = function() {
+ switch (this.order) {
+ case tcuTexture.ChannelOrder.S:
+ switch (this.type) {
+ case tcuTexture.ChannelType.UNSIGNED_INT8: return 8;
+ case tcuTexture.ChannelType.UNSIGNED_INT16: return 16;
+ case tcuTexture.ChannelType.UNSIGNED_INT32: return 32;
+ default:
+ throw new Error('Wrong type: ' + this.type);
+ }
+
+ case tcuTexture.ChannelOrder.DS:
+ switch (this.type) {
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8: return 8;
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: return 8;
+ default:
+ throw new Error('Wrong type: ' + this.type);
+ }
+
+ default:
+ throw new Error('Wrong order: ' + this.order);
+ }
+};
+
+/**
+ * Get TypedArray type that can be used to access texture.
+ * @param {?tcuTexture.ChannelType} type
+ * @return TypedArray that supports the tcuTexture.channel type.
+ */
+tcuTexture.getTypedArray = function(type) {
+ switch (type) {
+ case tcuTexture.ChannelType.SNORM_INT8: return Int8Array;
+ case tcuTexture.ChannelType.SNORM_INT16: return Int16Array;
+ case tcuTexture.ChannelType.SNORM_INT32: return Int32Array;
+ case tcuTexture.ChannelType.UNORM_INT8: return Uint8Array;
+ case tcuTexture.ChannelType.UNORM_INT16: return Uint16Array;
+ case tcuTexture.ChannelType.UNORM_INT32: return Uint32Array;
+ case tcuTexture.ChannelType.UNORM_SHORT_565: return Uint16Array;
+ case tcuTexture.ChannelType.UNORM_SHORT_555: return Uint16Array;
+ case tcuTexture.ChannelType.UNORM_SHORT_4444: return Uint16Array;
+ case tcuTexture.ChannelType.UNORM_SHORT_5551: return Uint16Array;
+ case tcuTexture.ChannelType.UNORM_INT_101010: return Uint32Array;
+ case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return Uint32Array;
+ case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return Uint32Array;
+ case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: return Uint32Array;
+ case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return Uint32Array;
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8: return Uint32Array;
+ case tcuTexture.ChannelType.FLOAT: return Float32Array;
+ case tcuTexture.ChannelType.SIGNED_INT8: return Int8Array;
+ case tcuTexture.ChannelType.SIGNED_INT16: return Int16Array;
+ case tcuTexture.ChannelType.SIGNED_INT32: return Int32Array;
+ case tcuTexture.ChannelType.UNSIGNED_INT8: return Uint8Array;
+ case tcuTexture.ChannelType.UNSIGNED_INT16: return Uint16Array;
+ case tcuTexture.ChannelType.UNSIGNED_INT32: return Uint32Array;
+ case tcuTexture.ChannelType.HALF_FLOAT: return Uint16Array;
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: return Float32Array; /* this type is a special case */
+ }
+
+ throw new Error('Unrecognized type ' + type);
+};
+
+/**
+ * @return {number} pixel size in bytes
+ */
+tcuTexture.TextureFormat.prototype.getPixelSize = function() {
+ if (this.type == null || this.order == null) {
+ // Invalid/empty format.
+ return 0;
+ } else if (this.type == tcuTexture.ChannelType.UNORM_SHORT_565 ||
+ this.type == tcuTexture.ChannelType.UNORM_SHORT_555 ||
+ this.type == tcuTexture.ChannelType.UNORM_SHORT_4444 ||
+ this.type == tcuTexture.ChannelType.UNORM_SHORT_5551) {
+ DE_ASSERT(this.order == tcuTexture.ChannelOrder.RGB || this.order == tcuTexture.ChannelOrder.RGBA);
+ return 2;
+ } else if (this.type == tcuTexture.ChannelType.UNORM_INT_101010 ||
+ this.type == tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV ||
+ this.type == tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV) {
+ DE_ASSERT(this.order == tcuTexture.ChannelOrder.RGB);
+ return 4;
+ } else if (this.type == tcuTexture.ChannelType.UNORM_INT_1010102_REV ||
+ this.type == tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV) {
+ DE_ASSERT(this.order == tcuTexture.ChannelOrder.RGBA);
+ return 4;
+ } else if (this.type == tcuTexture.ChannelType.UNSIGNED_INT_24_8) {
+ DE_ASSERT(this.order == tcuTexture.ChannelOrder.D || this.order == tcuTexture.ChannelOrder.DS);
+ return 4;
+ } else if (this.type == tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV) {
+ DE_ASSERT(this.order == tcuTexture.ChannelOrder.DS);
+ return 8;
+ } else {
+ var numChannels;
+ var channelSize;
+
+ switch (this.order) {
+ case tcuTexture.ChannelOrder.R: numChannels = 1; break;
+ case tcuTexture.ChannelOrder.A: numChannels = 1; break;
+ case tcuTexture.ChannelOrder.I: numChannels = 1; break;
+ case tcuTexture.ChannelOrder.L: numChannels = 1; break;
+ case tcuTexture.ChannelOrder.LA: numChannels = 2; break;
+ case tcuTexture.ChannelOrder.RG: numChannels = 2; break;
+ case tcuTexture.ChannelOrder.RA: numChannels = 2; break;
+ case tcuTexture.ChannelOrder.RGB: numChannels = 3; break;
+ case tcuTexture.ChannelOrder.RGBA: numChannels = 4; break;
+ case tcuTexture.ChannelOrder.ARGB: numChannels = 4; break;
+ case tcuTexture.ChannelOrder.BGRA: numChannels = 4; break;
+ case tcuTexture.ChannelOrder.sRGB: numChannels = 3; break;
+ case tcuTexture.ChannelOrder.sRGBA: numChannels = 4; break;
+ case tcuTexture.ChannelOrder.D: numChannels = 1; break;
+ case tcuTexture.ChannelOrder.S: numChannels = 1; break;
+ case tcuTexture.ChannelOrder.DS: numChannels = 2; break;
+ default: DE_ASSERT(false);
+ }
+
+ switch (this.type) {
+ case tcuTexture.ChannelType.SNORM_INT8: channelSize = 1; break;
+ case tcuTexture.ChannelType.SNORM_INT16: channelSize = 2; break;
+ case tcuTexture.ChannelType.SNORM_INT32: channelSize = 4; break;
+ case tcuTexture.ChannelType.UNORM_INT8: channelSize = 1; break;
+ case tcuTexture.ChannelType.UNORM_INT16: channelSize = 2; break;
+ case tcuTexture.ChannelType.UNORM_INT32: channelSize = 4; break;
+ case tcuTexture.ChannelType.SIGNED_INT8: channelSize = 1; break;
+ case tcuTexture.ChannelType.SIGNED_INT16: channelSize = 2; break;
+ case tcuTexture.ChannelType.SIGNED_INT32: channelSize = 4; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT8: channelSize = 1; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT16: channelSize = 2; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT32: channelSize = 4; break;
+ case tcuTexture.ChannelType.HALF_FLOAT: channelSize = 2; break;
+ case tcuTexture.ChannelType.FLOAT: channelSize = 4; break;
+ default: DE_ASSERT(false);
+ }
+
+ return numChannels * channelSize;
+ }
+};
+
+/**
+ * @enum
+ */
+tcuTexture.CubeFace = {
+ CUBEFACE_NEGATIVE_X: 0,
+ CUBEFACE_POSITIVE_X: 1,
+ CUBEFACE_NEGATIVE_Y: 2,
+ CUBEFACE_POSITIVE_Y: 3,
+ CUBEFACE_NEGATIVE_Z: 4,
+ CUBEFACE_POSITIVE_Z: 5
+};
+
+/**
+ * Renamed from ArrayBuffer due to name clash
+ * Wraps ArrayBuffer.
+ * @constructor
+ * @param {number=} numElements
+ */
+tcuTexture.DeqpArrayBuffer = function(numElements) {
+ if (numElements)
+ this.m_ptr = new ArrayBuffer(numElements);
+};
+
+/**
+ * Set array size
+ * @param {number} numElements Size in bytes
+ */
+tcuTexture.DeqpArrayBuffer.prototype.setStorage = function(numElements) {
+ this.m_ptr = new ArrayBuffer(numElements);
+};
+
+/**
+ * @return {number} Buffer size
+ */
+tcuTexture.DeqpArrayBuffer.prototype.size = function() {
+ if (this.m_ptr)
+ return this.m_ptr.byteLength;
+
+ return 0;
+};
+
+/**
+ * Is the buffer empty (zero size)?
+ * @return {boolean}
+ */
+tcuTexture.DeqpArrayBuffer.prototype.empty = function() {
+ if (!this.m_ptr)
+ return true;
+ return this.size() == 0;
+};
+
+/**
+ * @enum
+ * The values are negative to avoid conflict with channels 0 - 3
+ */
+tcuTexture.channel = {
+ ZERO: -1,
+ ONE: -2
+};
+
+/**
+ * @param {tcuTexture.ChannelOrder} order
+ * @return {Array<Number|tcuTexture.channel>}
+ */
+tcuTexture.getChannelReadMap = function(order) {
+ switch (order) {
+ /*static const Channel INV[] = { tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ONE }; */
+
+ case tcuTexture.ChannelOrder.R: return [0, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ONE];
+ case tcuTexture.ChannelOrder.A: return [tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, 0];
+ case tcuTexture.ChannelOrder.I: return [0, 0, 0, 0];
+ case tcuTexture.ChannelOrder.L: return [0, 0, 0, tcuTexture.channel.ONE];
+ case tcuTexture.ChannelOrder.LA: return [0, 0, 0, 1];
+ case tcuTexture.ChannelOrder.RG: return [0, 1, tcuTexture.channel.ZERO, tcuTexture.channel.ONE];
+ case tcuTexture.ChannelOrder.RA: return [0, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, 1];
+ case tcuTexture.ChannelOrder.RGB: return [0, 1, 2, tcuTexture.channel.ONE];
+ case tcuTexture.ChannelOrder.RGBA: return [0, 1, 2, 3];
+ case tcuTexture.ChannelOrder.BGRA: return [2, 1, 0, 3];
+ case tcuTexture.ChannelOrder.ARGB: return [1, 2, 3, 0];
+ case tcuTexture.ChannelOrder.sRGB: return [0, 1, 2, tcuTexture.channel.ONE];
+ case tcuTexture.ChannelOrder.sRGBA: return [0, 1, 2, 3];
+ case tcuTexture.ChannelOrder.D: return [0, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ONE];
+ case tcuTexture.ChannelOrder.S: return [tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, 0];
+ case tcuTexture.ChannelOrder.DS: return [0, tcuTexture.channel.ZERO, tcuTexture.channel.ZERO, 1];
+ }
+
+ throw new Error('Unrecognized order ' + order);
+};
+
+/**
+ * @param {tcuTexture.ChannelOrder} order
+ * @return {Array<number>}
+ */
+tcuTexture.getChannelWriteMap = function(order) {
+ switch (order) {
+ case tcuTexture.ChannelOrder.R: return [0];
+ case tcuTexture.ChannelOrder.A: return [3];
+ case tcuTexture.ChannelOrder.I: return [0];
+ case tcuTexture.ChannelOrder.L: return [0];
+ case tcuTexture.ChannelOrder.LA: return [0, 3];
+ case tcuTexture.ChannelOrder.RG: return [0, 1];
+ case tcuTexture.ChannelOrder.RA: return [0, 3];
+ case tcuTexture.ChannelOrder.RGB: return [0, 1, 2];
+ case tcuTexture.ChannelOrder.RGBA: return [0, 1, 2, 3];
+ case tcuTexture.ChannelOrder.ARGB: return [3, 0, 1, 2];
+ case tcuTexture.ChannelOrder.BGRA: return [2, 1, 0, 3];
+ case tcuTexture.ChannelOrder.sRGB: return [0, 1, 2];
+ case tcuTexture.ChannelOrder.sRGBA: return [0, 1, 2, 3];
+ case tcuTexture.ChannelOrder.D: return [0];
+ case tcuTexture.ChannelOrder.S: return [3];
+ case tcuTexture.ChannelOrder.DS: return [0, 3];
+ }
+ throw new Error('Unrecognized order ' + order);
+};
+
+/**
+ * @param {tcuTexture.ChannelType} type
+ * @return {number}
+ */
+tcuTexture.getChannelSize = function(type) {
+ switch (type) {
+ case tcuTexture.ChannelType.SNORM_INT8: return 1;
+ case tcuTexture.ChannelType.SNORM_INT16: return 2;
+ case tcuTexture.ChannelType.SNORM_INT32: return 4;
+ case tcuTexture.ChannelType.UNORM_INT8: return 1;
+ case tcuTexture.ChannelType.UNORM_INT16: return 2;
+ case tcuTexture.ChannelType.UNORM_INT32: return 4;
+ case tcuTexture.ChannelType.SIGNED_INT8: return 1;
+ case tcuTexture.ChannelType.SIGNED_INT16: return 2;
+ case tcuTexture.ChannelType.SIGNED_INT32: return 4;
+ case tcuTexture.ChannelType.UNSIGNED_INT8: return 1;
+ case tcuTexture.ChannelType.UNSIGNED_INT16: return 2;
+ case tcuTexture.ChannelType.UNSIGNED_INT32: return 4;
+ case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: return 4;
+ case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return 4;
+ case tcuTexture.ChannelType.HALF_FLOAT: return 2;
+ case tcuTexture.ChannelType.FLOAT: return 4;
+
+ }
+ throw new Error('Unrecognized type ' + deString.enumToString(tcuTexture.ChannelType, type));
+};
+
+/**
+ * @param {number} src Source value
+ * @param {number} bits Source value size in bits
+ * @return {number} Normalized value
+ */
+tcuTexture.channelToNormFloat = function(src, bits) {
+ var maxVal = (1 << bits) - 1;
+ return src / maxVal;
+};
+
+/**
+ * @param {number} value Source value
+ * @param {tcuTexture.ChannelType} type
+ * @return {number} Source value converted to float
+ */
+tcuTexture.channelToFloat = function(value, type) {
+ switch (type) {
+ case tcuTexture.ChannelType.SNORM_INT8: return Math.max(-1, value / 127);
+ case tcuTexture.ChannelType.SNORM_INT16: return Math.max(-1, value / 32767);
+ case tcuTexture.ChannelType.SNORM_INT32: return Math.max(-1, value / 2147483647);
+ case tcuTexture.ChannelType.UNORM_INT8: return value / 255;
+ case tcuTexture.ChannelType.UNORM_INT16: return value / 65535;
+ case tcuTexture.ChannelType.UNORM_INT32: return value / 4294967295;
+ case tcuTexture.ChannelType.SIGNED_INT8: return value;
+ case tcuTexture.ChannelType.SIGNED_INT16: return value;
+ case tcuTexture.ChannelType.SIGNED_INT32: return value;
+ case tcuTexture.ChannelType.UNSIGNED_INT8: return value;
+ case tcuTexture.ChannelType.UNSIGNED_INT16: return value;
+ case tcuTexture.ChannelType.UNSIGNED_INT32: return value;
+ case tcuTexture.ChannelType.HALF_FLOAT: return tcuFloat.halfFloatToNumber(value);
+ case tcuTexture.ChannelType.FLOAT: return value;
+ }
+ throw new Error('Unrecognized tcuTexture.channel type ' + type);
+};
+
+/**
+ * @param {number} value Source value
+ * @param {tcuTexture.ChannelType} type
+ * @return {number} Source value converted to int
+ */
+tcuTexture.channelToInt = function(value, type) {
+ switch (type) {
+ case tcuTexture.ChannelType.HALF_FLOAT: return Math.round(tcuFloat.halfFloatToNumber(value));
+ case tcuTexture.ChannelType.FLOAT: return Math.round(value);
+ default:
+ return value;
+ }
+};
+
+/**
+ * @param {tcuTexture.ChannelOrder} order
+ * @return {number}
+ */
+tcuTexture.getNumUsedChannels = function(order) {
+ switch (order) {
+ case tcuTexture.ChannelOrder.R: return 1;
+ case tcuTexture.ChannelOrder.A: return 1;
+ case tcuTexture.ChannelOrder.I: return 1;
+ case tcuTexture.ChannelOrder.L: return 1;
+ case tcuTexture.ChannelOrder.LA: return 2;
+ case tcuTexture.ChannelOrder.RG: return 2;
+ case tcuTexture.ChannelOrder.RA: return 2;
+ case tcuTexture.ChannelOrder.RGB: return 3;
+ case tcuTexture.ChannelOrder.RGBA: return 4;
+ case tcuTexture.ChannelOrder.ARGB: return 4;
+ case tcuTexture.ChannelOrder.BGRA: return 4;
+ case tcuTexture.ChannelOrder.sRGB: return 3;
+ case tcuTexture.ChannelOrder.sRGBA: return 4;
+ case tcuTexture.ChannelOrder.D: return 1;
+ case tcuTexture.ChannelOrder.S: return 1;
+ case tcuTexture.ChannelOrder.DS: return 2;
+ }
+ throw new Error('Unrecognized tcuTexture.channel order ' + order);
+};
+
+/**
+ * @enum
+ */
+tcuTexture.WrapMode = {
+ CLAMP_TO_EDGE: 0, //! Clamp to edge
+ CLAMP_TO_BORDER: 1, //! Use border color at edge
+ REPEAT_GL: 2, //! Repeat with OpenGL semantics
+ REPEAT_CL: 3, //! Repeat with OpenCL semantics
+ MIRRORED_REPEAT_GL: 4, //! Mirrored repeat with OpenGL semantics
+ MIRRORED_REPEAT_CL: 5 //! Mirrored repeat with OpenCL semantics
+};
+
+/**
+ * @enum
+ */
+tcuTexture.FilterMode = {
+ NEAREST: 0,
+ LINEAR: 1,
+
+ NEAREST_MIPMAP_NEAREST: 2,
+ NEAREST_MIPMAP_LINEAR: 3,
+ LINEAR_MIPMAP_NEAREST: 4,
+ LINEAR_MIPMAP_LINEAR: 5
+};
+
+/**
+ * @enum
+ */
+tcuTexture.CompareMode = {
+ COMPAREMODE_NONE: 0,
+ COMPAREMODE_LESS: 1,
+ COMPAREMODE_LESS_OR_EQUAL: 2,
+ COMPAREMODE_GREATER: 3,
+ COMPAREMODE_GREATER_OR_EQUAL: 4,
+ COMPAREMODE_EQUAL: 5,
+ COMPAREMODE_NOT_EQUAL: 6,
+ COMPAREMODE_ALWAYS: 7,
+ COMPAREMODE_NEVER: 8
+};
+
+/**
+ * @constructor
+ * @param {!tcuTexture.WrapMode} wrapS
+ * @param {!tcuTexture.WrapMode} wrapT
+ * @param {!tcuTexture.WrapMode} wrapR
+ * @param {!tcuTexture.FilterMode} minFilter
+ * @param {!tcuTexture.FilterMode} magFilter
+ * @param {number=} lodThreshold
+ * @param {boolean=} normalizedCoords
+ * @param {tcuTexture.CompareMode=} compare
+ * @param {number=} compareChannel
+ * @param {Array<number>=} borderColor
+ * @param {boolean=} seamlessCubeMap
+ */
+tcuTexture.Sampler = function(wrapS, wrapT, wrapR, minFilter, magFilter, lodThreshold, normalizedCoords, compare, compareChannel, borderColor, seamlessCubeMap) {
+ /** @type {!tcuTexture.WrapMode} */ this.wrapS = wrapS;
+ /** @type {!tcuTexture.WrapMode} */ this.wrapT = wrapT;
+ /** @type {!tcuTexture.WrapMode} */ this.wrapR = wrapR;
+ /** @type {!tcuTexture.FilterMode} */ this.minFilter = minFilter;
+ /** @type {!tcuTexture.FilterMode} */ this.magFilter = magFilter;
+ this.lodThreshold = lodThreshold || 0;
+ this.normalizedCoords = normalizedCoords === undefined ? true : normalizedCoords;
+ /** @type {tcuTexture.CompareMode} */ this.compare = compare || tcuTexture.CompareMode.COMPAREMODE_NONE;
+ this.compareChannel = compareChannel || 0;
+ this.borderColor = borderColor || [0, 0, 0, 0];
+ this.seamlessCubeMap = seamlessCubeMap || false;
+};
+
+/**
+ * Special unnormalization for REPEAT_CL and MIRRORED_REPEAT_CL tcuTexture.wrap modes; otherwise ordinary unnormalization.
+ * @param {tcuTexture.WrapMode} mode
+ * @param {number} c Value to tcuTexture.unnormalize
+ * @param {number} size Unnormalized type size (integer)
+ * @return {number}
+ */
+tcuTexture.unnormalize = function(mode, c, size) {
+ switch (mode) {
+ case tcuTexture.WrapMode.CLAMP_TO_EDGE:
+ case tcuTexture.WrapMode.CLAMP_TO_BORDER:
+ case tcuTexture.WrapMode.REPEAT_GL:
+ case tcuTexture.WrapMode.MIRRORED_REPEAT_GL: // Fall-through (ordinary case).
+ return size * c;
+
+ case tcuTexture.WrapMode.REPEAT_CL:
+ return size * (c - Math.floor(c));
+
+ case tcuTexture.WrapMode.MIRRORED_REPEAT_CL:
+ return size * Math.abs(c - 2 * deMath.rint(0.5 * c));
+ }
+ throw new Error('Unrecognized tcuTexture.wrap mode ' + mode);
+};
+
+/**
+ * @param {tcuTexture.WrapMode} mode
+ * @param {number} c Source value (integer)
+ * @param {number} size Type size (integer)
+ * @return {number}
+ */
+tcuTexture.wrap = function(mode, c, size) {
+ switch (mode) {
+ case tcuTexture.WrapMode.CLAMP_TO_BORDER:
+ return deMath.clamp(c, -1, size);
+
+ case tcuTexture.WrapMode.CLAMP_TO_EDGE:
+ return deMath.clamp(c, 0, size - 1);
+
+ case tcuTexture.WrapMode.REPEAT_GL:
+ return deMath.imod(c, size);
+
+ case tcuTexture.WrapMode.REPEAT_CL:
+ return deMath.imod(c, size);
+
+ case tcuTexture.WrapMode.MIRRORED_REPEAT_GL:
+ return (size - 1) - deMath.mirror(deMath.imod(c, 2 * size) - size);
+
+ case tcuTexture.WrapMode.MIRRORED_REPEAT_CL:
+ return deMath.clamp(c, 0, size - 1); // \note Actual mirroring done already in unnormalization function.
+ }
+ throw new Error('Unrecognized tcuTexture.wrap mode ' + mode);
+};
+
+/**
+ * @param {number} cs
+ * @return {number}
+ */
+tcuTexture.sRGBChannelToLinear = function(cs) {
+ if (cs <= 0.04045)
+ return cs / 12.92;
+ else
+ return Math.pow((cs + 0.055) / 1.055, 2.4);
+};
+
+/**
+ * Convert sRGB to linear colorspace
+ * @param {Array<number>} cs Vec4
+ * @return {Array<number>} Vec4
+ */
+tcuTexture.sRGBToLinear = function(cs) {
+ return [
+ tcuTexture.sRGBChannelToLinear(cs[0]),
+ tcuTexture.sRGBChannelToLinear(cs[1]),
+ tcuTexture.sRGBChannelToLinear(cs[2]),
+ cs[3]
+ ];
+};
+
+/**
+ * Texel tcuTexture.lookup with color conversion.
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {number} i
+ * @param {number} j
+ * @param {number} k
+ * @return {Array<number>} Vec4 pixel color
+ */
+tcuTexture.lookup = function(access, i, j, k) {
+ var p = access.getPixel(i, j, k);
+ return access.getFormat().isSRGB() ? tcuTexture.sRGBToLinear(p) : p;
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} u
+ * @param {number} v
+ * @param {(number|Array<number>)} depthOrOffset depth (int) or offset (ivec3)
+ * @return {Array<number>} Vec4 pixel color
+ */
+tcuTexture.sampleLinear2D = function(access, sampler, u, v, depthOrOffset) {
+ /** @type {number} */ var xOffset = 0;
+ /** @type {number} */ var yOffset = 0;
+ /** @type {number} */ var value;
+ if (Array.isArray(depthOrOffset)) {
+ xOffset = depthOrOffset[0];
+ yOffset = depthOrOffset[1];
+ value = depthOrOffset[2];
+ } else {
+ value = /** @type {number} */ (depthOrOffset);
+ }
+
+ /**
+ * @param {Array<number>} p00
+ * @param {Array<number>} p10
+ * @param {Array<number>} p01
+ * @param {Array<number>} p11
+ * @param {number} a
+ * @param {number} b
+ */
+ var interpolateQuad = function(p00, p10, p01, p11, a, b) {
+ var s00 = (1 - a) * (1 - b);
+ var s10 = a * (1 - b);
+ var s01 = (1 - a) * b;
+ var s11 = a * b;
+
+ return [
+ (p00[0] * s00) + (p10[0] * s10) + (p01[0] * s01) + (p11[0] * s11),
+ (p00[1] * s00) + (p10[1] * s10) + (p01[1] * s01) + (p11[1] * s11),
+ (p00[2] * s00) + (p10[2] * s10) + (p01[2] * s01) + (p11[2] * s11),
+ (p00[3] * s00) + (p10[3] * s10) + (p01[3] * s01) + (p11[3] * s11)
+ ];
+ };
+
+ var w = access.getWidth();
+ var h = access.getHeight();
+
+ var x0 = Math.floor(u - 0.5) + xOffset;
+ var x1 = x0 + 1;
+ var y0 = Math.floor(v - 0.5) + yOffset;
+ var y1 = y0 + 1;
+
+ var i0 = tcuTexture.wrap(sampler.wrapS, x0, w);
+ var i1 = tcuTexture.wrap(sampler.wrapS, x1, w);
+ var j0 = tcuTexture.wrap(sampler.wrapT, y0, h);
+ var j1 = tcuTexture.wrap(sampler.wrapT, y1, h);
+
+ var a = deMath.deFloatFrac(u - 0.5);
+ var b = deMath.deFloatFrac(v - 0.5);
+
+ var i0UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i0, 0, w);
+ var i1UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i1, 0, w);
+ var j0UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j0, 0, h);
+ var j1UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j1, 0, h);
+
+ // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
+ var p00 = (i0UseBorder || j0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j0, value);
+ var p10 = (i1UseBorder || j0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j0, value);
+ var p01 = (i0UseBorder || j1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j1, value);
+ var p11 = (i1UseBorder || j1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j1, value);
+
+ // Interpolate.
+ return interpolateQuad(p00, p10, p01, p11, a, b);
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} u
+ * @param {number} v
+ * @param {number} w
+ * @param {Array<number>=} offset
+ * @return {Array<number>} Vec4 pixel color
+ */
+tcuTexture.sampleLinear3D = function(access, sampler, u, v, w, offset) {
+ /**
+ * @param {Array<number>} p000
+ * @param {Array<number>} p100
+ * @param {Array<number>} p010
+ * @param {Array<number>} p110
+ * @param {Array<number>} p001
+ * @param {Array<number>} p101
+ * @param {Array<number>} p011
+ * @param {Array<number>} p111
+ * @param {number} a
+ * @param {number} b
+ * @param {number} c
+ */
+ var interpolateCube = function(p000, p100, p010, p110, p001, p101, p011, p111, a, b, c) {
+ var s000 = (1 - a) * (1 - b) * (1 - c);
+ var s100 = a * (1 - b) * (1 - c);
+ var s010 = (1 - a) * b * (1 - c);
+ var s110 = a * b * (1 - c);
+ var s001 = (1 - a) * (1 - b) * c;
+ var s101 = a * (1 - b) * c;
+ var s011 = (1 - a) * b * c;
+ var s111 = a * b * c;
+
+ return [
+ (p000[0] * s000) + (p100[0] * s100) + (p010[0] * s010) + (p110[0] * s110) + (p001[0] * s001) + (p101[0] * s101) + (p011[0] * s011) + (p111[0] * s111),
+ (p000[1] * s000) + (p100[1] * s100) + (p010[1] * s010) + (p110[1] * s110) + (p001[1] * s001) + (p101[1] * s101) + (p011[1] * s011) + (p111[1] * s111),
+ (p000[2] * s000) + (p100[2] * s100) + (p010[2] * s010) + (p110[2] * s110) + (p001[2] * s001) + (p101[2] * s101) + (p011[2] * s011) + (p111[2] * s111),
+ (p000[3] * s000) + (p100[3] * s100) + (p010[3] * s010) + (p110[3] * s110) + (p001[3] * s001) + (p101[3] * s101) + (p011[3] * s011) + (p111[3] * s111)
+ ];
+ };
+
+ var width = access.getWidth();
+ var height = access.getHeight();
+ var depth = access.getDepth();
+
+ /** @type {number} */ var xOffset = 0;
+ /** @type {number} */ var yOffset = 0;
+ /** @type {number} */ var zOffset = 0;
+
+ if (offset !== undefined && offset.length === 3) {
+ xOffset = offset[0];
+ yOffset = offset[1];
+ zOffset = offset[2];
+ }
+
+ var x0 = Math.floor(u - 0.5) + xOffset;
+ var x1 = x0 + 1;
+ var y0 = Math.floor(v - 0.5) + yOffset;
+ var y1 = y0 + 1;
+ var z0 = Math.floor(w - 0.5) + zOffset;
+ var z1 = z0 + 1;
+
+ var i0 = tcuTexture.wrap(sampler.wrapS, x0, width);
+ var i1 = tcuTexture.wrap(sampler.wrapS, x1, width);
+ var j0 = tcuTexture.wrap(sampler.wrapT, y0, height);
+ var j1 = tcuTexture.wrap(sampler.wrapT, y1, height);
+ var k0 = tcuTexture.wrap(sampler.wrapR, z0, depth);
+ var k1 = tcuTexture.wrap(sampler.wrapR, z1, depth);
+
+ var a = deMath.deFloatFrac(u - 0.5);
+ var b = deMath.deFloatFrac(v - 0.5);
+ var c = deMath.deFloatFrac(w - 0.5);
+
+ var i0UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i0, 0, width);
+ var i1UseBorder = sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(i1, 0, width);
+ var j0UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j0, 0, height);
+ var j1UseBorder = sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(j1, 0, height);
+ var k0UseBorder = sampler.wrapR == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(k0, 0, depth);
+ var k1UseBorder = sampler.wrapR == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(k1, 0, depth);
+
+ // Border color for out-of-range coordinates if using CLAMP_TO_BORDER, otherwise execute lookups.
+ var p000 = (i0UseBorder || j0UseBorder || k0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j0, k0);
+ var p100 = (i1UseBorder || j0UseBorder || k0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j0, k0);
+ var p010 = (i0UseBorder || j1UseBorder || k0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j1, k0);
+ var p110 = (i1UseBorder || j1UseBorder || k0UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j1, k0);
+ var p001 = (i0UseBorder || j0UseBorder || k1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j0, k1);
+ var p101 = (i1UseBorder || j0UseBorder || k1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j0, k1);
+ var p011 = (i0UseBorder || j1UseBorder || k1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i0, j1, k1);
+ var p111 = (i1UseBorder || j1UseBorder || k1UseBorder) ? sampler.borderColor : tcuTexture.lookup(access, i1, j1, k1);
+
+ // Interpolate.
+ return interpolateCube(p000, p100, p010, p110, p001, p101, p011, p111, a, b, c);
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} u
+ * @param {number} v
+ * @param {(number|Array<number>)} depthOrOffset depth (integer) or offset (ivec3)
+ * @return {Array<number>} Vec4 pixel color
+ */
+tcuTexture.sampleNearest2D = function(access, sampler, u, v, depthOrOffset) {
+ /** @type {number} */ var xOffset = 0;
+ /** @type {number} */ var yOffset = 0;
+ /** @type {number} */ var value;
+ if (Array.isArray(depthOrOffset)) {
+ xOffset = depthOrOffset[0];
+ yOffset = depthOrOffset[1];
+ value = depthOrOffset[2];
+ } else {
+ value = /** @type {number} */ (depthOrOffset);
+ }
+
+ var width = access.getWidth();
+ var height = access.getHeight();
+
+ var x = Math.floor(u) + xOffset;
+ var y = Math.floor(v) + yOffset;
+
+ // Check for CLAMP_TO_BORDER.
+ if ((sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(x, 0, width)) ||
+ (sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(y, 0, height)))
+ return sampler.borderColor;
+
+ var i = tcuTexture.wrap(sampler.wrapS, x, width);
+ var j = tcuTexture.wrap(sampler.wrapT, y, height);
+
+ return tcuTexture.lookup(access, i, j, value);
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} u
+ * @param {number} v
+ * @param {number} w
+ * @param {Array<number>=} offset
+ * @return {Array<number>} Vec4 pixel color
+ */
+tcuTexture.sampleNearest3D = function(access, sampler, u, v, w, offset) {
+ var width = access.getWidth();
+ var height = access.getHeight();
+ var depth = access.getDepth();
+ /** @type {number} */ var xOffset = 0;
+ /** @type {number} */ var yOffset = 0;
+ /** @type {number} */ var zOffset = 0;
+
+ if (offset !== undefined && offset.length === 3) {
+ xOffset = offset[0];
+ yOffset = offset[1];
+ zOffset = offset[2];
+ }
+
+ var x = Math.floor(u) + xOffset;
+ var y = Math.floor(v) + yOffset;
+ var z = Math.floor(w) + zOffset;
+
+ // Check for CLAMP_TO_BORDER.
+ if ((sampler.wrapS == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(x, 0, width)) ||
+ (sampler.wrapT == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(y, 0, height)) ||
+ (sampler.wrapR == tcuTexture.WrapMode.CLAMP_TO_BORDER && !deMath.deInBounds32(z, 0, depth)))
+ return sampler.borderColor;
+
+ var i = tcuTexture.wrap(sampler.wrapS, x, width);
+ var j = tcuTexture.wrap(sampler.wrapT, y, height);
+ var k = tcuTexture.wrap(sampler.wrapR, z, depth);
+
+ return tcuTexture.lookup(access, i, j, k);
+};
+
+/**
+ * @param {Array<number>} color Vec4 color
+ * @return {number} The color in packed 32 bit format
+ */
+tcuTexture.packRGB999E5 = function(color) {
+ /** @const */ var mBits = 9;
+ /** @const */ var eBits = 5;
+ /** @const */ var eBias = 15;
+ /** @const */ var eMax = (1 << eBits) - 1;
+ /** @const */ var maxVal = (((1 << mBits) - 1) * (1 << (eMax - eBias))) / (1 << mBits);
+
+ var rc = deMath.clamp(color[0], 0, maxVal);
+ var gc = deMath.clamp(color[1], 0, maxVal);
+ var bc = deMath.clamp(color[2], 0, maxVal);
+ var maxc = Math.max(rc, gc, bc);
+ var expp = Math.max(-eBias - 1, Math.floor(Math.log2(maxc))) + 1 + eBias;
+ var e = Math.pow(2, expp - eBias - mBits);
+ var maxs = Math.floor(maxc / e + 0.5);
+
+ var exps = maxs == (1 << mBits) ? expp + 1 : expp;
+ var rs = deMath.clamp(Math.floor(rc / e + 0.5), 0, (1 << 9) - 1);
+ var gs = deMath.clamp(Math.floor(gc / e + 0.5), 0, (1 << 9) - 1);
+ var bs = deMath.clamp(Math.floor(bc / e + 0.5), 0, (1 << 9) - 1);
+
+ DE_ASSERT((exps & ~((1 << 5) - 1)) == 0);
+ DE_ASSERT((rs & ~((1 << 9) - 1)) == 0);
+ DE_ASSERT((gs & ~((1 << 9) - 1)) == 0);
+ DE_ASSERT((bs & ~((1 << 9) - 1)) == 0);
+
+ return rs | (gs << 9) | (bs << 18) | (exps << 27);
+};
+
+/**
+ * @param {number} color Color in packed 32 bit format
+ * @return {Array<number>} The color in unpacked format
+ */
+tcuTexture.unpackRGB999E5 = function(color) {
+ var mBits = 9;
+ var eBias = 15;
+
+ var exp = (color >> 27) & ((1 << 5) - 1);
+ var bs = (color >> 18) & ((1 << 9) - 1);
+ var gs = (color >> 9) & ((1 << 9) - 1);
+ var rs = color & ((1 << 9) - 1);
+
+ var e = Math.pow(2, (exp - eBias - mBits));
+ var r = rs * e;
+ var g = gs * e;
+ var b = bs * e;
+
+ return [r, g, b, 1];
+};
+
+/**
+ * \brief Read-only pixel data access
+ *
+ * tcuTexture.ConstPixelBufferAccess encapsulates pixel data pointer along with
+ * format and layout information. It can be used for read-only access
+ * to arbitrary pixel buffers.
+ *
+ * Access objects are like iterators or pointers. They can be passed around
+ * as values and are valid as long as the storage doesn't change.
+ * @constructor
+ */
+tcuTexture.ConstPixelBufferAccess = function(descriptor) {
+ if (descriptor) {
+ this.m_offset = descriptor.offset || 0;
+ this.m_format = descriptor.format || new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.FLOAT);
+ this.m_width = descriptor.width;
+ this.m_height = descriptor.height;
+ if (descriptor.depth)
+ this.m_depth = descriptor.depth;
+ else
+ this.m_depth = 1;
+ this.m_data = descriptor.data;
+ if (descriptor.rowPitch)
+ this.m_rowPitch = descriptor.rowPitch;
+ else
+ this.m_rowPitch = this.m_width * this.m_format.getPixelSize();
+
+ if (descriptor.slicePitch)
+ this.m_slicePitch = descriptor.slicePitch;
+ else
+ this.m_slicePitch = this.m_rowPitch * this.m_height;
+
+ if (this.m_format.isEqual(new tcuTexture.TextureFormat(
+ tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8)))
+ this.m_rgba8View = new tcuTexture.RGBA8View(this);
+ else if (this.m_format.isEqual(new tcuTexture.TextureFormat(
+ tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8)))
+ this.m_rgb8View = new tcuTexture.RGBA8View(this);
+
+ }
+
+ this.m_dataPtrType = null;
+ this.m_dataPtr = null;
+};
+
+tcuTexture.ConstPixelBufferAccess.prototype.toString = function() {
+ var str = 'BufferAccess(format: ' + this.m_format +
+ ', width: ' + this.m_width +
+ ', height: ' + this.m_height;
+ if (this.m_depth > 1)
+ str += ', depth: ' + this.m_depth;
+ if (this.m_rowPitch != this.m_width * this.m_format.getPixelSize())
+ str += ', row pitch: ' + this.m_rowPitch;
+ if (this.m_slicePitch != this.m_rowPitch * this.m_height)
+ str += ', slice pitch: ' + this.m_slicePitch;
+ if (this.m_offset > 0)
+ str += ', offset: ' + this.m_offset;
+ str += ')';
+ return str;
+};
+
+/** @return {number} */
+tcuTexture.ConstPixelBufferAccess.prototype.getDataSize = function() { return this.m_depth * this.m_slicePitch; };
+tcuTexture.ConstPixelBufferAccess.prototype.isEmpty = function() { return this.m_width == 0 || this.m_height == 0 || this.m_depth == 0; };
+/** @return {goog.TypedArray} */
+tcuTexture.ConstPixelBufferAccess.prototype.getDataPtr = function() {
+ if (this.m_dataPtrType != this.m_format.type) {
+ this.m_dataPtrType = this.m_format.type;
+ var arrayType = tcuTexture.getTypedArray(this.m_format.type);
+ this.m_dataPtr = new arrayType(this.m_data, this.m_offset);
+ }
+ return this.m_dataPtr;
+};
+/** @return {ArrayBuffer} */
+tcuTexture.ConstPixelBufferAccess.prototype.getBuffer = function() {
+ return this.m_data;
+};
+/** @return {number} */
+tcuTexture.ConstPixelBufferAccess.prototype.getRowPitch = function() { return this.m_rowPitch; };
+/** @return {number} */
+tcuTexture.ConstPixelBufferAccess.prototype.getWidth = function() { return this.m_width; };
+/** @return {number} */
+tcuTexture.ConstPixelBufferAccess.prototype.getHeight = function() { return this.m_height; };
+/** @return {number} */
+tcuTexture.ConstPixelBufferAccess.prototype.getDepth = function() { return this.m_depth; };
+/** @return {number} */
+tcuTexture.ConstPixelBufferAccess.prototype.getSlicePitch = function() { return this.m_slicePitch; };
+/** @return {tcuTexture.TextureFormat} */
+tcuTexture.ConstPixelBufferAccess.prototype.getFormat = function() { return this.m_format; };
+
+/**
+ * @param {number} x
+ * @param {number} y
+ * @param {number=} z
+ * @return {number} stencil value
+ */
+tcuTexture.ConstPixelBufferAccess.prototype.getPixStencil = function(x, y, z) {
+ z = z || 0;
+
+ DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
+ DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
+ DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
+
+ // Make sure that the position is 'integer'
+ x = Math.round(x);
+ y = Math.round(y);
+ z = Math.round(z);
+
+ var pixelSize = this.m_format.getPixelSize();
+ var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
+ var pixelPtr = this.getDataPtr();
+ var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
+
+ switch (this.m_format.type) {
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
+ switch (this.m_format.order) {
+ case tcuTexture.ChannelOrder.S: return (pixelPtr[pixelPtrOffset] >> 8) & 0xff;
+ case tcuTexture.ChannelOrder.DS: return pixelPtr[pixelPtrOffset] & 0xff;
+
+ default:
+ DE_ASSERT(false);
+ return 0;
+ }
+
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV:
+ DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
+ var u32array = new Uint32Array(this.m_data, offset + this.m_offset + 4, 1);
+ return u32array[0] & 0xff;
+
+ default: {
+ if (this.m_format.order == tcuTexture.ChannelOrder.S)
+ return tcuTexture.channelToInt(pixelPtr[pixelPtrOffset], this.m_format.type);
+ else {
+ DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
+ var stencilChannelIndex = 3;
+ return tcuTexture.channelToInt(pixelPtr[stencilChannelIndex + pixelPtrOffset], this.m_format.type);
+ }
+ }
+ }
+};
+
+/**
+ * @param {number} x
+ * @param {number} y
+ * @param {number=} z
+ * @return {number}
+ */
+tcuTexture.ConstPixelBufferAccess.prototype.getPixDepth = function(x, y, z) {
+ if (z == null)
+ z = 0;
+ DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
+ DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
+ DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
+
+ // Make sure that the position is 'integer'
+ x = Math.round(x);
+ y = Math.round(y);
+ z = Math.round(z);
+
+ var pixelSize = this.m_format.getPixelSize();
+ var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
+ var pixelPtr = this.getDataPtr();
+ var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
+
+ var ub = function(pixel, offset, count) {
+ return (pixel >> offset) & ((1 << count) - 1);
+ };
+ var nb = function(pixel, offset, count) {
+ return tcuTexture.channelToNormFloat(ub(pixel, offset, count), count);
+ };
+
+ // Packed formats.
+ switch (this.m_format.type) {
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
+ switch (this.m_format.order) {
+ case tcuTexture.ChannelOrder.D: // fall-through
+ case tcuTexture.ChannelOrder.DS:
+ return nb(pixelPtr[pixelPtrOffset], 8, 24);
+ default:
+ throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order);
+ }
+ break;
+
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
+ DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
+ return pixelPtr[pixelPtrOffset];
+ break;
+ }
+
+ default: {
+ DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.D || this.m_format.order == tcuTexture.ChannelOrder.DS);
+ return tcuTexture.channelToFloat(pixelPtr[pixelPtrOffset], this.m_format.type);
+ }
+ }
+};
+
+/**
+ * @param {number} x
+ * @param {number} y
+ * @param {number=} z
+ * @return {Array<number>} Pixel value as Vec4
+ */
+tcuTexture.ConstPixelBufferAccess.prototype.getPixel = function(x, y, z) {
+ z = z || 0;
+
+ DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
+ DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
+ DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
+
+ // Make sure that the position is 'integer'
+ return this._getPixelInternal(Math.round(x), Math.round(y), Math.round(z));
+};
+
+// NOTE: getPixel has been broken into getPixel, _getPixelInternal, and _getPixelPacked
+// because having them combined previously was causing V8 depots
+tcuTexture.ConstPixelBufferAccess.prototype._getPixelInternal = function(x, y, z) {
+ // Quick paths
+ if (z == 0) {
+ if (this.m_rgba8View) {
+ var color = this.m_rgba8View.read(x, y, 4);
+ color[0] /= 255;
+ color[1] /= 255;
+ color[2] /= 255;
+ color[3] /= 255;
+ return color;
+ } else if (this.m_rgb8View) {
+ var color = this.m_rgb8View.read(x, y, 3);
+ color[0] /= 255;
+ color[1] /= 255;
+ color[2] /= 255;
+ color[3] = 1;
+ return color;
+ }
+ }
+
+ var pixelSize = this.m_format.getPixelSize();
+ var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
+
+ var pixelPtr = this.getDataPtr();
+ var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
+
+ return this._getPixelPacked(pixelPtr, pixelPtrOffset);
+};
+
+tcuTexture.ConstPixelBufferAccess.prototype._getPixelPacked = (function() {
+
+ var ub = function(pixel, offset, count) {
+ return (pixel >> offset) & ((1 << count) - 1);
+ };
+ var nb = function(pixel, offset, count) {
+ var maxVal = (1 << count) - 1;
+ return ((pixel >> offset) & ((1 << count) - 1)) / maxVal;
+ };
+ var f11 = tcuFloat.float11ToNumber;
+ var f10 = tcuFloat.float10ToNumber;
+
+ return function tcuTexture_ConstPixelBufferAccess_getPixelPacked(pixelPtr, pixelPtrOffset) {
+ var pixel = pixelPtr[pixelPtrOffset];
+
+ // Packed formats.
+ switch (this.m_format.type) {
+ case tcuTexture.ChannelType.UNORM_SHORT_565: return [nb(pixel, 11, 5), nb(pixel, 5, 6), nb(pixel, 0, 5), 1];
+ case tcuTexture.ChannelType.UNORM_SHORT_555: return [nb(pixel, 10, 5), nb(pixel, 5, 5), nb(pixel, 0, 5), 1];
+ case tcuTexture.ChannelType.UNORM_SHORT_4444: return [nb(pixel, 12, 4), nb(pixel, 8, 4), nb(pixel, 4, 4), nb(pixel, 0, 4)];
+ case tcuTexture.ChannelType.UNORM_SHORT_5551: return [nb(pixel, 11, 5), nb(pixel, 6, 5), nb(pixel, 1, 5), nb(pixel, 0, 1)];
+ case tcuTexture.ChannelType.UNORM_INT_101010: return [nb(pixel, 22, 10), nb(pixel, 12, 10), nb(pixel, 2, 10), 1];
+ case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return [nb(pixel, 0, 10), nb(pixel, 10, 10), nb(pixel, 20, 10), nb(pixel, 30, 2)];
+ case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return [ub(pixel, 0, 10), ub(pixel, 10, 10), ub(pixel, 20, 10), ub(pixel, 30, 2)];
+ case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return tcuTexture.unpackRGB999E5(pixel);
+
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
+ switch (this.m_format.order) {
+ // \note Stencil is always ignored.
+ case tcuTexture.ChannelOrder.D: return [nb(pixel, 8, 24), 0, 0, 1];
+ case tcuTexture.ChannelOrder.DS: return [nb(pixel, 8, 24), 0, 0, 1 /* (float)ub(0, 8) */];
+ default:
+ DE_ASSERT(false);
+ }
+
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
+ DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
+ // \note Stencil is ignored.
+ return [pixel, 0, 0, 1];
+ }
+
+ case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: {
+ return [f11(ub(pixel, 0, 11)), f11(ub(pixel, 11, 11)), f10(ub(pixel, 22, 10)), 1];
+ }
+
+ default:
+ break;
+ }
+
+ // Generic path.
+ var result = [0, 0, 0, 0];
+ var channelMap = tcuTexture.getChannelReadMap(this.m_format.order);
+ var channelSize = tcuTexture.getChannelSize(this.m_format.type);
+
+ for (var c = 0; c < 4; c++) {
+ var map = channelMap[c];
+ if (map == tcuTexture.channel.ZERO)
+ result[c] = 0;
+ else if (map == tcuTexture.channel.ONE)
+ result[c] = 1;
+ else
+ result[c] = tcuTexture.channelToFloat(pixelPtr[map + pixelPtrOffset], this.m_format.type);
+ }
+
+ return result;
+ };
+})();
+
+/**
+ * @param {number} x
+ * @param {number} y
+ * @param {number=} z
+ * @return {Array<number>} Pixel value as Vec4
+ */
+tcuTexture.ConstPixelBufferAccess.prototype.getPixelInt = function(x, y, z) {
+ z = z || 0;
+ DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
+ DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
+ DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
+
+ // Make sure that the position is 'integer'
+ x = Math.round(x);
+ y = Math.round(y);
+ z = Math.round(z);
+
+ // Quick paths
+ if (z == 0) {
+ if (this.m_rgba8View)
+ return this.m_rgba8View.read(x, y, 4);
+ else if (this.m_rgb8View)
+ return this.m_rgb8View.read(x, y, 3);
+ }
+
+ var pixelSize = this.m_format.getPixelSize();
+ var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
+
+ var pixelPtr = this.getDataPtr();
+ var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
+ var pixel = pixelPtr[pixelPtrOffset];
+
+ var ub = function(pixel, offset, count) {
+ return (pixel >> offset) & ((1 << count) - 1);
+ };
+
+ // Packed formats.
+ switch (this.m_format.type) {
+ case tcuTexture.ChannelType.UNORM_SHORT_565: return [ub(pixel, 11, 5), ub(pixel, 5, 6), ub(pixel, 0, 5), 1];
+ case tcuTexture.ChannelType.UNORM_SHORT_555: return [ub(pixel, 10, 5), ub(pixel, 5, 5), ub(pixel, 0, 5), 1];
+ case tcuTexture.ChannelType.UNORM_SHORT_4444: return [ub(pixel, 12, 4), ub(pixel, 8, 4), ub(pixel, 4, 4), ub(pixel, 0, 4)];
+ case tcuTexture.ChannelType.UNORM_SHORT_5551: return [ub(pixel, 11, 5), ub(pixel, 6, 5), ub(pixel, 1, 5), ub(pixel, 0, 1)];
+ case tcuTexture.ChannelType.UNORM_INT_101010: return [ub(pixel, 22, 10), ub(pixel, 12, 10), ub(pixel, 2, 10), 1];
+ case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return [ub(pixel, 0, 10), ub(pixel, 10, 10), ub(pixel, 20, 10), ub(pixel, 30, 2)];
+ case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return [ub(pixel, 0, 10), ub(pixel, 10, 10), ub(pixel, 20, 10), ub(pixel, 30, 2)];
+
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
+ switch (this.m_format.order) {
+ case tcuTexture.ChannelOrder.D: return [ub(pixel, 8, 24), 0, 0, 1];
+ case tcuTexture.ChannelOrder.S: return [0, 0, 0, ub(pixel, 8, 24)];
+ case tcuTexture.ChannelOrder.DS: return [ub(pixel, 8, 24), 0, 0, ub(pixel, 0, 8)];
+ default:
+ DE_ASSERT(false);
+ }
+
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
+ DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
+ var u32array = new Uint32Array(this.m_data, this.m_offset + offset + 4, 1);
+ return [pixel, 0, 0, ub(u32array[0], 0, 8)];
+ }
+
+ default:
+ break;
+ }
+
+ // Generic path.
+ var result = [];
+ result.length = 4;
+ var channelMap = tcuTexture.getChannelReadMap(this.m_format.order);
+ var channelSize = tcuTexture.getChannelSize(this.m_format.type);
+
+ for (var c = 0; c < 4; c++) {
+ var map = channelMap[c];
+ if (map == tcuTexture.channel.ZERO)
+ result[c] = 0;
+ else if (map == tcuTexture.channel.ONE)
+ result[c] = 1;
+ else
+ result[c] = tcuTexture.channelToInt(pixelPtr[map + pixelPtrOffset], this.m_format.type);
+ }
+
+ return result;
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {?tcuTexture.FilterMode} filter
+ * @param {number} s
+ * @param {number} t
+ * @param {number} depth (integer)
+ * @return {Array<number>} Sample color
+ */
+tcuTexture.ConstPixelBufferAccess.prototype.sample2D = function(sampler, filter, s, t, depth) {
+ DE_ASSERT(deMath.deInBounds32(depth, 0, this.m_depth));
+
+ // Non-normalized coordinates.
+ var u = s;
+ var v = t;
+
+ if (sampler.normalizedCoords) {
+ u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width);
+ v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height);
+ }
+
+ switch (filter) {
+ case tcuTexture.FilterMode.NEAREST: return tcuTexture.sampleNearest2D(this, sampler, u, v, depth);
+ case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear2D(this, sampler, u, v, depth);
+ default:
+ throw new Error('Invalid filter:' + filter);
+ }
+ throw new Error('Unimplemented');
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {?tcuTexture.FilterMode} filter
+ * @param {number} s
+ * @param {number} t
+ * @param {Array<number>} offset
+ * @return {Array<number>} Sample color
+ */
+tcuTexture.ConstPixelBufferAccess.prototype.sample2DOffset = function(sampler, filter, s, t, offset) {
+ DE_ASSERT(deMath.deInBounds32(offset[2], 0, this.m_depth));
+
+ // Non-normalized coordinates.
+ var u = s;
+ var v = t;
+
+ if (sampler.normalizedCoords) {
+ u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width);
+ v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height);
+ }
+
+ switch (filter) {
+ case tcuTexture.FilterMode.NEAREST: return tcuTexture.sampleNearest2D(this, sampler, u, v, offset);
+ case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear2D(this, sampler, u, v, offset);
+ default:
+ throw new Error('Invalid filter:' + filter);
+ }
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {?tcuTexture.FilterMode} filter
+ * @param {number} s
+ * @param {number} t
+ * @param {number} r
+ * @param {Array<number>} offset
+ * @return {Array<number>} Sample color
+ */
+tcuTexture.ConstPixelBufferAccess.prototype.sample3DOffset = function(sampler, filter, s, t, r, offset) {
+ // Non-normalized coordinates.
+ /** @type {number} */ var u = s;
+ /** @type {number} */ var v = t;
+ /** @type {number} */ var w = r;
+
+ if (sampler.normalizedCoords) {
+ u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width);
+ v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height);
+ w = tcuTexture.unnormalize(sampler.wrapR, r, this.m_depth);
+ }
+
+ switch (filter) {
+ case tcuTexture.FilterMode.NEAREST: return tcuTexture.sampleNearest3D(this, sampler, u, v, w, offset);
+ case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear3D(this, sampler, u, v, w, offset);
+ default:
+ throw new Error('Invalid filter:' + filter);
+ }
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} filter
+ * @param {number} ref
+ * @param {number} s
+ * @param {number} t
+ * @param {Array<number>} offset
+ * @return {number}
+ */
+tcuTexture.ConstPixelBufferAccess.prototype.sample2DCompare = function(sampler, filter, ref, s, t, offset) {
+ DE_ASSERT(deMath.deInBounds32(offset[2], 0, this.m_depth));
+
+ // Format information for comparison function
+ var isFixedPointDepth = tcuTexture.isFixedPointDepthTextureFormat(this.m_format);
+
+ // Non-normalized coordinates.
+ var u = s;
+ var v = t;
+
+ if (sampler.normalizedCoords) {
+ u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width);
+ v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height);
+ }
+
+ switch (filter) {
+ case tcuTexture.FilterMode.NEAREST: return tcuTexture.execCompare(tcuTexture.sampleNearest2D(this, sampler, u, v, offset), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
+ case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear2DCompare(this, sampler, ref, u, v, offset, isFixedPointDepth);
+ default:
+ DE_ASSERT(false);
+ return 0.0;
+ }
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {tcuTexture.FilterMode} filter
+ * @param {number} s
+ * @param {number} t
+ * @param {number} r
+ * @return {Array<number>} Sample color
+ */
+tcuTexture.ConstPixelBufferAccess.prototype.sample3D = function(sampler, filter, s, t, r) {
+ // Non-normalized coordinates.
+ var u = s;
+ var v = t;
+ var w = r;
+
+ if (sampler.normalizedCoords) {
+ u = tcuTexture.unnormalize(sampler.wrapS, s, this.m_width);
+ v = tcuTexture.unnormalize(sampler.wrapT, t, this.m_height);
+ w = tcuTexture.unnormalize(sampler.wrapR, r, this.m_depth);
+ }
+
+ switch (filter) {
+ case tcuTexture.FilterMode.NEAREST: return tcuTexture.sampleNearest3D(this, sampler, u, v, w);
+ case tcuTexture.FilterMode.LINEAR: return tcuTexture.sampleLinear3D(this, sampler, u, v, w);
+ default:
+ throw new Error('Invalid filter:' + filter);
+ }
+ throw new Error('Unimplemented');
+};
+
+ /* TODO: do we need any of these? */ {
+ // template<typename T>
+ // Vector<T, 4> getPixelT (int x, int y, int z = 0) const;
+
+ // Vec4 sample3D (const tcuTexture.Sampler& sampler, tcuTexture.tcuTexture.Sampler.tcuTexture.FilterMode filter, float s, float t, float r) const;
+
+ // Vec4 sample2DOffset (const tcuTexture.Sampler& sampler, tcuTexture.Sampler::tcuTexture.FilterMode filter, float s, float t, const IVec3& offset) const;
+ // Vec4 sample3DOffset (const tcuTexture.Sampler& sampler, tcuTexture.Sampler::tcuTexture.FilterMode filter, float s, float t, float r, const IVec3& offset) const;
+
+ // float sample2DCompare (const tcuTexture.Sampler& sampler, tcuTexture.Sampler::tcuTexture.FilterMode filter, float ref, float s, float t, const IVec3& offset) const;
+ };
+
+/** Common type limits
+ *
+ */
+tcuTexture.deTypes = {
+ deInt8: {min: -(1 << 7), max: (1 << 7) - 1},
+ deInt16: {min: -(1 << 15), max: (1 << 15) - 1},
+ deInt32: {min: -2147483648, max: 2147483647},
+ deUint8: {min: 0, max: (1 << 8) - 1},
+ deUint16: {min: 0, max: (1 << 16) - 1},
+ deUint32: {min: 0, max: 4294967295}
+};
+
+/**
+ * Round to even and saturate
+ * @param {{max: number, min: number}} deType from tcuTexture.deTypes
+ * @param {number} value
+ * @return {number}
+ */
+tcuTexture.convertSatRte = function(deType, value) {
+ var minVal = deType.min;
+ var maxVal = deType.max;
+ var floor = Math.floor(value);
+ var frac = value - floor;
+ if (frac == 0.5) {
+ if (floor % 2 != 0)
+ floor += 1;
+ } else if (frac > 0.5) {
+ floor += 1;
+ }
+
+ return Math.max(minVal, Math.min(maxVal, floor));
+};
+
+/**
+ * Saturate value to type range
+ * @param { {max: number, min: number}} deType from tcuTexture.deTypes
+ * @param {number} src
+ * @return {number}
+ */
+tcuTexture.convertSat = function(deType, src) {
+ var minVal = deType.min;
+ var maxVal = deType.max;
+ if (src < minVal)
+ return minVal;
+ else if (src > maxVal)
+ return maxVal;
+ else
+ return src;
+};
+
+/**
+ * @param {number} src Input integer value
+ * @param {tcuTexture.ChannelType} type
+ * @return {number}
+ */
+tcuTexture.intToChannel = function(src, type) {
+ var dst;
+ switch (type) {
+ case tcuTexture.ChannelType.SNORM_INT8: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt8, src); break;
+ case tcuTexture.ChannelType.SNORM_INT16: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt16, src); break;
+ case tcuTexture.ChannelType.UNORM_INT8: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint8, src); break;
+ case tcuTexture.ChannelType.UNORM_INT16: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint16, src); break;
+ case tcuTexture.ChannelType.SIGNED_INT8: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt8, src); break;
+ case tcuTexture.ChannelType.SIGNED_INT16: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt16, src); break;
+ case tcuTexture.ChannelType.SIGNED_INT32: dst = tcuTexture.convertSat(tcuTexture.deTypes.deInt32, src); break;
+ case tcuTexture.ChannelType.UNSIGNED_INT8: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint8, src); break;
+ case tcuTexture.ChannelType.UNSIGNED_INT16: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint16, src); break;
+ case tcuTexture.ChannelType.UNSIGNED_INT32: dst = tcuTexture.convertSat(tcuTexture.deTypes.deUint32, src); break;
+ case tcuTexture.ChannelType.HALF_FLOAT: dst = tcuFloat.numberToHalfFloat(src); break;
+ case tcuTexture.ChannelType.FLOAT: dst = src; break;
+ default:
+ throw new Error('Unrecognized tcuTexture.channel type: ' + type);
+ }
+ return dst;
+};
+
+/**
+ * @param {number} src
+ * @param {number} bits
+ * @return {number}
+ */
+tcuTexture.normFloatToChannel = function(src, bits) {
+ var maxVal = (1 << bits) - 1;
+ var intVal = tcuTexture.convertSatRte(tcuTexture.deTypes.deUint32, src * maxVal);
+ return Math.min(maxVal, intVal);
+};
+
+/**
+ * @param {number} src
+ * @param {number} bits
+ * @return {number}
+ */
+tcuTexture.uintToChannel = function(src, bits) {
+ var maxVal = (1 << bits) - 1;
+ return Math.min(maxVal, src);
+};
+
+/**
+ * @param {number} src
+ * @param {tcuTexture.ChannelType} type
+ * @return {number} Converted src color value
+ */
+tcuTexture.floatToChannel = function(src, type) {
+ switch (type) {
+ case tcuTexture.ChannelType.SNORM_INT8: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt8, src * 127);
+ case tcuTexture.ChannelType.SNORM_INT16: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt16, src * 32767);
+ case tcuTexture.ChannelType.SNORM_INT32: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt32, src * 2147483647);
+ case tcuTexture.ChannelType.UNORM_INT8: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint8, src * 255);
+ case tcuTexture.ChannelType.UNORM_INT16: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint16, src * 65535);
+ case tcuTexture.ChannelType.UNORM_INT32: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint32, src * 4294967295);
+ case tcuTexture.ChannelType.SIGNED_INT8: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt8, src);
+ case tcuTexture.ChannelType.SIGNED_INT16: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt16, src);
+ case tcuTexture.ChannelType.SIGNED_INT32: return tcuTexture.convertSatRte(tcuTexture.deTypes.deInt32, src);
+ case tcuTexture.ChannelType.UNSIGNED_INT8: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint8, src);
+ case tcuTexture.ChannelType.UNSIGNED_INT16: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint16, src);
+ case tcuTexture.ChannelType.UNSIGNED_INT32: return tcuTexture.convertSatRte(tcuTexture.deTypes.deUint32, src);
+ case tcuTexture.ChannelType.HALF_FLOAT: return tcuFloat.numberToHalfFloat(src);
+ case tcuTexture.ChannelType.FLOAT: return src;
+ }
+ throw new Error('Unrecognized type ' + type);
+};
+
+/**
+ * \brief Read-write pixel data access
+ *
+ * This class extends read-only access object by providing write functionality.
+ *
+ * \note tcuTexture.PixelBufferAccess may not have any data members nor add any
+ * virtual functions. It must be possible to reinterpret_cast<>
+ * tcuTexture.PixelBufferAccess to tcuTexture.ConstPixelBufferAccess.
+ * @constructor
+ * @extends {tcuTexture.ConstPixelBufferAccess}
+ *
+ */
+tcuTexture.PixelBufferAccess = function(descriptor) {
+ tcuTexture.ConstPixelBufferAccess.call(this, descriptor);
+};
+
+tcuTexture.PixelBufferAccess.prototype = Object.create(tcuTexture.ConstPixelBufferAccess.prototype);
+tcuTexture.PixelBufferAccess.prototype.constructor = tcuTexture.PixelBufferAccess;
+
+/**
+ * @param {Array<number>} color Vec4 color to set
+ * @param {number} x
+ * @param {number} y
+ * @param {number=} z
+ */
+tcuTexture.PixelBufferAccess.prototype.setPixel = function(color, x, y, z) {
+ z = z || 0;
+ DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
+ DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
+ DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
+
+ // Make sure that the position is 'integer'
+ this._setPixelInternal(color, Math.round(x), Math.round(y), Math.round(z));
+};
+
+// NOTE: setPixel has been broken into setPixel, _setPixelInternal, and _setPixelPacked
+// because having them combined previously was causing V8 depots
+tcuTexture.PixelBufferAccess.prototype._setPixelInternal = function(color, x, y, z) {
+ // Quick paths
+ if (z == 0) {
+ if (this.m_rgba8View) {
+ color = deMath.toIVec(color);
+ this.m_rgba8View.write(x, y, color, 4);
+ return;
+ } else if (this.m_rgb8View) {
+ color = deMath.toIVec(color);
+ this.m_rgb8View.write(x, y, color, 3);
+ return;
+ }
+ }
+
+ var pixelSize = this.m_format.getPixelSize();
+ var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
+ var pixelPtr = this.getDataPtr();
+ var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
+
+ return this._setPixelPacked(color, pixelPtr, pixelPtrOffset);
+};
+
+tcuTexture.PixelBufferAccess.prototype._setPixelPacked = (function () {
+ var pn = function(val, offs, bits) {
+ return tcuTexture.normFloatToChannel(val, bits) << offs;
+ };
+
+ var pu = function(val, offs, bits) {
+ return tcuTexture.uintToChannel(val, bits) << offs;
+ };
+
+ return function tcuTexture_PixelBufferAccess_setPixelPacked(color, pixelPtr, pixelPtrOffset) {
+ // Packed formats.
+ switch (this.m_format.type) {
+ case tcuTexture.ChannelType.UNORM_SHORT_565: pixelPtr[pixelPtrOffset] = pn(color[0], 11, 5) | pn(color[1], 5, 6) | pn(color[2], 0, 5); break;
+ case tcuTexture.ChannelType.UNORM_SHORT_555: pixelPtr[pixelPtrOffset] = pn(color[0], 10, 5) | pn(color[1], 5, 5) | pn(color[2], 0, 5); break;
+ case tcuTexture.ChannelType.UNORM_SHORT_4444: pixelPtr[pixelPtrOffset] = pn(color[0], 12, 4) | pn(color[1], 8, 4) | pn(color[2], 4, 4) | pn(color[3], 0, 4); break;
+ case tcuTexture.ChannelType.UNORM_SHORT_5551: pixelPtr[pixelPtrOffset] = pn(color[0], 11, 5) | pn(color[1], 6, 5) | pn(color[2], 1, 5) | pn(color[3], 0, 1); break;
+ case tcuTexture.ChannelType.UNORM_INT_101010: pixelPtr[pixelPtrOffset] = pn(color[0], 22, 10) | pn(color[1], 12, 10) | pn(color[2], 2, 10); break;
+ case tcuTexture.ChannelType.UNORM_INT_1010102_REV: pixelPtr[pixelPtrOffset] = pn(color[0], 0, 10) | pn(color[1], 10, 10) | pn(color[2], 20, 10) | pn(color[3], 30, 2); break;
+ case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: pixelPtr[pixelPtrOffset] = pu(color[0], 0, 10) | pu(color[1], 10, 10) | pu(color[2], 20, 10) | pu(color[3], 30, 2); break;
+ case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: pixelPtr[pixelPtrOffset] = tcuTexture.packRGB999E5(color); break;
+
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
+ switch (this.m_format.order) {
+ // \note Stencil is always ignored.
+ case tcuTexture.ChannelOrder.D: pixelPtr[pixelPtrOffset] = pn(color[0], 8, 24); break;
+ case tcuTexture.ChannelOrder.S: pixelPtr[pixelPtrOffset] = pn(color[3], 8, 24); break;
+ case tcuTexture.ChannelOrder.DS: pixelPtr[pixelPtrOffset] = pn(color[0], 8, 24) | pu(color[3], 0, 8); break;
+ default:
+ throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order);
+ }
+ break;
+
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
+ pixelPtr[pixelPtrOffset] = color[0];
+ var u32array = new Uint32Array(this.m_data, (pixelPtrOffset * pixelPtr.BYTES_PER_ELEMENT) + this.m_offset + 4, 1);
+ u32array[0] = pu(color[3], 0, 8);
+ break;
+ }
+
+ case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: {
+ var f11 = function(value) {
+ return tcuFloat.numberToFloat11(value);
+ };
+ var f10 = function(value) {
+ return tcuFloat.numberToFloat10(value);
+ };
+
+ pixelPtr[pixelPtrOffset] = f11(color[0]) | (f11(color[1]) << 11) | (f10(color[2]) << 22);
+ break;
+ }
+ case tcuTexture.ChannelType.FLOAT:
+ if (this.m_format.order == tcuTexture.ChannelOrder.D) {
+ pixelPtr[pixelPtrOffset] = color[0];
+ break;
+ }
+ // else fall-through to default case!
+
+ default: {
+ // Generic path.
+ var numChannels = tcuTexture.getNumUsedChannels(this.m_format.order);
+ var map = tcuTexture.getChannelWriteMap(this.m_format.order);
+
+ for (var c = 0; c < numChannels; c++)
+ pixelPtr[c + pixelPtrOffset] = tcuTexture.floatToChannel(color[map[c]], this.m_format.type);
+ }
+ }
+ };
+})();
+
+/**
+ * @param {Array<number>} color Vec4 color to set (unnormalized)
+ * @param {number} x
+ * @param {number} y
+ * @param {number=} z
+ */
+tcuTexture.PixelBufferAccess.prototype.setPixelInt = function(color, x, y, z) {
+ z = z || 0;
+ DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
+ DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
+ DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
+
+ // Make sure that the position is 'integer'
+ x = Math.round(x);
+ y = Math.round(y);
+ z = Math.round(z);
+
+ // Quick paths
+ if (z == 0) {
+ if (this.m_rgba8View) {
+ this.m_rgba8View.write(x, y, color, 4);
+ return;
+ } else if (this.m_rgb8View) {
+ this.m_rgb8View.write(x, y, color, 3);
+ return;
+ }
+ }
+
+ var pixelSize = this.m_format.getPixelSize();
+ var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
+ var pixelPtr = this.getDataPtr();
+ var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
+
+ var pu = function(val, offs, bits) {
+ return tcuTexture.uintToChannel(val, bits) << offs;
+ };
+
+ // Packed formats.
+ switch (this.m_format.type) {
+ case tcuTexture.ChannelType.UNORM_SHORT_565: pixelPtr[pixelPtrOffset] = pu(color[0], 11, 5) | pu(color[1], 5, 6) | pu(color[2], 0, 5); break;
+ case tcuTexture.ChannelType.UNORM_SHORT_555: pixelPtr[pixelPtrOffset] = pu(color[0], 10, 5) | pu(color[1], 5, 5) | pu(color[2], 0, 5); break;
+ case tcuTexture.ChannelType.UNORM_SHORT_4444: pixelPtr[pixelPtrOffset] = pu(color[0], 12, 4) | pu(color[1], 8, 4) | pu(color[2], 4, 4) | pu(color[3], 0, 4); break;
+ case tcuTexture.ChannelType.UNORM_SHORT_5551: pixelPtr[pixelPtrOffset] = pu(color[0], 11, 5) | pu(color[1], 6, 5) | pu(color[2], 1, 5) | pu(color[3], 0, 1); break;
+ case tcuTexture.ChannelType.UNORM_INT_101010: pixelPtr[pixelPtrOffset] = pu(color[0], 22, 10) | pu(color[1], 12, 10) | pu(color[2], 2, 10); break;
+ case tcuTexture.ChannelType.UNORM_INT_1010102_REV: pixelPtr[pixelPtrOffset] = pu(color[0], 0, 10) | pu(color[1], 10, 10) | pu(color[2], 20, 10) | pu(color[3], 30, 2); break;
+ case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: pixelPtr[pixelPtrOffset] = pu(color[0], 0, 10) | pu(color[1], 10, 10) | pu(color[2], 20, 10) | pu(color[3], 30, 2); break;
+
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
+ switch (this.m_format.order) {
+ // \note Stencil is always ignored.
+ case tcuTexture.ChannelOrder.D: pixelPtr[pixelPtrOffset] = pu(color[0], 8, 24); break;
+ case tcuTexture.ChannelOrder.S: pixelPtr[pixelPtrOffset] = pu(color[3], 8, 24); break;
+ case tcuTexture.ChannelOrder.DS: pixelPtr[pixelPtrOffset] = pu(color[0], 8, 24) | pu(color[3], 0, 8); break;
+ default:
+ throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order);
+ }
+ break;
+
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
+ pixelPtr[pixelPtrOffset] = color[0];
+ var u32array = new Uint32Array(this.m_data, offset + this.m_offset + 4, 1);
+ u32array[pixelPtrOffset] = pu(color[3], 0, 8);
+ break;
+ }
+
+ default: {
+ // Generic path.
+ var numChannels = tcuTexture.getNumUsedChannels(this.m_format.order);
+ var map = tcuTexture.getChannelWriteMap(this.m_format.order);
+
+ for (var c = 0; c < numChannels; c++)
+ pixelPtr[c + pixelPtrOffset] = tcuTexture.intToChannel(color[map[c]], this.m_format.type);
+ }
+ }
+};
+
+/**
+ * @param {Array<number>=} color Vec4 color to set, optional.
+ * @param {Array<number>=} x Range in x axis, optional.
+ * @param {Array<number>=} y Range in y axis, optional.
+ * @param {Array<number>=} z Range in z axis, optional.
+ */
+tcuTexture.PixelBufferAccess.prototype.clear = function(color, x, y, z) {
+ var c = color || [0, 0, 0, 0];
+ var arrayType = tcuTexture.getTypedArray(this.m_format.type);
+ var range_x = x || [0, this.m_width];
+ var range_y = y || [0, this.m_height];
+ var range_z = z || [0, this.m_depth];
+ var pixelSize = this.m_format.getPixelSize();
+ var numElements = pixelSize / arrayType.BYTES_PER_ELEMENT;
+ var width = range_x[1] - range_x[0];
+ var height = range_y[1] - range_y[0];
+ var depth = range_z[1] - range_z[0];
+ if (x === undefined && y === undefined && z === undefined &&
+ c[0] == 0 && c[1] == 0 && c[2] == 0 && c[3] == 0) {
+ var pixelPtr = new arrayType(this.m_data, this.m_offset);
+ pixelPtr.fill(0);
+ return;
+ }
+
+ //copy first pixel over other pixels in the row
+ var fillRow = function(pixelPtr, numElements, width) {
+ for (var i = 1; i < width; i++)
+ for (var c = 0; c < numElements; c++)
+ pixelPtr[i * numElements + c] = pixelPtr[c];
+ };
+ // copy first row to other rows in all planes
+ var fillPlanes = function(buffer, arrayType, src, offset, rowStride, planeStride, width, height, depth) {
+ for (var j = 0; j < depth; j++)
+ for (var i = (j == 0 ? 1 : 0); i < height; i++) {
+ var dst = new arrayType(buffer, offset + i * rowStride + j * planeStride, width);
+ dst.set(src);
+ }
+ };
+
+ this.setPixel(c, range_x[0], range_y[0], range_z[0]);
+
+ var offset = range_z[0] * this.m_slicePitch + range_y[0] * this.m_rowPitch + range_x[0] * pixelSize;
+ var pixelPtr = new arrayType(this.m_data, offset + this.m_offset, width * numElements);
+
+ fillRow(pixelPtr, numElements, width);
+ fillPlanes(this.m_data, arrayType, pixelPtr, offset + this.m_offset, this.m_rowPitch, this.m_slicePitch, width * numElements, height, depth);
+};
+
+/**
+ * @param {number} depth to set
+ * @param {number} x
+ * @param {number} y
+ * @param {number=} z
+ */
+tcuTexture.PixelBufferAccess.prototype.setPixDepth = function(depth, x, y, z) {
+ if (z == null)
+ z = 0;
+ DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
+ DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
+ DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
+
+ // Make sure that the position is 'integer'
+ x = Math.round(x);
+ y = Math.round(y);
+ z = Math.round(z);
+
+ var pixelSize = this.m_format.getPixelSize();
+ var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
+ var pixelPtr = this.getDataPtr();
+ var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
+
+ var pn = function(val, offs, bits) {
+ return tcuTexture.normFloatToChannel(val, bits) << offs;
+ };
+
+ // Packed formats.
+ switch (this.m_format.type) {
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
+ switch (this.m_format.order) {
+ case tcuTexture.ChannelOrder.D: pixelPtr[pixelPtrOffset] = pn(depth, 8, 24); break;
+ case tcuTexture.ChannelOrder.DS: pixelPtr[pixelPtrOffset] = pn(depth, 8, 24) | (pixelPtr[pixelPtrOffset] & 0xFF); break;
+ default:
+ throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order);
+ }
+ break;
+
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
+ DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
+ pixelPtr[pixelPtrOffset] = depth;
+ break;
+ }
+
+ default: {
+ DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.D || this.m_format.order == tcuTexture.ChannelOrder.DS);
+ pixelPtr[pixelPtrOffset] = tcuTexture.floatToChannel(depth, this.m_format.type);
+ }
+ }
+};
+
+/**
+ * @param {number} stencil to set
+ * @param {number} x
+ * @param {number} y
+ * @param {number=} z
+ */
+tcuTexture.PixelBufferAccess.prototype.setPixStencil = function(stencil, x, y, z) {
+ if (z == null)
+ z = 0;
+ DE_ASSERT(deMath.deInBounds32(x, 0, this.m_width));
+ DE_ASSERT(deMath.deInBounds32(y, 0, this.m_height));
+ DE_ASSERT(deMath.deInBounds32(z, 0, this.m_depth));
+
+ // Make sure that the position is 'integer'
+ x = Math.round(x);
+ y = Math.round(y);
+ z = Math.round(z);
+
+ var pixelSize = this.m_format.getPixelSize();
+ var offset = z * this.m_slicePitch + y * this.m_rowPitch + x * pixelSize;
+ var pixelPtr = this.getDataPtr();
+ var pixelPtrOffset = offset / pixelPtr.BYTES_PER_ELEMENT;
+
+ var pu = function(val, offs, bits) {
+ return tcuTexture.uintToChannel(val, bits) << offs;
+ };
+
+ // Packed formats.
+ switch (this.m_format.type) {
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
+ switch (this.m_format.order) {
+ case tcuTexture.ChannelOrder.S: pixelPtr[pixelPtrOffset] = pu(stencil, 8, 24); break;
+ case tcuTexture.ChannelOrder.DS: pixelPtr[pixelPtrOffset] = pu(stencil, 0, 8) | (pixelPtr[pixelPtrOffset] & 0xFFFFFF00); break;
+ default:
+ throw new Error('Unsupported tcuTexture.channel order ' + this.m_format.order);
+ }
+ break;
+
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: {
+ var u32array = new Uint32Array(this.m_data, this.m_offset + offset + 4, 1);
+ u32array[0] = pu(stencil, 0, 8);
+ break;
+ }
+
+ default: {
+ if (this.m_format.order == tcuTexture.ChannelOrder.S)
+ pixelPtr[pixelPtrOffset] = tcuTexture.floatToChannel(stencil, this.m_format.type);
+ else {
+ DE_ASSERT(this.m_format.order == tcuTexture.ChannelOrder.DS);
+ pixelPtr[3 + pixelPtrOffset] = tcuTexture.floatToChannel(stencil, this.m_format.type);
+ }
+ }
+ }
+};
+
+/**
+ * newFromTextureLevel
+ * @param {tcuTexture.TextureLevel} level
+ * @return {tcuTexture.PixelBufferAccess}
+ */
+tcuTexture.PixelBufferAccess.newFromTextureLevel = function(level) {
+ var descriptor = new Object();
+ descriptor.format = level.getFormat();
+ descriptor.width = level.getWidth();
+ descriptor.height = level.getHeight();
+ descriptor.depth = level.m_depth;
+ descriptor.data = level.m_data.m_ptr;
+
+ return new tcuTexture.PixelBufferAccess(descriptor);
+};
+
+/**
+ * newFromTextureFormat
+ * @param {tcuTexture.TextureFormat} format
+ * @param {number} width
+ * @param {number} height
+ * @param {number} depth
+ * @param {number} rowPitch
+ * @param {number} slicePitch
+ * @param {ArrayBuffer} data
+ */
+tcuTexture.PixelBufferAccess.newFromTextureFormat = function(format, width, height, depth, rowPitch, slicePitch, data) {
+ var descriptor = new Object();
+ descriptor.format = format;
+ descriptor.width = width;
+ descriptor.height = height;
+ descriptor.depth = depth;
+ descriptor.rowPitch = rowPitch;
+ descriptor.slicePitch = slicePitch;
+ descriptor.data = data;
+
+ return new tcuTexture.PixelBufferAccess(descriptor);
+};
+
+/* TODO: Port */
+// {
+// public:
+// tcuTexture.PixelBufferAccess (void) {}
+// tcuTexture.PixelBufferAccess (const tcuTexture.TextureFormat& format, int width, int height, int depth, void* data);
+
+// void* getDataPtr (void) const { return m_data; }
+
+// void setPixels (const void* buf, int bufSize) const;
+// void setPixel (const tcu::Vec4& color, int x, int y, int z = 0) const;
+// void setPixel (const tcu::IVec4& color, int x, int y, int z = 0) const;
+// void setPixel (const tcu::UVec4& color, int x, int y, int z = 0) const { setPixel(color.cast<int>(), x, y, z); }
+
+// void setPixDepth (float depth, int x, int y, int z = 0) const;
+// void setPixStencil (int stencil, int x, int y, int z = 0) const;
+// };
+
+/**
+ * @constructor
+ * @param {tcuTexture.TextureFormat} format
+ * @param {number} numLevels
+ */
+tcuTexture.TextureLevelPyramid = function(format, numLevels) {
+ /* tcuTexture.TextureFormat */this.m_format = format;
+ /* LevelData */ this.m_data = [];
+ for (var i = 0; i < numLevels; i++)
+ this.m_data.push(new tcuTexture.DeqpArrayBuffer());
+ /* {Array<tcuTexture.PixelBufferAccess>} */ this.m_access = [];
+ this.m_access.length = numLevels;
+};
+
+/** @return {boolean} */
+tcuTexture.TextureLevelPyramid.prototype.isLevelEmpty = function(levelNdx) { return this.m_data[levelNdx].empty(); };
+/** @return {tcuTexture.TextureFormat} */
+tcuTexture.TextureLevelPyramid.prototype.getFormat = function() { return this.m_format; };
+/** @return {number} */
+tcuTexture.TextureLevelPyramid.prototype.getNumLevels = function() { return this.m_access.length; };
+/** @return {tcuTexture.PixelBufferAccess} */
+tcuTexture.TextureLevelPyramid.prototype.getLevel = function(ndx) { return this.m_access[ndx]; };
+/** @return {Array<tcuTexture.PixelBufferAccess>} */
+tcuTexture.TextureLevelPyramid.prototype.getLevels = function() { return this.m_access; };
+
+/**
+ * @param {number} levelNdx
+ * @param {number} width
+ * @param {number} height
+ * @param {number} depth
+ */
+tcuTexture.TextureLevelPyramid.prototype.allocLevel = function(levelNdx, width, height, depth) {
+ var size = this.m_format.getPixelSize() * width * height * depth;
+
+ DE_ASSERT(this.isLevelEmpty(levelNdx));
+
+ this.m_data[levelNdx].setStorage(size);
+ this.m_access[levelNdx] = new tcuTexture.PixelBufferAccess({
+ format: this.m_format,
+ width: width,
+ height: height,
+ depth: depth,
+ data: this.m_data[levelNdx].m_ptr
+ });
+};
+
+tcuTexture.TextureLevelPyramid.prototype.clearLevel = function(levelNdx) {
+ /* TODO: Implement */
+ throw new Error('Not implemented');
+};
+
+/**
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
+ * @param {number} numLevels
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} s
+ * @param {number} t
+ * @param {number} depth (integer)
+ * @param {number=} lod
+ * @return {Array<number>} Vec4 pixel color
+ */
+tcuTexture.sampleLevelArray2D = function(levels, numLevels, sampler, s, t, depth, lod) {
+ // z-offset in 2D textures is layer selector
+ return tcuTexture.sampleLevelArray2DOffset(levels, numLevels, sampler, [s, t], lod, [0, 0, depth]);
+};
+
+/**
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
+ * @param {number} numLevels
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} s
+ * @param {number} t
+ * @param {number} r
+ * @param {number} lod
+ * @return {Array<number>} Vec4 pixel color
+ */
+tcuTexture.sampleLevelArray3D = function(levels, numLevels, sampler, s, t, r, lod) {
+ return tcuTexture.sampleLevelArray3DOffset(levels, numLevels, sampler, s, t, r, lod, [0, 0, 0]);
+};
+
+/**
+ * @constructor
+ * @param {tcuTexture.CubeFace} face
+ * @param {Array<number>} coords
+ */
+tcuTexture.CubeFaceCoords = function(face, coords) {
+ this.face = face;
+ this.s = coords[0];
+ this.t = coords[1];
+};
+
+/**
+ * \brief 2D Texture View
+ * @constructor
+ * @param {number} numLevels
+ * @param {?Array<tcuTexture.ConstPixelBufferAccess>} levels
+ */
+tcuTexture.Texture2DView = function(numLevels, levels) {
+ this.m_numLevels = numLevels;
+ this.m_levels = levels;
+};
+
+/** @return {number} */
+tcuTexture.Texture2DView.prototype.getNumLevels = function() { return this.m_numLevels; };
+/** @return {number} */
+tcuTexture.Texture2DView.prototype.getWidth = function() { return this.m_numLevels > 0 ? this.m_levels[0].getWidth() : 0; };
+/** @return {number} */
+tcuTexture.Texture2DView.prototype.getHeight = function() { return this.m_numLevels > 0 ? this.m_levels[0].getHeight() : 0; };
+/**
+ * @param {number} ndx
+ * @return {tcuTexture.ConstPixelBufferAccess}
+ */
+tcuTexture.Texture2DView.prototype.getLevel = function(ndx) { DE_ASSERT(deMath.deInBounds32(ndx, 0, this.m_numLevels)); return this.m_levels[ndx]; };
+/** @return {Array<tcuTexture.ConstPixelBufferAccess>} */
+tcuTexture.Texture2DView.prototype.getLevels = function() { return this.m_levels; };
+
+/**
+ * @param {number} baseLevel
+ * @param {number} maxLevel
+ * return {tcuTexture.Texture2DView}
+ */
+tcuTexture.Texture2DView.prototype.getSubView = function(baseLevel, maxLevel) {
+ var clampedBase = deMath.clamp(baseLevel, 0, this.m_numLevels - 1);
+ var clampedMax = deMath.clamp(maxLevel, clampedBase, this.m_numLevels - 1);
+ var numLevels = clampedMax - clampedBase + 1;
+ return new tcuTexture.Texture2DView(numLevels, this.m_levels.slice(clampedBase, numLevels));
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {Array<number>} texCoord
+ * @param {number=} lod
+ * @return {Array<number>} Pixel color
+ */
+tcuTexture.Texture2DView.prototype.sample = function(sampler, texCoord, lod) {
+ return tcuTexture.sampleLevelArray2D(this.m_levels, this.m_numLevels, sampler, texCoord[0], texCoord[1], 0 /* depth */, lod);
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {Array<number>} texCoord
+ * @param {number} lod
+ * @param {Array<number>} offset
+ * @return {Array<number>} Pixel color
+ */
+tcuTexture.Texture2DView.prototype.sampleOffset = function(sampler, texCoord, lod, offset) {
+ return tcuTexture.sampleLevelArray2DOffset(this.m_levels, this.m_numLevels, sampler, texCoord, lod, [offset[0], offset[1], 0]);
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} ref
+ * @param {Array<number>} texCoord
+ * @param {number} lod
+ * @return {number}
+ */
+tcuTexture.Texture2DView.prototype.sampleCompare = function(sampler, ref, texCoord, lod) {
+ return tcuTexture.sampleLevelArray2DCompare(this.m_levels, this.m_numLevels, sampler, ref, texCoord[0], texCoord[1], lod, [0, 0, 0]);
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} ref
+ * @param {Array<number>} texCoord
+ * @param {number} lod
+ * @param {Array<number>} offset
+ * @return {number}
+ */
+tcuTexture.Texture2DView.prototype.sampleCompareOffset = function(sampler, ref, texCoord, lod, offset) {
+ return tcuTexture.sampleLevelArray2DCompare(this.m_levels, this.m_numLevels, sampler, ref, texCoord[0], texCoord[1], lod, [offset[0], offset[1], 0]);
+};
+
+ /* TODO: Port
+ Vec4 sample (const tcuTexture.Sampler& sampler, float s, float t, float lod) const;
+ Vec4 sampleOffset (const tcuTexture.Sampler& sampler, float s, float t, float lod, const IVec2& offset) const;
+ float sampleCompare (const tcuTexture.Sampler& sampler, float ref, float s, float t, float lod) const;
+ float sampleCompareOffset (const tcuTexture.Sampler& sampler, float ref, float s, float t, float lod, const IVec2& offset) const;
+
+ Vec4 gatherOffsets (const tcuTexture.Sampler& sampler, float s, float t, int componentNdx, const IVec2 (&offsets)[4]) const;
+ Vec4 gatherOffsetsCompare(const tcuTexture.Sampler& sampler, float ref, float s, float t, const IVec2 (&offsets)[4]) const;
+ */
+
+/**
+ * @constructor
+ * @param {number} numLevels
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
+ */
+tcuTexture.Texture2DArrayView = function(numLevels, levels) {
+ this.m_numLevels = numLevels;
+ this.m_levels = levels;
+};
+
+/** @return {number} */
+tcuTexture.Texture2DArrayView.prototype.getNumLevels = function() { return this.m_numLevels; };
+/** @return {number} */
+tcuTexture.Texture2DArrayView.prototype.getWidth = function() { return this.m_numLevels > 0 ? this.m_levels[0].getWidth() : 0; };
+/** @return {number} */
+tcuTexture.Texture2DArrayView.prototype.getHeight = function() { return this.m_numLevels > 0 ? this.m_levels[0].getHeight() : 0; };
+/** @return {number} */
+tcuTexture.Texture2DArrayView.prototype.getNumLayers = function() { return this.m_numLevels > 0 ? this.m_levels[0].getDepth() : 0; };
+/**
+ * @param {number} ndx
+ * @return {tcuTexture.ConstPixelBufferAccess}
+ */
+tcuTexture.Texture2DArrayView.prototype.getLevel = function(ndx) { DE_ASSERT(deMath.deInBounds32(ndx, 0, this.m_numLevels)); return this.m_levels[ndx]; };
+/** @return {Array<tcuTexture.ConstPixelBufferAccess>} */
+tcuTexture.Texture2DArrayView.prototype.getLevels = function() { return this.m_levels; };
+
+/**
+ * @param {number} r
+ * @return {number} layer corresponding to requested sampling 'r' coordinate
+ */
+tcuTexture.Texture2DArrayView.prototype.selectLayer = function(r) {
+ DE_ASSERT(this.m_numLevels > 0 && this.m_levels);
+ return deMath.clamp(Math.round(r), 0, this.m_levels[0].getDepth() - 1);
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {Array<number>} texCoord
+ * @param {number=} lod
+ * @return {Array<number>} Pixel color
+ */
+tcuTexture.Texture2DArrayView.prototype.sample = function(sampler, texCoord, lod) {
+ lod = lod || 0;
+ return tcuTexture.sampleLevelArray2D(this.m_levels, this.m_numLevels, sampler, texCoord[0], texCoord[1], this.selectLayer(texCoord[2]), lod);
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {Array<number>} texCoord
+ * @param {number} lod
+ * @param {Array<number>} offset
+ * @return {Array<number>}
+ */
+tcuTexture.Texture2DArrayView.prototype.sampleOffset = function(sampler, texCoord, lod, offset) {
+ return tcuTexture.sampleLevelArray2DOffset(this.m_levels, this.m_numLevels, sampler, texCoord, lod, [offset[0], offset[1], this.selectLayer(texCoord[2])]);
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} ref
+ * @param {Array<number>} texCoord
+ * @param {number} lod
+ * @param {Array<number>} offset
+ * @return {number}
+ */
+tcuTexture.Texture2DArrayView.prototype.sampleCompareOffset = function(sampler, ref, texCoord, lod, offset) {
+ return tcuTexture.sampleLevelArray2DCompare(this.m_levels, this.m_numLevels, sampler, ref, texCoord[0], texCoord[1], lod, [offset[0], offset[1], this.selectLayer(texCoord[2])]);
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} ref
+ * @param {Array<number>} texCoord
+ * @param {number} lod
+ * @return {number}
+ */
+tcuTexture.Texture2DArrayView.prototype.sampleCompare = function(sampler, ref, texCoord, lod) {
+ return tcuTexture.sampleLevelArray2DCompare(this.m_levels, this.m_numLevels, sampler, ref, texCoord[0], texCoord[1], lod, [0, 0, this.selectLayer(texCoord[2])]);
+};
+
+/**
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
+ * @param {number} numLevels
+ * @param {tcuTexture.Sampler} sampler
+ * @param {Array<number>} texCoord
+ * @param {number} lod
+ * @param {Array<number>} offset
+ * @return {Array<number>}
+ */
+tcuTexture.sampleLevelArray2DOffset = function(levels, numLevels, sampler, texCoord, lod, offset) {
+ /** @type {boolean} */ var magnified = lod <= sampler.lodThreshold;
+ /** @type {tcuTexture.FilterMode} */ var filterMode = magnified ? sampler.magFilter : sampler.minFilter;
+ /** @type {number} */ var maxLevel;
+ /** @type {tcuTexture.FilterMode} */ var levelFilter;
+ switch (filterMode) {
+ case tcuTexture.FilterMode.NEAREST: return levels[0].sample2DOffset(sampler, filterMode, texCoord[0], texCoord[1], offset);
+ case tcuTexture.FilterMode.LINEAR: return levels[0].sample2DOffset(sampler, filterMode, texCoord[0], texCoord[1], offset);
+
+ case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST:
+ case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST:
+ maxLevel = numLevels - 1;
+ /** @type {number} */ var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel);
+ levelFilter = (filterMode === tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
+
+ return levels[level].sample2DOffset(sampler, levelFilter, texCoord[0], texCoord[1], offset);
+
+ case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR:
+ case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR:
+ maxLevel = numLevels - 1;
+ /** @type {number} */ var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel);
+ /** @type {number} */ var level1 = Math.min(maxLevel, level0 + 1);
+ levelFilter = (filterMode === tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
+ /** @type {number} */ var f = deMath.deFloatFrac(lod);
+ /** @type {Array<number>} */ var t0 = levels[level0].sample2DOffset(sampler, levelFilter, texCoord[0], texCoord[1], offset);
+ /** @type {Array<number>} */ var t1 = levels[level1].sample2DOffset(sampler, levelFilter, texCoord[0], texCoord[1], offset);
+
+ return deMath.add(deMath.scale(t0, (1.0 - f)), deMath.scale(t1, f));
+
+ default:
+ return [0.0, 0.0, 0.0, 0.0];
+ }
+};
+
+/**
+ * @constructor
+ * @param {number} numLevels
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
+ */
+tcuTexture.Texture3DView = function(numLevels, levels) {
+ this.m_numLevels = numLevels;
+ this.m_levels = levels;
+};
+
+/** @return {number} */
+tcuTexture.Texture3DView.prototype.getNumLevels = function() { return this.m_numLevels; };
+/** @return {number} */
+tcuTexture.Texture3DView.prototype.getWidth = function() { return this.m_numLevels > 0 ? this.m_levels[0].getWidth() : 0; };
+/** @return {number} */
+tcuTexture.Texture3DView.prototype.getHeight = function() { return this.m_numLevels > 0 ? this.m_levels[0].getHeight() : 0; };
+/** @return {number} */
+tcuTexture.Texture3DView.prototype.getDepth = function() { return this.m_numLevels > 0 ? this.m_levels[0].getDepth() : 0; };
+/**
+ * @param {number} ndx
+ * @return {tcuTexture.ConstPixelBufferAccess}
+ */
+tcuTexture.Texture3DView.prototype.getLevel = function(ndx) { DE_ASSERT(deMath.deInBounds32(ndx, 0, this.m_numLevels)); return this.m_levels[ndx]; };
+/** @return {Array<tcuTexture.ConstPixelBufferAccess>} */
+tcuTexture.Texture3DView.prototype.getLevels = function() { return this.m_levels; };
+
+/**
+ * @param {number} baseLevel
+ * @param {number} maxLevel
+ * return {tcuTexture.Texture3DView}
+ */
+tcuTexture.Texture3DView.prototype.getSubView = function(baseLevel, maxLevel) {
+ var clampedBase = deMath.clamp(baseLevel, 0, this.m_numLevels - 1);
+ var clampedMax = deMath.clamp(maxLevel, clampedBase, this.m_numLevels - 1);
+ var numLevels = clampedMax - clampedBase + 1;
+ return new tcuTexture.Texture3DView(numLevels, this.m_levels.slice(clampedBase, numLevels));
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {Array<number>} texCoord
+ * @param {number=} lod
+ * @return {Array<number>} Pixel color
+ */
+tcuTexture.Texture3DView.prototype.sample = function(sampler, texCoord, lod) {
+ lod = lod || 0;
+ return tcuTexture.sampleLevelArray3D(this.m_levels, this.m_numLevels, sampler, texCoord[0], texCoord[1], texCoord[2], lod);
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} ref
+ * @param {Array<number>} texCoord
+ * @param {number} lod
+ * @return {number}
+ */
+tcuTexture.Texture3DView.prototype.sampleCompare = function(sampler, ref, texCoord, lod) {
+ throw new Error('Unimplemented');
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {Array<number>} texCoord
+ * @param {number} lod
+ * @param {Array<number>} offset
+ * @return {Array<number>}
+ */
+tcuTexture.Texture3DView.prototype.sampleOffset = function(sampler, texCoord, lod, offset) {
+ return tcuTexture.sampleLevelArray3DOffset(this.m_levels, this.m_numLevels, sampler, texCoord[0], texCoord[1], texCoord[2], lod, offset);
+};
+
+/* TODO: All view classes are very similar. They should have a common base class */
+
+/**
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} levels
+ * @param {number} numLevels
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} s
+ * @param {number} t
+ * @param {number} r
+ * @param {number} lod
+ * @param {Array<number>} offset
+ * @return {Array<number>}
+ */
+tcuTexture.sampleLevelArray3DOffset = function(levels, numLevels, sampler, s, t, r, lod, offset) {
+ /** @type {boolean} */ var magnified = lod <= sampler.lodThreshold;
+ /** @type {tcuTexture.FilterMode} */ var filterMode = magnified ? sampler.magFilter : sampler.minFilter;
+ /** @type {number} */ var maxLevel;
+ /** @type {tcuTexture.FilterMode} */ var levelFilter;
+ switch (filterMode) {
+ case tcuTexture.FilterMode.NEAREST: return levels[0].sample3DOffset(sampler, filterMode, s, t, r, offset);
+ case tcuTexture.FilterMode.LINEAR: return levels[0].sample3DOffset(sampler, filterMode, s, t, r, offset);
+
+ case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST:
+ case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST:
+ maxLevel = numLevels - 1;
+ /** @type {number} */ var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel);
+ levelFilter = (filterMode === tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
+
+ return levels[level].sample3DOffset(sampler, levelFilter, s, t, r, offset);
+
+ case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR:
+ case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR:
+ maxLevel = numLevels - 1;
+ /** @type {number} */ var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel);
+ /** @type {number} */ var level1 = Math.min(maxLevel, level0 + 1);
+ levelFilter = (filterMode === tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
+ /** @type {number} */ var f = deMath.deFloatFrac(lod);
+ /** @type {Array<number>} */ var t0 = levels[level0].sample3DOffset(sampler, levelFilter, s, t, r, offset);
+ /** @type {Array<number>} */ var t1 = levels[level1].sample3DOffset(sampler, levelFilter, s, t, r, offset);
+
+ return deMath.add(deMath.scale(t0, (1.0 - f)), deMath.scale(t1, f));
+
+ default:
+ throw new Error('Filter mode not supported');
+ }
+};
+
+/**
+ * @param {number} width
+ * @param {number=} height
+ * @param {number=} depth
+ * @return {number} Number of pyramid levels
+ */
+tcuTexture.computeMipPyramidLevels = function(width, height, depth) {
+ if (depth !== undefined)
+ return Math.floor(Math.log2(Math.max(width, Math.max(height, depth)))) + 1;
+ else if (height !== undefined)
+ return Math.floor(Math.log2(Math.max(width, height))) + 1;
+ else
+ return Math.floor(Math.log2(width)) + 1;
+};
+
+/**
+ * @param {number} baseLevelSize
+ * @param {number} levelNdx
+ */
+tcuTexture.getMipPyramidLevelSize = function(baseLevelSize, levelNdx) {
+ return Math.max(baseLevelSize >> levelNdx, 1);
+};
+
+/**
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} faceAccesses
+ * @param {tcuTexture.CubeFace} baseFace
+ * @param {number} u
+ * @param {number} v
+ * @param {number} depth
+ * @return {Array<Array<number>>}
+ */
+tcuTexture.getCubeLinearSamples = function(faceAccesses, baseFace, u, v, depth) {
+ DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
+ /** @type {Array<Array<number>>} */ var dst = [];
+ var size = faceAccesses[0].getWidth();
+ var x0 = Math.floor(u - 0.5);
+ var x1 = x0 + 1;
+ var y0 = Math.floor(v - 0.5);
+ var y1 = y0 + 1;
+ var baseSampleCoords =
+ [
+ [x0, y0],
+ [x1, y0],
+ [x0, y1],
+ [x1, y1]
+ ];
+ /** @type {Array<Array<number>>} */ var sampleColors = [];
+ /** @type {Array<boolean>} */ var hasBothCoordsOutOfBounds = []; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
+
+ // Find correct faces and coordinates for out-of-bounds sample coordinates.
+
+ for (var i = 0; i < 4; i++) {
+ /** @type {tcuTexture.CubeFaceCoords} */ var coords = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(baseFace, baseSampleCoords[i]), size);
+ hasBothCoordsOutOfBounds[i] = coords == null;
+ if (!hasBothCoordsOutOfBounds[i])
+ sampleColors[i] = tcuTexture.lookup(faceAccesses[coords.face], coords.s, coords.t, depth);
+ }
+
+ // If a sample was out of bounds in both u and v, we get its color from the average of the three other samples.
+ // \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only
+ // requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample
+ // must have this color as well.
+
+ var bothOutOfBoundsNdx = -1;
+ for (var i = 0; i < 4; i++) {
+ if (hasBothCoordsOutOfBounds[i]) {
+ DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
+ bothOutOfBoundsNdx = i;
+ }
+ }
+ if (bothOutOfBoundsNdx != -1) {
+ sampleColors[bothOutOfBoundsNdx] = [0, 0, 0, 0];
+ for (var i = 0; i < 4; i++)
+ if (i != bothOutOfBoundsNdx)
+ sampleColors[bothOutOfBoundsNdx] = deMath.add(sampleColors[bothOutOfBoundsNdx], sampleColors[i]);
+
+ sampleColors[bothOutOfBoundsNdx] = deMath.scale(sampleColors[bothOutOfBoundsNdx], (1.0 / 3.0));
+ }
+
+ for (var i = 0; i < sampleColors.length; i++)
+ dst[i] = sampleColors[i];
+
+ return dst;
+};
+
+// \todo [2014-02-19 pyry] Optimize faceAccesses
+/**
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} faceAccesses
+ * @param {tcuTexture.CubeFace} baseFace
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} s
+ * @param {number} t
+ * @param {number} depth
+ * @return {Array<number>}
+ */
+tcuTexture.sampleCubeSeamlessLinear = function(faceAccesses, baseFace, sampler, s, t, depth) {
+ DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
+
+ var size = faceAccesses[0].getWidth();
+ // Non-normalized coordinates.
+ var u = s;
+ var v = t;
+
+ if (sampler.normalizedCoords) {
+ u = tcuTexture.unnormalize(sampler.wrapS, s, size);
+ v = tcuTexture.unnormalize(sampler.wrapT, t, size);
+ }
+
+ // Get sample colors.
+
+ /** @type {Array<Array<number>>} */ var sampleColors = tcuTexture.getCubeLinearSamples(faceAccesses, baseFace, u, v, depth);
+
+ // Interpolate.
+
+ var a = deMath.deFloatFrac(u - 0.5);
+ var b = deMath.deFloatFrac(v - 0.5);
+
+ return deMath.add((deMath.scale(deMath.scale(sampleColors[0], (1.0 - a)), (1.0 - b))),
+ deMath.add((deMath.scale(deMath.scale(sampleColors[1], (a)), (1.0 - b))),
+ deMath.add((deMath.scale(deMath.scale(sampleColors[2], (1.0 - a)), (b))),
+ (deMath.scale(deMath.scale(sampleColors[3], (a)), (b))))));
+};
+
+/**
+ * @param {Array<Array<tcuTexture.ConstPixelBufferAccess>>} faces
+ * @param {number} numLevels
+ * @param {tcuTexture.CubeFace} face
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} s
+ * @param {number} t
+ * @param {number} depth
+ * @param {number=} lod
+ * @return {Array<number>}
+ */
+tcuTexture.sampleLevelArrayCubeSeamless = function(faces, numLevels, face, sampler, s, t, depth, lod) {
+ lod = lod || 0;
+ var magnified = lod <= sampler.lodThreshold;
+ /** @type {tcuTexture.FilterMode} */ var filterMode = magnified ? sampler.magFilter : sampler.minFilter;
+ /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faceAccesses = [];
+ /** @type {tcuTexture.FilterMode}*/ var levelFilter;
+
+ switch (filterMode) {
+ case tcuTexture.FilterMode.NEAREST:
+ return tcuTexture.sampleCubeSeamlessNearest(faces[face][0], sampler, s, t, depth);
+
+ case tcuTexture.FilterMode.LINEAR: {
+ faceAccesses = [];
+ for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++)
+ faceAccesses[i] = faces[i][0];
+
+ return tcuTexture.sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
+ }
+
+ case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST:
+ case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: {
+ var maxLevel = numLevels - 1;
+ var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel);
+ levelFilter = (filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
+
+ if (levelFilter == tcuTexture.FilterMode.NEAREST)
+ return tcuTexture.sampleCubeSeamlessNearest(faces[face][level], sampler, s, t, depth);
+ else {
+ DE_ASSERT(levelFilter == tcuTexture.FilterMode.LINEAR);
+
+ faceAccesses = [];
+ for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++)
+ faceAccesses[i] = faces[i][level];
+
+ return tcuTexture.sampleCubeSeamlessLinear(faceAccesses, face, sampler, s, t, depth);
+ }
+ }
+
+ case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR:
+ case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: {
+ var maxLevel = numLevels - 1;
+ var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel);
+ var level1 = Math.min(maxLevel, level0 + 1);
+ levelFilter = (filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
+ var f = deMath.deFloatFrac(lod);
+ var t0 = [];
+ var t1 = [];
+
+ if (levelFilter == tcuTexture.FilterMode.NEAREST) {
+ t0 = tcuTexture.sampleCubeSeamlessNearest(faces[face][level0], sampler, s, t, depth);
+ t1 = tcuTexture.sampleCubeSeamlessNearest(faces[face][level1], sampler, s, t, depth);
+ } else {
+ DE_ASSERT(levelFilter == tcuTexture.FilterMode.LINEAR);
+
+ /** @type {Array<tcuTexture.ConstPixelBufferAccess>}*/ var faceAccesses0 = [];
+ /** @type {Array<tcuTexture.ConstPixelBufferAccess>}*/ var faceAccesses1 = [];
+ for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++) {
+ faceAccesses0[i] = faces[i][level0];
+ faceAccesses1[i] = faces[i][level1];
+ }
+
+ t0 = tcuTexture.sampleCubeSeamlessLinear(faceAccesses0, face, sampler, s, t, depth);
+ t1 = tcuTexture.sampleCubeSeamlessLinear(faceAccesses1, face, sampler, s, t, depth);
+ }
+
+ return deMath.add(deMath.scale(t0, (1.0 - f)), deMath.scale(t1, f));
+ }
+
+ default:
+ throw new Error('Unsupported filter mode');
+ }
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} faceAccess
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} ref
+ * @param {number} s
+ * @param {number} t
+ * @param {number=} depth
+ * @return {number}
+ */
+tcuTexture.sampleCubeSeamlessNearestCompare = function(faceAccess, sampler, ref, s, t, depth) {
+ depth = depth ? depth : 0;
+ /** @type {tcuTexture.Sampler} */ var clampingSampler = deUtil.clone(sampler);
+ clampingSampler.wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ clampingSampler.wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ return faceAccess.sample2DCompare(clampingSampler, tcuTexture.FilterMode.NEAREST, ref, s, t, [0, 0, depth]);
+};
+
+/**
+ * @param {Array<tcuTexture.ConstPixelBufferAccess>} faceAccesses
+ * @param {tcuTexture.CubeFace} baseFace
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} ref
+ * @param {number} s
+ * @param {number} t
+ * @return {number}
+ */
+tcuTexture.sampleCubeSeamlessLinearCompare = function(faceAccesses, baseFace, sampler, ref, s, t) {
+ DE_ASSERT(faceAccesses[0].getWidth() == faceAccesses[0].getHeight());
+
+ var size = faceAccesses[0].getWidth();
+ // Non-normalized coordinates.
+ var u = s;
+ var v = t;
+
+ if (sampler.normalizedCoords) {
+ u = tcuTexture.unnormalize(sampler.wrapS, s, size);
+ v = tcuTexture.unnormalize(sampler.wrapT, t, size);
+ }
+
+ var x0 = Math.floor(u - 0.5);
+ var x1 = x0 + 1;
+ var y0 = Math.floor(v - 0.5);
+ var y1 = y0 + 1;
+ var baseSampleCoords = [
+ [x0, y0],
+ [x1, y0],
+ [x0, y1],
+ [x1, y1]
+ ];
+ var sampleRes = [];
+ var hasBothCoordsOutOfBounds = []; //!< Whether correctCubeFace() returns CUBEFACE_LAST, i.e. both u and v are out of bounds.
+
+ // Find correct faces and coordinates for out-of-bounds sample coordinates.
+
+ for (var i = 0; i < 4; i++) {
+ /** @type {tcuTexture.CubeFaceCoords} */ var coords = tcuTexture.remapCubeEdgeCoords(new tcuTexture.CubeFaceCoords(baseFace, baseSampleCoords[i]), size);
+ hasBothCoordsOutOfBounds[i] = coords == null;
+
+ if (!hasBothCoordsOutOfBounds[i]) {
+ var isFixedPointDepth = tcuTexture.isFixedPointDepthTextureFormat(faceAccesses[coords.face].getFormat());
+
+ sampleRes[i] = tcuTexture.execCompare(faceAccesses[coords.face].getPixel(coords.s, coords.t), sampler.compare, sampler.compareChannel, ref, isFixedPointDepth);
+ }
+ }
+
+ // If a sample was out of bounds in both u and v, we get its color from the average of the three other samples.
+ // \note This averaging behavior is not required by the GLES3 spec (though it is recommended). GLES3 spec only
+ // requires that if the three other samples all have the same color, then the doubly-out-of-bounds sample
+ // must have this color as well.
+
+ var bothOutOfBoundsNdx = -1;
+ for (var i = 0; i < 4; i++) {
+ if (hasBothCoordsOutOfBounds[i]) {
+ DE_ASSERT(bothOutOfBoundsNdx < 0); // Only one sample can be out of bounds in both u and v.
+ bothOutOfBoundsNdx = i;
+ }
+ }
+ if (bothOutOfBoundsNdx != -1) {
+ sampleRes[bothOutOfBoundsNdx] = 0.0;
+ for (var i = 0; i < 4; i++)
+ if (i != bothOutOfBoundsNdx)
+ sampleRes[bothOutOfBoundsNdx] += sampleRes[i];
+
+ sampleRes[bothOutOfBoundsNdx] = sampleRes[bothOutOfBoundsNdx] * (1.0 / 3.0);
+ }
+
+ // Interpolate.
+
+ var a = deMath.deFloatFrac(u - 0.5);
+ var b = deMath.deFloatFrac(v - 0.5);
+
+ return (sampleRes[0] * (1.0 - a) * (1.0 - b)) +
+ (sampleRes[1] * (a) * (1.0 - b)) +
+ (sampleRes[2] * (1.0 - a) * (b)) +
+ (sampleRes[3] * (a) * (b));
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} faceAccess
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} s
+ * @param {number} t
+ * @param {number} depth
+ * @return {Array<number>}
+ */
+tcuTexture.sampleCubeSeamlessNearest = function(faceAccess, sampler, s, t, depth) {
+ /** @type {tcuTexture.Sampler} */ var clampingSampler = sampler;
+ clampingSampler.wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ clampingSampler.wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ return faceAccess.sample2D(clampingSampler, tcuTexture.FilterMode.NEAREST, s, t, depth);
+};
+
+/**
+ * @param {Array<number>} coords Vec3 cube coordinates
+ * @return {tcuTexture.CubeFaceCoords}
+ */
+tcuTexture.getCubeFaceCoords = function(coords) {
+ var face = tcuTexture.selectCubeFace(coords);
+ return new tcuTexture.CubeFaceCoords(face, tcuTexture.projectToFace(face, coords));
+};
+
+/**
+ * @param {Array<Array<tcuTexture.ConstPixelBufferAccess>>} faces
+ * @param {number} numLevels
+ * @param {tcuTexture.CubeFace} face
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} ref
+ * @param {number} s
+ * @param {number} t
+ * @param {number} lod
+ * @return {number}
+ */
+tcuTexture.sampleLevelArrayCubeSeamlessCompare = function(faces, numLevels, face, sampler, ref, s, t, lod) {
+ var magnified = lod <= sampler.lodThreshold;
+ /** @type {tcuTexture.FilterMode}*/ var filterMode = magnified ? sampler.magFilter : sampler.minFilter;
+ /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faceAccesses = [];
+ /** @type {tcuTexture.FilterMode} */ var levelFilter;
+
+ switch (filterMode) {
+ case tcuTexture.FilterMode.NEAREST:
+ return tcuTexture.sampleCubeSeamlessNearestCompare(faces[face][0], sampler, ref, s, t);
+
+ case tcuTexture.FilterMode.LINEAR: {
+ faceAccesses = [];
+ for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++)
+ faceAccesses[i] = faces[i][0];
+
+ return tcuTexture.sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
+ }
+
+ case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST:
+ case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: {
+ var maxLevel = numLevels - 1;
+ var level = deMath.clamp(Math.ceil(lod + 0.5) - 1, 0, maxLevel);
+ levelFilter = filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
+
+ if (levelFilter == tcuTexture.FilterMode.NEAREST)
+ return tcuTexture.sampleCubeSeamlessNearestCompare(faces[face][level], sampler, ref, s, t);
+ else {
+ DE_ASSERT(levelFilter == tcuTexture.FilterMode.LINEAR);
+
+ faceAccesses = [];
+ for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++)
+ faceAccesses[i] = faces[i][level];
+
+ return tcuTexture.sampleCubeSeamlessLinearCompare(faceAccesses, face, sampler, ref, s, t);
+ }
+ }
+
+ case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR:
+ case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: {
+ var maxLevel = numLevels - 1;
+ var level0 = deMath.clamp(Math.floor(lod), 0, maxLevel);
+ var level1 = Math.min(maxLevel, level0 + 1);
+ levelFilter = (filterMode == tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
+ var f = deMath.deFloatFrac(lod);
+ var t0;
+ var t1;
+
+ if (levelFilter == tcuTexture.FilterMode.NEAREST) {
+ t0 = tcuTexture.sampleCubeSeamlessNearestCompare(faces[face][level0], sampler, ref, s, t);
+ t1 = tcuTexture.sampleCubeSeamlessNearestCompare(faces[face][level1], sampler, ref, s, t);
+ } else {
+ DE_ASSERT(levelFilter == tcuTexture.FilterMode.LINEAR);
+
+ /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faceAccesses0 = [];
+ /** @type {Array<tcuTexture.ConstPixelBufferAccess>} */ var faceAccesses1 = [];
+ for (var i = 0; i < Object.keys(tcuTexture.CubeFace).length; i++) {
+ faceAccesses0[i] = faces[i][level0];
+ faceAccesses1[i] = faces[i][level1];
+ }
+
+ t0 = tcuTexture.sampleCubeSeamlessLinearCompare(faceAccesses0, face, sampler, ref, s, t);
+ t1 = tcuTexture.sampleCubeSeamlessLinearCompare(faceAccesses1, face, sampler, ref, s, t);
+ }
+
+ return t0 * (1.0 - f) + t1 * f;
+ }
+
+ default:
+ throw new Error('Unsupported filter mode');
+ }
+};
+
+/**
+ * @constructor
+ * @extends {tcuTexture.TextureLevelPyramid}
+ * @param {tcuTexture.TextureFormat} format
+ * @param {number} width
+ * @param {number} height
+ */
+tcuTexture.Texture2D = function(format, width, height) {
+ tcuTexture.TextureLevelPyramid.call(this, format, tcuTexture.computeMipPyramidLevels(width, height));
+ this.m_width = width;
+ this.m_height = height;
+ this.m_view = new tcuTexture.Texture2DView(this.getNumLevels(), this.getLevels());
+};
+
+tcuTexture.Texture2D.prototype = Object.create(tcuTexture.TextureLevelPyramid.prototype);
+tcuTexture.Texture2D.prototype.constructor = tcuTexture.Texture2D;
+
+tcuTexture.Texture2D.prototype.getWidth = function() { return this.m_width; };
+tcuTexture.Texture2D.prototype.getHeight = function() { return this.m_height; };
+/** @return {tcuTexture.Texture2DView} */
+tcuTexture.Texture2D.prototype.getView = function() { return this.m_view; };
+
+/**
+ * @param {number} baseLevel
+ * @param {number} maxLevel
+ * @return {tcuTexture.Texture2DView}
+ */
+tcuTexture.Texture2D.prototype.getSubView = function(baseLevel, maxLevel) { return this.m_view.getSubView(baseLevel, maxLevel); };
+
+/**
+ * @param {number} levelNdx
+ */
+tcuTexture.Texture2D.prototype.allocLevel = function(levelNdx) {
+ DE_ASSERT(deMath.deInBounds32(levelNdx, 0, this.getNumLevels()));
+
+ var width = tcuTexture.getMipPyramidLevelSize(this.m_width, levelNdx);
+ var height = tcuTexture.getMipPyramidLevelSize(this.m_height, levelNdx);
+
+ tcuTexture.TextureLevelPyramid.prototype.allocLevel.call(this, levelNdx, width, height, 1);
+};
+
+/**
+ * @constructor
+ * @extends {tcuTexture.TextureLevelPyramid}
+ * @param {tcuTexture.TextureFormat} format
+ * @param {number} width
+ * @param {number} height
+ * @param {number} numLayers
+ */
+tcuTexture.Texture2DArray = function(format, width, height, numLayers) {
+ tcuTexture.TextureLevelPyramid.call(this, format, tcuTexture.computeMipPyramidLevels(width, height));
+ this.m_width = width;
+ this.m_height = height;
+ this.m_numLayers = numLayers;
+ this.m_view = new tcuTexture.Texture2DArrayView(this.getNumLevels(), this.getLevels());
+};
+
+tcuTexture.Texture2DArray.prototype = Object.create(tcuTexture.TextureLevelPyramid.prototype);
+tcuTexture.Texture2DArray.prototype.constructor = tcuTexture.Texture2DArray;
+/** @return {tcuTexture.Texture2DArrayView} */
+tcuTexture.Texture2DArray.prototype.getView = function() { return this.m_view; };
+
+/** @return {number} */
+tcuTexture.Texture2DArray.prototype.getWidth = function() { return this.m_width; };
+
+/** @return {number} */
+tcuTexture.Texture2DArray.prototype.getHeight = function() { return this.m_height; };
+
+/**
+ * @param {number} levelNdx
+ */
+tcuTexture.Texture2DArray.prototype.allocLevel = function(levelNdx) {
+ DE_ASSERT(deMath.deInBounds32(levelNdx, 0, this.getNumLevels()));
+
+ var width = tcuTexture.getMipPyramidLevelSize(this.m_width, levelNdx);
+ var height = tcuTexture.getMipPyramidLevelSize(this.m_height, levelNdx);
+
+ tcuTexture.TextureLevelPyramid.prototype.allocLevel.call(this, levelNdx, width, height, this.m_numLayers);
+};
+
+/**
+ * @constructor
+ * @extends {tcuTexture.TextureLevelPyramid}
+ * @param {tcuTexture.TextureFormat} format
+ * @param {number} width
+ * @param {number} height
+ * @param {number} depth
+ */
+tcuTexture.Texture3D = function(format, width, height, depth) {
+ tcuTexture.TextureLevelPyramid.call(this, format, tcuTexture.computeMipPyramidLevels(width, height, depth));
+ this.m_width = width;
+ this.m_height = height;
+ this.m_depth = depth;
+ this.m_view = new tcuTexture.Texture3DView(this.getNumLevels(), this.getLevels());
+};
+
+tcuTexture.Texture3D.prototype = Object.create(tcuTexture.TextureLevelPyramid.prototype);
+tcuTexture.Texture3D.prototype.constructor = tcuTexture.Texture3D;
+
+tcuTexture.Texture3D.prototype.getWidth = function() { return this.m_width; };
+tcuTexture.Texture3D.prototype.getHeight = function() { return this.m_height; };
+tcuTexture.Texture3D.prototype.getDepth = function() { return this.m_depth; };
+tcuTexture.Texture3D.prototype.getView = function() { return this.m_view; };
+/**
+ * @param {number} baseLevel
+ * @param {number} maxLevel
+ * @return {tcuTexture.Texture3DView}
+ */
+tcuTexture.Texture3D.prototype.getSubView = function(baseLevel, maxLevel) { return this.m_view.getSubView(baseLevel, maxLevel); };
+
+/**
+ * @param {number} levelNdx
+ */
+tcuTexture.Texture3D.prototype.allocLevel = function(levelNdx) {
+ DE_ASSERT(deMath.deInBounds32(levelNdx, 0, this.getNumLevels()));
+
+ var width = tcuTexture.getMipPyramidLevelSize(this.m_width, levelNdx);
+ var height = tcuTexture.getMipPyramidLevelSize(this.m_height, levelNdx);
+ var depth = tcuTexture.getMipPyramidLevelSize(this.m_depth, levelNdx);
+
+ tcuTexture.TextureLevelPyramid.prototype.allocLevel.call(this, levelNdx, width, height, depth);
+};
+
+/**
+ * @constructor
+ * @param {number} numLevels
+ * @param {Array<Array<tcuTexture.ConstPixelBufferAccess>>} levels
+ */
+tcuTexture.TextureCubeView = function(numLevels, levels) {
+ this.m_numLevels = numLevels;
+ this.m_levels = levels;
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {Array<number>} texCoord
+ * @param {number=} lod
+ * @return {Array<number>} Pixel color
+ */
+tcuTexture.TextureCubeView.prototype.sample = function(sampler, texCoord, lod) {
+ DE_ASSERT(sampler.compare == tcuTexture.CompareMode.COMPAREMODE_NONE);
+
+ // Computes (face, s, t).
+ var coords = tcuTexture.getCubeFaceCoords(texCoord);
+ if (sampler.seamlessCubeMap)
+ return tcuTexture.sampleLevelArrayCubeSeamless(this.m_levels, this.m_numLevels, coords.face, sampler, coords.s, coords.t, 0 /* depth */, lod);
+ else
+ return tcuTexture.sampleLevelArray2D(this.m_levels[coords.face], this.m_numLevels, sampler, coords.s, coords.t, 0 /* depth */, lod);
+};
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {number} ref
+ * @param {Array<number>} texCoord
+ * @param {number} lod
+ * @return {number}
+ */
+tcuTexture.TextureCubeView.prototype.sampleCompare = function(sampler, ref, texCoord, lod) {
+ DE_ASSERT(sampler.compare != tcuTexture.CompareMode.COMPAREMODE_NONE);
+
+ // Computes (face, s, t).
+ var coords = tcuTexture.getCubeFaceCoords(texCoord);
+ if (sampler.seamlessCubeMap)
+ return tcuTexture.sampleLevelArrayCubeSeamlessCompare(this.m_levels, this.m_numLevels, coords.face, sampler, ref, coords.s, coords.t, lod);
+ else
+ return tcuTexture.sampleLevelArray2DCompare(this.m_levels[coords.face], this.m_numLevels, sampler, ref, coords.s, coords.t, lod, [0, 0, 0]);
+};
+
+/**
+ * @param {tcuTexture.CubeFace} face
+ * @return {Array<tcuTexture.ConstPixelBufferAccess>}
+ */
+tcuTexture.TextureCubeView.prototype.getFaceLevels = function(face) { return this.m_levels[face]; };
+/** @return {number} */
+tcuTexture.TextureCubeView.prototype.getSize = function() { return this.m_numLevels > 0 ? this.m_levels[0][0].getWidth() : 0; };
+
+/** @return {number} */
+tcuTexture.TextureCubeView.prototype.getNumLevels = function() { return this.m_numLevels; };
+
+/**
+ * @param {number} ndx
+ * @param {tcuTexture.CubeFace} face
+ * @return {tcuTexture.ConstPixelBufferAccess}
+ */
+tcuTexture.TextureCubeView.prototype.getLevelFace = function(ndx, face) {
+ assertMsgOptions(0 <= ndx && ndx < this.m_numLevels, '', false, true);
+ return this.m_levels[face][ndx];
+};
+
+/**
+ * @param {number} baseLevel
+ * @param {number} maxLevel
+ * @return {tcuTexture.TextureCubeView}
+ */
+tcuTexture.TextureCubeView.prototype.getSubView = function(baseLevel, maxLevel) {
+ var clampedBase = deMath.clamp(baseLevel, 0, this.m_numLevels - 1);
+ var clampedMax = deMath.clamp(maxLevel, clampedBase, this.m_numLevels - 1);
+ var numLevels = clampedMax - clampedBase + 1;
+ var levels = [];
+ for (var face in tcuTexture.CubeFace)
+ levels.push(this.getFaceLevels(tcuTexture.CubeFace[face]).slice(clampedBase, numLevels));
+
+ return new tcuTexture.TextureCubeView(numLevels, levels);
+};
+
+/**
+ * @constructor
+ * @param {tcuTexture.TextureFormat} format
+ * @param {number} size
+ */
+tcuTexture.TextureCube = function(format, size) {
+ this.m_format = format;
+ this.m_size = size;
+ this.m_data = [];
+ this.m_data.length = Object.keys(tcuTexture.CubeFace).length;
+ this.m_access = [];
+ this.m_access.length = Object.keys(tcuTexture.CubeFace).length;
+
+ var numLevels = tcuTexture.computeMipPyramidLevels(this.m_size);
+ var levels = [];
+ levels.length = Object.keys(tcuTexture.CubeFace).length;
+
+ for (var face in tcuTexture.CubeFace) {
+ this.m_data[tcuTexture.CubeFace[face]] = [];
+ for (var i = 0; i < numLevels; i++)
+ this.m_data[tcuTexture.CubeFace[face]].push(new tcuTexture.DeqpArrayBuffer());
+ this.m_access[tcuTexture.CubeFace[face]] = [];
+ this.m_access[tcuTexture.CubeFace[face]].length = numLevels;
+ levels[tcuTexture.CubeFace[face]] = this.m_access[tcuTexture.CubeFace[face]];
+ }
+
+ this.m_view = new tcuTexture.TextureCubeView(numLevels, levels);
+};
+
+/** @return {tcuTexture.TextureFormat} */
+tcuTexture.TextureCube.prototype.getFormat = function() { return this.m_format; };
+/** @return {number} */
+tcuTexture.TextureCube.prototype.getSize = function() { return this.m_size; };
+/** @return {tcuTexture.TextureCubeView} */
+tcuTexture.TextureCube.prototype.getView = function() { return this.m_view; };
+/**
+ * @param {number} ndx Level index
+ * @param {tcuTexture.CubeFace} face
+ * @return {tcuTexture.PixelBufferAccess}
+ */
+tcuTexture.TextureCube.prototype.getLevelFace = function(ndx, face) { return this.m_access[face][ndx]; };
+/** @return {number} */
+tcuTexture.TextureCube.prototype.getNumLevels = function() { return this.m_access[0].length; };
+
+/**
+ * @param {tcuTexture.Sampler} sampler
+ * @param {Array<number>} texCoord
+ * @param {number} lod
+ * @return {Array<number>} Pixel color
+ */
+tcuTexture.TextureCube.prototype.sample = function(sampler, texCoord, lod) {
+ return this.m_view.sample(sampler, texCoord, lod);
+};
+
+/**
+ * @param {number} baseLevel
+ * @param {number} maxLevel
+ * @return {tcuTexture.TextureCubeView}
+ */
+tcuTexture.TextureCube.prototype.getSubView = function(baseLevel, maxLevel) { return this.m_view.getSubView(baseLevel, maxLevel); };
+
+/**
+ * @param {tcuTexture.CubeFace} face
+ * @param {number} levelNdx
+ * @return {boolean}
+ */
+tcuTexture.TextureCube.prototype.isLevelEmpty = function(face, levelNdx) {
+ return this.m_data[face][levelNdx].empty();
+};
+
+/**
+ * @param {tcuTexture.CubeFace} face
+ * @param {number} levelNdx
+ */
+tcuTexture.TextureCube.prototype.allocLevel = function(face, levelNdx) {
+ /** @const */ var size = tcuTexture.getMipPyramidLevelSize(this.m_size, levelNdx);
+ /** @const*/ var dataSize = this.m_format.getPixelSize() * size * size;
+ DE_ASSERT(this.isLevelEmpty(face, levelNdx));
+
+ this.m_data[face][levelNdx].setStorage(dataSize);
+ this.m_access[face][levelNdx] = new tcuTexture.PixelBufferAccess({
+ format: this.m_format,
+ width: size,
+ height: size,
+ depth: 1,
+ data: this.m_data[face][levelNdx].m_ptr
+ });
+};
+
+/**
+ * @param {Array<number>} coords Cube coordinates
+ * @return {tcuTexture.CubeFace}
+ */
+tcuTexture.selectCubeFace = function(coords) {
+ var x = coords[0];
+ var y = coords[1];
+ var z = coords[2];
+ var ax = Math.abs(x);
+ var ay = Math.abs(y);
+ var az = Math.abs(z);
+
+ if (ay < ax && az < ax)
+ return x >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_X : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X;
+ else if (ax < ay && az < ay)
+ return y >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y;
+ else if (ax < az && ay < az)
+ return z >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z;
+ else {
+ // Some of the components are equal. Use tie-breaking rule.
+ if (ax == ay) {
+ if (ax < az)
+ return z >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z;
+ else
+ return x >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_X : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X;
+ } else if (ax == az) {
+ if (az < ay)
+ return y >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y;
+ else
+ return z >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z;
+ } else if (ay == az) {
+ if (ay < ax)
+ return x >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_X : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X;
+ else
+ return y >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y;
+ } else
+ return x >= 0 ? tcuTexture.CubeFace.CUBEFACE_POSITIVE_X : tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X;
+ }
+};
+
+/**
+ * @param {tcuTexture.CubeFace} face
+ * @param {Array<number>} coord Cube coordinates (Vec3)
+ * @return {Array<number>} face coordinates (Vec2)
+ */
+tcuTexture.projectToFace = function(face, coord) {
+ var rx = coord[0];
+ var ry = coord[1];
+ var rz = coord[2];
+ var sc = 0;
+ var tc = 0;
+ var ma = 0;
+
+ switch (face) {
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: sc = +rz; tc = -ry; ma = -rx; break;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: sc = -rz; tc = -ry; ma = +rx; break;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: sc = +rx; tc = -rz; ma = -ry; break;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: sc = +rx; tc = +rz; ma = +ry; break;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: sc = -rx; tc = -ry; ma = -rz; break;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: sc = +rx; tc = -ry; ma = +rz; break;
+ default:
+ throw new Error('Unrecognized face ' + face);
+ }
+
+ // Compute s, t
+ var s = ((sc / ma) + 1) / 2;
+ var t = ((tc / ma) + 1) / 2;
+
+ return [s, t];
+};
+
+/**
+ * @constructor
+ * @param {tcuTexture.TextureFormat} format
+ * @param {number=} width
+ * @param {number=} height
+ * @param {number=} depth
+ */
+tcuTexture.TextureLevel = function(format, width, height, depth) {
+ this.m_format = format;
+ this.m_width = width || 0;
+ this.m_height = height || 0;
+ this.m_depth = depth === undefined ? 1 : depth;
+ this.m_data = new tcuTexture.DeqpArrayBuffer();
+ this.setSize(this.m_width, this.m_height, this.m_depth);
+};
+
+tcuTexture.TextureLevel.prototype.constructor = tcuTexture.TextureLevel;
+
+/**
+ * @param {tcuTexture.TextureFormat} format
+ * @param {number=} width
+ * @param {number=} height
+ * @param {number=} depth
+ */
+tcuTexture.TextureLevel.prototype.setStorage = function(format, width, height, depth) {
+ this.m_format = format;
+ this.setSize(width, height, depth);
+};
+
+/**
+ * @param {number=} width
+ * @param {number=} height
+ * @param {number=} depth
+ */
+tcuTexture.TextureLevel.prototype.setSize = function(width, height, depth) {
+ var pixelSize = this.m_format.getPixelSize();
+
+ this.m_width = width || 0;
+ this.m_height = height || 0;
+ this.m_depth = depth === undefined ? 1 : depth;
+
+ this.m_data.setStorage(this.m_width * this.m_height * this.m_depth * pixelSize);
+};
+
+/**
+ * @return {tcuTexture.PixelBufferAccess}
+ */
+tcuTexture.TextureLevel.prototype.getAccess = function() {
+ return new tcuTexture.PixelBufferAccess({
+ format: this.m_format,
+ width: this.m_width,
+ height: this.m_height,
+ depth: this.m_depth,
+ data: this.m_data.m_ptr
+ });
+
+};
+
+/**
+ * @return {number}
+ */
+tcuTexture.TextureLevel.prototype.getWidth = function() {
+ return this.m_width;
+};
+
+/**
+ * @return {number}
+ */
+tcuTexture.TextureLevel.prototype.getHeight = function() {
+ return this.m_height;
+};
+
+/**
+ * @return {number}
+ */
+tcuTexture.TextureLevel.prototype.getDepth = function() {
+ return this.m_depth;
+};
+
+/**
+ * @return {?tcuTexture.TextureFormat}
+ */
+tcuTexture.TextureLevel.prototype.getFormat = function() {
+ return this.m_format;
+};
+
+/**
+ * Checks if origCoords.coords is in bounds defined by size; if not, return a CubeFaceCoords with face set to the appropriate neighboring face and coords transformed accordingly.
+ * \note If both x and y in origCoords.coords are out of bounds, this returns with face CUBEFACE_LAST, signifying that there is no unique neighboring face.
+ * @param {tcuTexture.CubeFaceCoords} origCoords
+ * @param {number} size
+ * @return {tcuTexture.CubeFaceCoords}
+ */
+tcuTexture.remapCubeEdgeCoords = function(origCoords, size) {
+ var uInBounds = deMath.deInBounds32(origCoords.s, 0, size);
+ var vInBounds = deMath.deInBounds32(origCoords.t, 0, size);
+
+ if (uInBounds && vInBounds)
+ return origCoords;
+
+ if (!uInBounds && !vInBounds)
+ return null;
+
+ var coords = [
+ tcuTexture.wrap(tcuTexture.WrapMode.CLAMP_TO_BORDER, origCoords.s, size),
+ tcuTexture.wrap(tcuTexture.WrapMode.CLAMP_TO_BORDER, origCoords.t, size)];
+ var canonizedCoords = [];
+
+ // Map the uv coordinates to canonized 3d coordinates.
+
+ switch (origCoords.face) {
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: canonizedCoords = [0, size - 1 - coords[1], coords[0]]; break;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: canonizedCoords = [size - 1, size - 1 - coords[1], size - 1 - coords[0]]; break;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: canonizedCoords = [coords[0], 0, size - 1 - coords[1]]; break;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: canonizedCoords = [coords[0], size - 1, coords[1]]; break;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: canonizedCoords = [size - 1 - coords[0], size - 1 - coords[1], 0]; break;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: canonizedCoords = [coords[0], size - 1 - coords[1], size - 1]; break;
+ default: throw new Error('Invalid cube face:' + origCoords.face);
+ }
+
+ // Find an appropriate face to re-map the coordinates to.
+
+ if (canonizedCoords[0] == -1)
+ return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X, [canonizedCoords[2], size - 1 - canonizedCoords[1]]);
+
+ if (canonizedCoords[0] == size)
+ return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_POSITIVE_X, [size - 1 - canonizedCoords[2], size - 1 - canonizedCoords[1]]);
+
+ if (canonizedCoords[1] == -1)
+ return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y, [canonizedCoords[0], size - 1 - canonizedCoords[2]]);
+
+ if (canonizedCoords[1] == size)
+ return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y, [canonizedCoords[0], canonizedCoords[2]]);
+
+ if (canonizedCoords[2] == -1)
+ return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z, [size - 1 - canonizedCoords[0], size - 1 - canonizedCoords[1]]);
+
+ if (canonizedCoords[2] == size)
+ return new tcuTexture.CubeFaceCoords(tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z, [canonizedCoords[0], size - 1 - canonizedCoords[1]]);
+
+ throw new Error('Cannot remap cube coordinates');
+};
+
+/**
+ * @constructor
+ * @param {tcuTexture.ConstPixelBufferAccess} src
+ */
+tcuTexture.RGBA8View = function(src) {
+ this.src = src;
+ this.data = new Uint8Array(src.getBuffer(), src.m_offset);
+ this.stride = src.getRowPitch();
+ this.width = src.getWidth();
+ this.height = src.getHeight();
+ this.pixelSize = src.getFormat().getPixelSize();
+};
+
+/**
+ * @return {tcuTexture.TextureFormat}
+ */
+tcuTexture.RGBA8View.prototype.getFormat = function() { return this.src.getFormat(); };
+
+/**
+ * Read a pixel
+ * @param {number} x
+ * @param {number} y
+ * @param {number=} numChannels
+ * @return {Array<number>}
+ */
+tcuTexture.RGBA8View.prototype.read = function(x, y, numChannels) {
+ numChannels = numChannels || 4;
+ var offset = y * this.stride + x * this.pixelSize;
+ /* Always return a vec4 */
+ var result = [0, 0, 0, 255];
+ for (var i = 0; i < numChannels; i++)
+ result[i] = this.data[offset + i];
+ return result;
+};
+
+/**
+ * Read a pixel into a Uint32
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+tcuTexture.RGBA8View.prototype.readUintRGBA8 = function(x, y) {
+ var offset = y * this.stride + x * this.pixelSize;
+ return ((this.data[offset] & 0xff) << 24) +
+ ((this.data[offset + 1] & 0xff) << 16) +
+ ((this.data[offset + 2] & 0xff) << 8) +
+ (this.data[offset + 3] & 0xff);
+};
+
+/**
+ * Write a pixel
+ * @param {number} x
+ * @param {number} y
+ * @param {Array<number>} value
+ * @param {number=} numChannels
+ */
+tcuTexture.RGBA8View.prototype.write = function(x, y, value, numChannels) {
+ numChannels = numChannels || 4;
+ var offset = y * this.stride + x * this.pixelSize;
+ for (var i = 0; i < numChannels; i++)
+ this.data[offset + i] = value[i];
+};
+
+tcuTexture.RGBA8View.prototype.getWidth = function() { return this.width; };
+
+tcuTexture.RGBA8View.prototype.getHeight = function() { return this.height; };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTextureUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTextureUtil.js
new file mode 100644
index 0000000000..40450ab380
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/common/tcuTextureUtil.js
@@ -0,0 +1,725 @@
+/*-------------------------------------------------------------------------
+ * 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 tcuTextureUtil.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.common.tcuTextureUtil');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.delibs.debase.deRandom');
+
+goog.scope(function() {
+
+var tcuTextureUtil = framework.common.tcuTextureUtil;
+var tcuTexture = framework.common.tcuTexture;
+var deMath = framework.delibs.debase.deMath;
+var deRandom = framework.delibs.debase.deRandom;
+
+var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+};
+
+/**
+ * @param {number} t
+ * @param {number} minVal
+ * @param {number} maxVal
+ * @return {number}
+ */
+tcuTextureUtil.linearInterpolate = function(t, minVal, maxVal) {
+ return minVal + (maxVal - minVal) * t;
+};
+
+/** tcuTextureUtil.linearChannelToSRGB
+ * @param {number} cl
+ * @return {number}
+ */
+tcuTextureUtil.linearChannelToSRGB = function(cl) {
+ if (cl <= 0.0)
+ return 0.0;
+ else if (cl < 0.0031308)
+ return 12.92 * cl;
+ else if (cl < 1.0)
+ return 1.055 * Math.pow(cl, 0.41666) - 0.055;
+ else
+ return 1.0;
+};
+
+/**
+ * Convert sRGB to linear colorspace
+ * @param {Array<number>} cs
+ * @return {Array<number>}
+ */
+tcuTextureUtil.sRGBToLinear = function(cs) {
+ return [tcuTextureUtil.sRGBChannelToLinear(cs[0]),
+ tcuTextureUtil.sRGBChannelToLinear(cs[1]),
+ tcuTextureUtil.sRGBChannelToLinear(cs[2]),
+ cs[3]];
+};
+
+/**
+ * @param {number} cs
+ * @return {number}
+ */
+ tcuTextureUtil.sRGBChannelToLinear = function(cs) {
+ if (cs <= 0.04045)
+ return cs / 12.92;
+ else
+ return Math.pow((cs + 0.055) / 1.055, 2.4);
+};
+
+/** tcuTextureUtil.linearToSRGB
+ * @param {Array<number>} cl
+ * @return {Array<number>}
+ */
+tcuTextureUtil.linearToSRGB = function(cl) {
+ return [tcuTextureUtil.linearChannelToSRGB(cl[0]),
+ tcuTextureUtil.linearChannelToSRGB(cl[1]),
+ tcuTextureUtil.linearChannelToSRGB(cl[2]),
+ cl[3]
+ ];
+};
+
+/**
+ * tcuTextureUtil.getSubregion
+ * @param {tcuTexture.PixelBufferAccess} access
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @param {number} width
+ * @param {number} height
+ * @param {number} depth
+ * @return {tcuTexture.PixelBufferAccess}
+ */
+tcuTextureUtil.getSubregion = function(access, x, y, z, width, height, depth) {
+
+ DE_ASSERT(deMath.deInBounds32(x, 0, access.getWidth()) && deMath.deInRange32(x + width, x, access.getWidth()));
+ DE_ASSERT(deMath.deInBounds32(y, 0, access.getHeight()) && deMath.deInRange32(y + height, y, access.getHeight()));
+ DE_ASSERT(deMath.deInBounds32(z, 0, access.getDepth()) && deMath.deInRange32(z + depth, z, access.getDepth()));
+
+ return new tcuTexture.PixelBufferAccess({
+ format: access.getFormat(),
+ width: width,
+ height: height,
+ depth: depth,
+ rowPitch: access.getRowPitch(),
+ slicePitch: access.getSlicePitch(),
+ offset: access.m_offset + access.getFormat().getPixelSize() * x + access.getRowPitch() * y + access.getSlicePitch() * z,
+ data: access.getBuffer()
+ });
+};
+
+/**
+ * @param {tcuTexture.PixelBufferAccess} access
+ * @param {Array<number>} minVal
+ * @param {Array<number>} maxVal
+ */
+tcuTextureUtil.fillWithComponentGradients1D = function(access, minVal, maxVal) {
+ DE_ASSERT(access.getHeight() == 1);
+ for (var x = 0; x < access.getWidth(); x++) {
+ var s = (x + 0.5) / access.getWidth();
+
+ var r = tcuTextureUtil.linearInterpolate(s, minVal[0], maxVal[0]);
+ var g = tcuTextureUtil.linearInterpolate(s, minVal[1], maxVal[1]);
+ var b = tcuTextureUtil.linearInterpolate(s, minVal[2], maxVal[2]);
+ var a = tcuTextureUtil.linearInterpolate(s, minVal[3], maxVal[3]);
+
+ access.setPixel([r, g, b, a], x, 0);
+ }
+};
+
+/**
+ * @param {tcuTexture.PixelBufferAccess} access
+ * @param {Array<number>} minVal
+ * @param {Array<number>} maxVal
+ */
+tcuTextureUtil.fillWithComponentGradients2D = function(access, minVal, maxVal) {
+ for (var y = 0; y < access.getHeight(); y++) {
+ var t = (y + 0.5) / access.getHeight();
+ for (var x = 0; x < access.getWidth(); x++) {
+ var s = (x + 0.5) / access.getWidth();
+
+ var r = tcuTextureUtil.linearInterpolate((s + t) * 0.5, minVal[0], maxVal[0]);
+ var g = tcuTextureUtil.linearInterpolate((s + (1 - t)) * 0.5, minVal[1], maxVal[1]);
+ var b = tcuTextureUtil.linearInterpolate(((1 - s) + t) * 0.5, minVal[2], maxVal[2]);
+ var a = tcuTextureUtil.linearInterpolate(((1 - s) + (1 - t)) * 0.5, minVal[3], maxVal[3]);
+
+ access.setPixel([r, g, b, a], x, y);
+ }
+ }
+};
+
+/**
+ * @param {tcuTexture.PixelBufferAccess} dst
+ * @param {Array<number>} minVal
+ * @param {Array<number>} maxVal
+ */
+tcuTextureUtil.fillWithComponentGradients3D = function(dst, minVal, maxVal) {
+ for (var z = 0; z < dst.getDepth(); z++) {
+ var p = (z + 0.5) / dst.getDepth();
+ var b = tcuTextureUtil.linearInterpolate(p, minVal[2], maxVal[2]);
+ for (var y = 0; y < dst.getHeight(); y++) {
+ var t = (y + 0.5) / dst.getHeight();
+ var g = tcuTextureUtil.linearInterpolate(t, minVal[1], maxVal[1]);
+ for (var x = 0; x < dst.getWidth(); x++) {
+ var s = (x + 0.5) / dst.getWidth();
+ var r = tcuTextureUtil.linearInterpolate(s, minVal[0], maxVal[0]);
+ var a = tcuTextureUtil.linearInterpolate(1 - (s + t + p) / 3, minVal[3], maxVal[3]);
+ dst.setPixel([r, g, b, a], x, y, z);
+ }
+ }
+ }
+};
+
+/**
+ * @param {tcuTexture.PixelBufferAccess} access
+ * @param {Array<number>} minVal
+ * @param {Array<number>} maxVal
+ */
+tcuTextureUtil.fillWithComponentGradients = function(access, minVal, maxVal) {
+ if (access.getHeight() == 1 && access.getDepth() == 1)
+ tcuTextureUtil.fillWithComponentGradients1D(access, minVal, maxVal);
+ else if (access.getDepth() == 1)
+ tcuTextureUtil.fillWithComponentGradients2D(access, minVal, maxVal);
+ else
+ tcuTextureUtil.fillWithComponentGradients3D(access, minVal, maxVal);
+};
+
+/**
+ * @param {tcuTexture.PixelBufferAccess} dst
+ */
+tcuTextureUtil.fillWithRGBAQuads = function(dst) {
+ checkMessage(dst.getDepth() == 1, 'Depth must be 1');
+ var width = dst.getWidth();
+ var height = dst.getHeight();
+ var left = width / 2;
+ var top = height / 2;
+
+ tcuTextureUtil.getSubregion(dst, 0, 0, 0, left, top, 1).clear([1.0, 0.0, 0.0, 1.0]);
+ tcuTextureUtil.getSubregion(dst, left, 0, 0, width - left, top, 1).clear([0.0, 1.0, 0.0, 1.0]);
+ tcuTextureUtil.getSubregion(dst, 0, top, 0, left, height - top, 1).clear([0.0, 0.0, 1.0, 0.0]);
+ tcuTextureUtil.getSubregion(dst, left, top, 0, width - left, height - top, 1).clear([0.5, 0.5, 0.5, 1.0]);
+};
+
+// \todo [2012-11-13 pyry] There is much better metaballs code in CL SIR value generators.
+/**
+ * @param {tcuTexture.PixelBufferAccess} dst
+ * @param {number} numBalls
+ * @param {number} seed
+ */
+tcuTextureUtil.fillWithMetaballs = function(dst, numBalls, seed) {
+ checkMessage(dst.getDepth() == 1, 'Depth must be 1');
+ var points = [];
+ var rnd = new deRandom.Random(seed);
+
+ for (var i = 0; i < numBalls; i++) {
+ var x = rnd.getFloat();
+ var y = rnd.getFloat();
+ points[i] = [x, y];
+ }
+
+ for (var y = 0; y < dst.getHeight(); y++)
+ for (var x = 0; x < dst.getWidth(); x++) {
+ var p = [x / dst.getWidth(), y / dst.getHeight()];
+
+ var sum = 0.0;
+ for (var pointNdx = 0; pointNdx < points.length; pointNdx++) {
+ var d = deMath.subtract(p, points[pointNdx]);
+ var f = 0.01 / (d[0] * d[0] + d[1] * d[1]);
+
+ sum += f;
+ }
+
+ dst.setPixel([sum, sum, sum, sum], x, y);
+ }
+};
+
+/**
+ * Create tcuTextureUtil.TextureFormatInfo.
+ * @constructor
+ * @param {Array<number>} valueMin
+ * @param {Array<number>} valueMax
+ * @param {Array<number>} lookupScale
+ * @param {Array<number>} lookupBias
+ */
+tcuTextureUtil.TextureFormatInfo = function(valueMin, valueMax, lookupScale, lookupBias) {
+ /** @type {Array<number>} */ this.valueMin = valueMin;
+ /** @type {Array<number>} */ this.valueMax = valueMax;
+ /** @type {Array<number>} */ this.lookupScale = lookupScale;
+ /** @type {Array<number>} */ this.lookupBias = lookupBias;
+};
+
+/**
+ * @param {?tcuTexture.ChannelType} channelType
+ * @return {Array<number>}
+ */
+tcuTextureUtil.getChannelValueRange = function(channelType) {
+ var cMin = 0;
+ var cMax = 0;
+
+ switch (channelType) {
+ // Signed normalized formats.
+ case tcuTexture.ChannelType.SNORM_INT8:
+ case tcuTexture.ChannelType.SNORM_INT16: cMin = -1; cMax = 1; break;
+
+ // Unsigned normalized formats.
+ case tcuTexture.ChannelType.UNORM_INT8:
+ case tcuTexture.ChannelType.UNORM_INT16:
+ case tcuTexture.ChannelType.UNORM_SHORT_565:
+ case tcuTexture.ChannelType.UNORM_SHORT_4444:
+ case tcuTexture.ChannelType.UNORM_INT_101010:
+ case tcuTexture.ChannelType.UNORM_INT_1010102_REV: cMin = 0; cMax = 1; break;
+
+ // Misc formats.
+ case tcuTexture.ChannelType.SIGNED_INT8: cMin = -128; cMax = 127; break;
+ case tcuTexture.ChannelType.SIGNED_INT16: cMin = -32768; cMax = 32767; break;
+ case tcuTexture.ChannelType.SIGNED_INT32: cMin = -2147483648; cMax = 2147483647; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT8: cMin = 0; cMax = 255; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT16: cMin = 0; cMax = 65535; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT32: cMin = 0; cMax = 4294967295; break;
+ case tcuTexture.ChannelType.HALF_FLOAT: cMin = -1e3; cMax = 1e3; break;
+ case tcuTexture.ChannelType.FLOAT: cMin = -1e5; cMax = 1e5; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: cMin = 0; cMax = 1e4; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: cMin = 0; cMax = 1e5; break;
+
+ default:
+ DE_ASSERT(false);
+ }
+
+ return [cMin, cMax];
+};
+
+/**
+ * Creates an array by choosing between 'a' and 'b' based on 'cond' array.
+ * @param {Array | number} a
+ * @param {Array | number} b
+ * @param {Array<boolean>} cond Condtions
+ * @return {Array}
+ */
+tcuTextureUtil.select = function(a, b, cond) {
+
+ /*DE_ASSERT(!(a.length && !b.length)
+ || !(!a.length && b.length)
+ || !((a.length && b.length) && ((a.length != b.length) || (b.length != cond.length) || (a.length != cond.length))));*/
+
+ if (a.length && !b.length) throw new Error('second input parameter is not a vector');
+ if (!a.length && b.length) throw new Error('first input parameter is not a vector');
+ if ((a.length && b.length) && ((a.length != b.length) || (b.length != cond.length) || (a.length != cond.length))) throw new Error('different size vectors');
+
+ var dst = [];
+ for (var i = 0; i < cond.length; i++)
+ if (cond[i]) {
+ if (a.length) dst.push(a[i]);
+ else dst.push(a);
+ } else {
+ if (b.length) dst.push(b[i]);
+ else dst.push(b);
+ }
+ return dst;
+};
+
+/**
+ * Get standard parameters for testing texture format
+ *
+ * Returns tcuTextureUtil.TextureFormatInfo that describes good parameters for exercising
+ * given TextureFormat. Parameters include value ranges per channel and
+ * suitable lookup scaling and bias in order to reduce result back to
+ * 0..1 range.
+ *
+ * @param {tcuTexture.TextureFormat} format
+ * @return {tcuTextureUtil.TextureFormatInfo}
+ */
+tcuTextureUtil.getTextureFormatInfo = function(format) {
+ // Special cases.
+ if (format.isEqual(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV)))
+ return new tcuTextureUtil.TextureFormatInfo([0, 0, 0, 0],
+ [1023, 1023, 1023, 3],
+ [1 / 1023, 1 / 1023, 1 / 1023, 1 / 3],
+ [0, 0, 0, 0]);
+ else if (format.order == tcuTexture.ChannelOrder.D || format.order == tcuTexture.ChannelOrder.DS)
+ return new tcuTextureUtil.TextureFormatInfo([0, 0, 0, 0],
+ [1, 1, 1, 0],
+ [1, 1, 1, 1],
+ [0, 0, 0, 0]); // Depth / stencil formats.
+ else if (format.isEqual(new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_5551)))
+ return new tcuTextureUtil.TextureFormatInfo([0, 0, 0, 0.5],
+ [1, 1, 1, 1.5],
+ [1, 1, 1, 1],
+ [0, 0, 0, 0]);
+
+ var cRange = tcuTextureUtil.getChannelValueRange(format.type);
+ var chnMask = null;
+
+ switch (format.order) {
+ case tcuTexture.ChannelOrder.R: chnMask = [true, false, false, false]; break;
+ case tcuTexture.ChannelOrder.A: chnMask = [false, false, false, true]; break;
+ case tcuTexture.ChannelOrder.L: chnMask = [true, true, true, false]; break;
+ case tcuTexture.ChannelOrder.LA: chnMask = [true, true, true, true]; break;
+ case tcuTexture.ChannelOrder.RG: chnMask = [true, true, false, false]; break;
+ case tcuTexture.ChannelOrder.RGB: chnMask = [true, true, true, false]; break;
+ case tcuTexture.ChannelOrder.RGBA: chnMask = [true, true, true, true]; break;
+ case tcuTexture.ChannelOrder.sRGB: chnMask = [true, true, true, false]; break;
+ case tcuTexture.ChannelOrder.sRGBA: chnMask = [true, true, true, true]; break;
+ case tcuTexture.ChannelOrder.D: chnMask = [true, true, true, false]; break;
+ case tcuTexture.ChannelOrder.DS: chnMask = [true, true, true, true]; break;
+ default:
+ DE_ASSERT(false);
+ }
+
+ var scale = 1 / (cRange[1] - cRange[0]);
+ var bias = -cRange[0] * scale;
+
+ return new tcuTextureUtil.TextureFormatInfo(tcuTextureUtil.select(cRange[0], 0, chnMask),
+ tcuTextureUtil.select(cRange[1], 0, chnMask),
+ tcuTextureUtil.select(scale, 1, chnMask),
+ tcuTextureUtil.select(bias, 0, chnMask));
+};
+
+/** tcuTextureUtil.getChannelBitDepth
+ * @param {?tcuTexture.ChannelType} channelType
+ * @return {Array<number>}
+ */
+tcuTextureUtil.getChannelBitDepth = function(channelType) {
+
+ switch (channelType) {
+ case tcuTexture.ChannelType.SNORM_INT8: return [8, 8, 8, 8];
+ case tcuTexture.ChannelType.SNORM_INT16: return [16, 16, 16, 16];
+ case tcuTexture.ChannelType.SNORM_INT32: return [32, 32, 32, 32];
+ case tcuTexture.ChannelType.UNORM_INT8: return [8, 8, 8, 8];
+ case tcuTexture.ChannelType.UNORM_INT16: return [16, 16, 16, 16];
+ case tcuTexture.ChannelType.UNORM_INT32: return [32, 32, 32, 32];
+ case tcuTexture.ChannelType.UNORM_SHORT_565: return [5, 6, 5, 0];
+ case tcuTexture.ChannelType.UNORM_SHORT_4444: return [4, 4, 4, 4];
+ case tcuTexture.ChannelType.UNORM_SHORT_555: return [5, 5, 5, 0];
+ case tcuTexture.ChannelType.UNORM_SHORT_5551: return [5, 5, 5, 1];
+ case tcuTexture.ChannelType.UNORM_INT_101010: return [10, 10, 10, 0];
+ case tcuTexture.ChannelType.UNORM_INT_1010102_REV: return [10, 10, 10, 2];
+ case tcuTexture.ChannelType.SIGNED_INT8: return [8, 8, 8, 8];
+ case tcuTexture.ChannelType.SIGNED_INT16: return [16, 16, 16, 16];
+ case tcuTexture.ChannelType.SIGNED_INT32: return [32, 32, 32, 32];
+ case tcuTexture.ChannelType.UNSIGNED_INT8: return [8, 8, 8, 8];
+ case tcuTexture.ChannelType.UNSIGNED_INT16: return [16, 16, 16, 16];
+ case tcuTexture.ChannelType.UNSIGNED_INT32: return [32, 32, 32, 32];
+ case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: return [10, 10, 10, 2];
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8: return [24, 0, 0, 8];
+ case tcuTexture.ChannelType.HALF_FLOAT: return [16, 16, 16, 16];
+ case tcuTexture.ChannelType.FLOAT: return [32, 32, 32, 32];
+ case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: return [11, 11, 10, 0];
+ case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: return [9, 9, 9, 0];
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: return [32, 0, 0, 8];
+ default:
+ DE_ASSERT(false);
+ return [0, 0, 0, 0];
+ }
+};
+
+/** tcuTextureUtil.getTextureFormatBitDepth
+ * @param {tcuTexture.TextureFormat} format
+ * @return {Array<number>}
+ */
+tcuTextureUtil.getTextureFormatBitDepth = function(format) {
+
+ /** @type {Array<number>} */ var chnBits = tcuTextureUtil.getChannelBitDepth(format.type); // IVec4
+ /** @type {Array<boolean>} */ var chnMask = [false, false, false, false]; // BVec4
+ /** @type {Array<number>} */ var chnSwz = [0, 1, 2, 3]; // IVec4
+
+ switch (format.order) {
+ case tcuTexture.ChannelOrder.R: chnMask = [true, false, false, false]; break;
+ case tcuTexture.ChannelOrder.A: chnMask = [false, false, false, true]; break;
+ case tcuTexture.ChannelOrder.RA: chnMask = [true, false, false, true]; break;
+ case tcuTexture.ChannelOrder.L: chnMask = [true, true, true, false]; break;
+ case tcuTexture.ChannelOrder.I: chnMask = [true, true, true, true]; break;
+ case tcuTexture.ChannelOrder.LA: chnMask = [true, true, true, true]; break;
+ case tcuTexture.ChannelOrder.RG: chnMask = [true, true, false, false]; break;
+ case tcuTexture.ChannelOrder.RGB: chnMask = [true, true, true, false]; break;
+ case tcuTexture.ChannelOrder.RGBA: chnMask = [true, true, true, true]; break;
+ case tcuTexture.ChannelOrder.BGRA: chnMask = [true, true, true, true]; chnSwz = [2, 1, 0, 3]; break;
+ case tcuTexture.ChannelOrder.ARGB: chnMask = [true, true, true, true]; chnSwz = [1, 2, 3, 0]; break;
+ case tcuTexture.ChannelOrder.sRGB: chnMask = [true, true, true, false]; break;
+ case tcuTexture.ChannelOrder.sRGBA: chnMask = [true, true, true, true]; break;
+ case tcuTexture.ChannelOrder.D: chnMask = [true, false, false, false]; break;
+ case tcuTexture.ChannelOrder.DS: chnMask = [true, false, false, true]; break;
+ case tcuTexture.ChannelOrder.S: chnMask = [false, false, false, true]; break;
+ default:
+ DE_ASSERT(false);
+ }
+
+ return tcuTextureUtil.select(deMath.swizzle(chnBits, [chnSwz[0], chnSwz[1], chnSwz[2], chnSwz[3]]), [0, 0, 0, 0], chnMask);
+
+};
+
+/** tcuTextureUtil.fillWithGrid
+ * @const @param {tcuTexture.PixelBufferAccess} access
+ * @param {number} cellSize
+ * @param {Array<number>} colorA
+ * @param {Array<number>} colorB
+ */
+tcuTextureUtil.fillWithGrid = function(access, cellSize, colorA, colorB) {
+ if (access.getHeight() == 1 && access.getDepth() == 1)
+ tcuTextureUtil.fillWithGrid1D(access, cellSize, colorA, colorB);
+ else if (access.getDepth() == 1)
+ tcuTextureUtil.fillWithGrid2D(access, cellSize, colorA, colorB);
+ else
+ tcuTextureUtil.fillWithGrid3D(access, cellSize, colorA, colorB);
+};
+
+/** tcuTextureUtil.fillWithGrid1D
+ * @const @param {tcuTexture.PixelBufferAccess} access
+ * @param {number} cellSize
+ * @param {Array<number>} colorA
+ * @param {Array<number>} colorB
+ */
+tcuTextureUtil.fillWithGrid1D = function(access, cellSize, colorA, colorB) {
+ for (var x = 0; x < access.getWidth(); x++) {
+ var mx = Math.floor(x / cellSize) % 2;
+
+ if (mx)
+ access.setPixel(colorB, x, 0);
+ else
+ access.setPixel(colorA, x, 0);
+ }
+};
+
+/** tcuTextureUtil.fillWithGrid2D
+ * @const @param {tcuTexture.PixelBufferAccess} access
+ * @param {number} cellSize
+ * @param {Array<number>} colorA
+ * @param {Array<number>} colorB
+ */
+tcuTextureUtil.fillWithGrid2D = function(access, cellSize, colorA, colorB) {
+ for (var y = 0; y < access.getHeight(); y++)
+ for (var x = 0; x < access.getWidth(); x++) {
+ var mx = Math.floor(x / cellSize) % 2;
+ var my = Math.floor(y / cellSize) % 2;
+
+ if (mx ^ my)
+ access.setPixel(colorB, x, y);
+ else
+ access.setPixel(colorA, x, y);
+ }
+};
+
+/** tcuTextureUtil.fillWithGrid3D
+ * @const @param {tcuTexture.PixelBufferAccess} access
+ * @param {number} cellSize
+ * @param {Array<number>} colorA
+ * @param {Array<number>} colorB
+ */
+tcuTextureUtil.fillWithGrid3D = function(access, cellSize, colorA, colorB) {
+ for (var z = 0; z < access.getDepth(); z++)
+ for (var y = 0; y < access.getHeight(); y++)
+ for (var x = 0; x < access.getWidth(); x++) {
+ var mx = Math.floor(x / cellSize) % 2;
+ var my = Math.floor(y / cellSize) % 2;
+ var mz = Math.floor(z / cellSize) % 2;
+
+ if (mx ^ my ^ mz)
+ access.setPixel(colorB, x, y, z);
+ else
+ access.setPixel(colorA, x, y, z);
+ }
+};
+
+/**
+ * @const @param {tcuTexture.TextureFormat} format
+ * @return {Array<number>}
+ */
+tcuTextureUtil.getTextureFormatMantissaBitDepth = function(format) {
+ /** @type {Array<number>} */ var chnBits = tcuTextureUtil.getChannelMantissaBitDepth(format.type);
+ /** @type {Array<boolean>} */ var chnMask = [false, false, false, false];
+ /** @type {Array<number>} */ var chnSwz = [0, 1, 2, 3];
+
+ switch (format.order) {
+ case tcuTexture.ChannelOrder.R: chnMask = [true, false, false, false]; break;
+ case tcuTexture.ChannelOrder.A: chnMask = [false, false, false, true]; break;
+ case tcuTexture.ChannelOrder.RA: chnMask = [true, false, false, true]; break;
+ case tcuTexture.ChannelOrder.L: chnMask = [true, true, true, false]; break;
+ case tcuTexture.ChannelOrder.I: chnMask = [true, true, true, true]; break;
+ case tcuTexture.ChannelOrder.LA: chnMask = [true, true, true, true]; break;
+ case tcuTexture.ChannelOrder.RG: chnMask = [true, true, false, false]; break;
+ case tcuTexture.ChannelOrder.RGB: chnMask = [true, true, true, false]; break;
+ case tcuTexture.ChannelOrder.RGBA: chnMask = [true, true, true, true]; break;
+ case tcuTexture.ChannelOrder.BGRA: chnMask = [true, true, true, true]; chnSwz = [2, 1, 0, 3]; break;
+ case tcuTexture.ChannelOrder.ARGB: chnMask = [true, true, true, true]; chnSwz = [1, 2, 3, 0]; break;
+ case tcuTexture.ChannelOrder.sRGB: chnMask = [true, true, true, false]; break;
+ case tcuTexture.ChannelOrder.sRGBA: chnMask = [true, true, true, true]; break;
+ case tcuTexture.ChannelOrder.D: chnMask = [true, false, false, false]; break;
+ case tcuTexture.ChannelOrder.DS: chnMask = [true, false, false, true]; break;
+ case tcuTexture.ChannelOrder.S: chnMask = [false, false, false, true]; break;
+ default:
+ DE_ASSERT(false);
+ }
+ return tcuTextureUtil.select(deMath.swizzle(chnBits, [chnSwz[0], chnSwz[1], chnSwz[2], chnSwz[3]]), [0, 0, 0, 0], chnMask);
+};
+
+/**
+ * @param {?tcuTexture.ChannelType} channelType
+ * @return {Array<number>}
+ */
+tcuTextureUtil.getChannelMantissaBitDepth = function(channelType) {
+ switch (channelType) {
+ case tcuTexture.ChannelType.SNORM_INT8:
+ case tcuTexture.ChannelType.SNORM_INT16:
+ case tcuTexture.ChannelType.SNORM_INT32:
+ case tcuTexture.ChannelType.UNORM_INT8:
+ case tcuTexture.ChannelType.UNORM_INT16:
+ case tcuTexture.ChannelType.UNORM_INT32:
+ case tcuTexture.ChannelType.UNORM_SHORT_565:
+ case tcuTexture.ChannelType.UNORM_SHORT_4444:
+ case tcuTexture.ChannelType.UNORM_SHORT_555:
+ case tcuTexture.ChannelType.UNORM_SHORT_5551:
+ case tcuTexture.ChannelType.UNORM_INT_101010:
+ case tcuTexture.ChannelType.UNORM_INT_1010102_REV:
+ case tcuTexture.ChannelType.SIGNED_INT8:
+ case tcuTexture.ChannelType.SIGNED_INT16:
+ case tcuTexture.ChannelType.SIGNED_INT32:
+ case tcuTexture.ChannelType.UNSIGNED_INT8:
+ case tcuTexture.ChannelType.UNSIGNED_INT16:
+ case tcuTexture.ChannelType.UNSIGNED_INT32:
+ case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV:
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8:
+ case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV:
+ return tcuTextureUtil.getChannelBitDepth(channelType);
+ case tcuTexture.ChannelType.HALF_FLOAT: return [10, 10, 10, 10];
+ case tcuTexture.ChannelType.FLOAT: return [23, 23, 23, 23];
+ case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: return [6, 6, 5, 0];
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: return [23, 0, 0, 8];
+ default:
+ throw new Error('Invalid channelType: ' + channelType);
+ }
+};
+
+/**
+ * @param {tcuTexture.PixelBufferAccess} dst
+ * @param {tcuTexture.ConstPixelBufferAccess} src
+ */
+tcuTextureUtil.copy = function(dst, src) {
+ var width = dst.getWidth();
+ var height = dst.getHeight();
+ var depth = dst.getDepth();
+
+ DE_ASSERT(src.getWidth() == width && src.getHeight() == height && src.getDepth() == depth);
+
+ if (src.getFormat().isEqual(dst.getFormat())) {
+ var srcData = src.getDataPtr();
+ var dstData = dst.getDataPtr();
+
+ if (srcData.length == dstData.length) {
+ dstData.set(srcData);
+ return;
+ }
+ }
+ var srcClass = tcuTexture.getTextureChannelClass(src.getFormat().type);
+ var dstClass = tcuTexture.getTextureChannelClass(dst.getFormat().type);
+ var srcIsInt = srcClass == tcuTexture.TextureChannelClass.SIGNED_INTEGER || srcClass == tcuTexture.TextureChannelClass.UNSIGNED_INTEGER;
+ var dstIsInt = dstClass == tcuTexture.TextureChannelClass.SIGNED_INTEGER || dstClass == tcuTexture.TextureChannelClass.UNSIGNED_INTEGER;
+
+ if (srcIsInt && dstIsInt) {
+ for (var z = 0; z < depth; z++)
+ for (var y = 0; y < height; y++)
+ for (var x = 0; x < width; x++)
+ dst.setPixelInt(src.getPixelInt(x, y, z), x, y, z);
+ } else {
+ for (var z = 0; z < depth; z++)
+ for (var y = 0; y < height; y++)
+ for (var x = 0; x < width; x++)
+ dst.setPixel(src.getPixel(x, y, z), x, y, z);
+ }
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ */
+tcuTextureUtil.estimatePixelValueRange = function(access) {
+ var format = access.getFormat();
+
+ switch (format.type) {
+ case tcuTexture.ChannelType.UNORM_INT8:
+ case tcuTexture.ChannelType.UNORM_INT16:
+ // Normalized unsigned formats.
+ return [
+ [0, 0, 0, 0],
+ [1, 1, 1, 1]
+ ];
+
+ case tcuTexture.ChannelType.SNORM_INT8:
+ case tcuTexture.ChannelType.SNORM_INT16:
+ // Normalized signed formats.
+ return [
+ [-1, -1, -1, -1],
+ [1, 1, 1, 1]
+ ];
+
+ default:
+ // \note Samples every 4/8th pixel.
+ var minVal = [Infinity, Infinity, Infinity, Infinity];
+ var maxVal = [-Infinity, -Infinity, -Infinity, -Infinity];
+
+ for (var z = 0; z < access.getDepth(); z += 2) {
+ for (var y = 0; y < access.getHeight(); y += 2) {
+ for (var x = 0; x < access.getWidth(); x += 2) {
+ var p = access.getPixel(x, y, z);
+
+ minVal[0] = Math.min(minVal[0], p[0]);
+ minVal[1] = Math.min(minVal[1], p[1]);
+ minVal[2] = Math.min(minVal[2], p[2]);
+ minVal[3] = Math.min(minVal[3], p[3]);
+
+ maxVal[0] = Math.max(maxVal[0], p[0]);
+ maxVal[1] = Math.max(maxVal[1], p[1]);
+ maxVal[2] = Math.max(maxVal[2], p[2]);
+ maxVal[3] = Math.max(maxVal[3], p[3]);
+ }
+ }
+ }
+ return [minVal, maxVal];
+ }
+};
+
+/**
+ * @param {tcuTexture.ConstPixelBufferAccess} access
+ * @return {{scale: Array<number>, bias: Array<number>}}
+ */
+tcuTextureUtil.computePixelScaleBias = function(access) {
+ var limits = tcuTextureUtil.estimatePixelValueRange(access);
+ var minVal = limits[0];
+ var maxVal = limits[1];
+
+ var scale = [1, 1, 1, 1];
+ var bias = [0, 0, 0, 0];
+
+ var eps = 0.0001;
+
+ for (var c = 0; c < 4; c++) {
+ if (maxVal[c] - minVal[c] < eps) {
+ scale[c] = (maxVal[c] < eps) ? 1 : (1 / maxVal[c]);
+ bias[c] = (c == 3) ? (1 - maxVal[c] * scale[c]) : (0 - minVal[c] * scale[c]);
+ } else {
+ scale[c] = 1 / (maxVal[c] - minVal[c]);
+ bias[c] = 0 - minVal[c] * scale[c];
+ }
+ }
+
+ return {
+ scale: scale,
+ bias: bias
+ };
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deMath.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deMath.js
new file mode 100644
index 0000000000..fbb2a61fd7
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deMath.js
@@ -0,0 +1,1143 @@
+/*-------------------------------------------------------------------------
+ * 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.delibs.debase.deMath');
+
+/** @typedef { (Int8Array|Uint8Array|Uint8ClampedArray|Int16Array|Uint16Array|Int32Array|Uint32Array|Float32Array|Float64Array) } */
+goog.TypedArray;
+
+/** @typedef { (Array<number>|Array<boolean>|goog.TypedArray) } */
+goog.NumberArray;
+
+goog.scope(function() {
+
+var deMath = framework.delibs.debase.deMath;
+
+var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+};
+
+/** @const */ deMath.INT32_SIZE = 4;
+
+deMath.deInRange32 = function(a, mn, mx) {
+ return (a >= mn) && (a <= mx);
+};
+
+deMath.deInBounds32 = function(a, mn, mx) {
+ return (a >= mn) && (a < mx);
+};
+
+/**
+ * @param {number} a
+ * @return {number}
+ */
+deMath.deFloatFrac = function(a) { return a - Math.floor(a); };
+
+/**
+ * Transform a 64-bit float number into a 32-bit float number.
+ * Native dEQP uses 32-bit numbers, so sometimes 64-bit floating numbers in JS should be transformed into 32-bit ones to ensure the correctness of the result.
+ * @param {number} a
+ * @return {number}
+ */
+deMath.toFloat32 = (function() {
+ var FLOAT32ARRAY1 = new Float32Array(1);
+ return function(a) {
+ FLOAT32ARRAY1[0] = a;
+ return FLOAT32ARRAY1[0];
+ };
+})();
+
+/** @const */ deMath.INV_LOG_2_FLOAT32 = deMath.toFloat32(1.44269504089); /** 1.0 / log_e(2.0) */
+
+/**
+ * Check if a value is a power-of-two.
+ * @param {number} a Input value.
+ * @return {boolean} return True if input is a power-of-two value, false otherwise.
+ * (Also returns true for zero).
+ */
+deMath.deIsPowerOfTwo32 = function(a) {
+ return ((a & (a - 1)) == 0);
+};
+
+/**
+ * Align an integer to given power-of-two size.
+ * @param {number} val The number to align.
+ * @param {number} align The size to align to.
+ * @return {number} The aligned value
+ */
+deMath.deAlign32 = function(val, align) {
+ if (!deMath.deIsPowerOfTwo32(align))
+ throw new Error('Not a power of 2: ' + align);
+ return ((val + align - 1) & ~(align - 1)) & 0xFFFFFFFF; //0xFFFFFFFF make sure it returns a 32 bit calculation in 64 bit browsers.
+};
+
+/**
+ * Compute the bit population count of an integer.
+ * @param {number} a
+ * @return {number} The number of one bits in
+ */
+deMath.dePop32 = function(a) {
+ /** @type {number} */ var mask0 = 0x55555555; /* 1-bit values. */
+ /** @type {number} */ var mask1 = 0x33333333; /* 2-bit values. */
+ /** @type {number} */ var mask2 = 0x0f0f0f0f; /* 4-bit values. */
+ /** @type {number} */ var mask3 = 0x00ff00ff; /* 8-bit values. */
+ /** @type {number} */ var mask4 = 0x0000ffff; /* 16-bit values. */
+ /** @type {number} */ var t = a & 0xFFFFFFFF; /* Crop to 32-bit value */
+ t = (t & mask0) + ((t >> 1) & mask0);
+ t = (t & mask1) + ((t >> 2) & mask1);
+ t = (t & mask2) + ((t >> 4) & mask2);
+ t = (t & mask3) + ((t >> 8) & mask3);
+ t = (t & mask4) + (t >> 16);
+ return t;
+};
+
+deMath.clamp = function(val, minParm, maxParm) {
+ return Math.min(Math.max(val, minParm), maxParm);
+};
+
+/**
+ * @param {Array<number>} values
+ * @param {number} minParm
+ * @param {number} maxParm
+ * @return {Array<number>}
+ */
+deMath.clampVector = function(values, minParm, maxParm) {
+ var result = [];
+ for (var i = 0; i < values.length; i++)
+ result.push(deMath.clamp(values[i], minParm, maxParm));
+ return result;
+};
+
+deMath.imod = function(a, b) {
+ var m = a % b;
+ return m < 0 ? m + b : m;
+};
+
+deMath.mirror = function(a) {
+ return a >= 0 ? a : -(1 + a);
+};
+
+/**
+ * @param {goog.NumberArray} a Source array
+ * @param {goog.NumberArray} indices
+ * @return {Array<number>} Swizzled array
+ */
+deMath.swizzle = function(a, indices) {
+ if (!indices.length)
+ throw new Error('Argument must be an array');
+ var dst = [];
+ for (var i = 0; i < indices.length; i++)
+ dst.push(a[indices[i]]);
+ return dst;
+};
+
+/**
+ * Shift left elements of array a by elements of array b
+ * dst[n] a[n] << b[n]
+ * @param {goog.NumberArray} a
+ * @param {goog.NumberArray} b
+ * @return {Array<number>} Result array
+ */
+deMath.arrayShiftLeft = function(a, b) {
+ if (a.length != b.length)
+ throw new Error('Arrays must have the same size');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(a[i] << b[i]);
+ return dst;
+};
+
+/**
+ * Multiply two vectors, element by element
+ * @param {goog.NumberArray} a
+ * @param {goog.NumberArray} b
+ * @return {Array<number>} Result array
+ */
+
+deMath.multiply = function(a, b) {
+ if (a.length != b.length)
+ throw new Error('Arrays must have the same size');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(a[i] * b[i]);
+ return dst;
+};
+
+/**
+ * Divide two vectors, element by element
+ * @param {goog.NumberArray} a
+ * @param {goog.NumberArray} b
+ * @return {Array<number>} Result array
+ * @throws {Error}
+ */
+
+deMath.divide = function(a, b) {
+ if (a.length != b.length)
+ throw new Error('Arrays must have the same size');
+ var dst = [];
+ for (var i = 0; i < a.length; i++) {
+ if (b[i] === 0)
+ throw new Error('Division by 0');
+ dst.push(a[i] / b[i]);
+ }
+ return dst;
+};
+
+/**
+ * Divide vector by a scalar
+ * @param {goog.NumberArray} a
+ * @param {number} b
+ * @return {Array<number>} Result array
+ */
+deMath.divideScale = function(a, b) {
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(a[i] / b);
+ return dst;
+};
+
+/**
+ * @param {number} a
+ * @param {number} b
+ * @return {number}
+ */
+deMath.mod = function(a, b) {
+ return a - b * Math.floor(a / b);
+};
+
+/**
+ * Modulus vector by a scalar
+ * @param {goog.NumberArray} a
+ * @param {number} b
+ * @return {Array<number>} Result array
+ */
+deMath.modScale = function(a, b) {
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(deMath.mod(a[i], b));
+ return dst;
+};
+
+/**
+ * Multiply vector by a scalar
+ * @param {goog.NumberArray} a
+ * @param {number} b
+ * @return {Array<number>} Result array
+ */
+deMath.scale = function(a, b) {
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(a[i] * b);
+ return dst;
+};
+
+/**
+ * Add vector and scalar, element by element
+ * @param {goog.NumberArray} a
+ * @param {number} b
+ * @return {Array<number>} Result array
+ */
+deMath.addScalar = function(a, b) {
+ if (!Array.isArray(a))
+ throw new Error('First argument must be an array.');
+ if (typeof b !== 'number')
+ throw new Error('Second argument must be a number.');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(a[i] + b);
+ return dst;
+};
+
+/**
+ * Add two vectors, element by element
+ * @param {goog.NumberArray} a
+ * @param {goog.NumberArray} b
+ * @return {Array<number>} Result array
+ */
+deMath.add = function(a, b) {
+ if (a.length != b.length)
+ throw new Error('Arrays must have the same size');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(a[i] + b[i]);
+ return dst;
+};
+
+/**
+ * Subtract two vectors, element by element
+ * @param {goog.NumberArray} a
+ * @param {goog.NumberArray} b
+ * @return {Array<number>} Result array
+ */
+
+deMath.subtract = function(a, b) {
+ if (a.length != b.length)
+ throw new Error('Arrays must have the same size');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(a[i] - b[i]);
+ return dst;
+};
+
+/**
+ * Subtract vector and scalar, element by element
+ * @param {goog.NumberArray} a
+ * @param {number} b
+ * @return {Array<number>} Result array
+ */
+deMath.subScalar = function(a, b) {
+ if (!Array.isArray(a))
+ throw new Error('First argument must be an array.');
+ if (typeof b !== 'number')
+ throw new Error('Second argument must be a number.');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(a[i] - b);
+ return dst;
+};
+
+/**
+ * Calculate absolute difference between two vectors
+ * @param {goog.NumberArray} a
+ * @param {goog.NumberArray} b
+ * @return {Array<number>} abs(diff(a - b))
+ */
+deMath.absDiff = function(a, b) {
+ if (a.length != b.length)
+ throw new Error('Arrays must have the same size');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(Math.abs(a[i] - b[i]));
+ return dst;
+};
+
+/**
+ * Calculate absolute value of a vector
+ * @param {goog.NumberArray} a
+ * @return {Array<number>} abs(a)
+ */
+deMath.abs = function(a) {
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(Math.abs(a[i]));
+ return dst;
+};
+
+/**
+ * Is a <= b (element by element)?
+ * @param {goog.NumberArray} a
+ * @param {goog.NumberArray} b
+ * @return {Array<boolean>} Result array of booleans
+ */
+deMath.lessThanEqual = function(a, b) {
+ if (a.length != b.length)
+ throw new Error('Arrays must have the same size');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(a[i] <= b[i]);
+ return dst;
+};
+
+/**
+ * Is a === b (element by element)?
+ * @param {goog.NumberArray} a
+ * @param {goog.NumberArray} b
+ * @return {boolean} Result
+ */
+deMath.equal = function(a, b) {
+ if (a.length != b.length)
+ throw new Error('Arrays must have the same size');
+ for (var i = 0; i < a.length; i++) {
+ if (a[i] !== b[i])
+ return false;
+ }
+ return true;
+};
+
+/**
+ * Are all values in the array true?
+ * @param {Array<boolean>} a
+ * @return {boolean}
+ */
+deMath.boolAll = function(a) {
+ for (var i = 0; i < a.length; i++)
+ if (a[i] == false)
+ return false;
+ return true;
+};
+
+/**
+ * deMath.assign(a, b) element by element
+ * @param {goog.NumberArray} a
+ * @return {Array<number>}
+ */
+deMath.assign = function(a) {
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(a[i]);
+ return dst;
+};
+
+/**
+ * deMath.max(a, b) element by element
+ * @param {goog.NumberArray} a
+ * @param {goog.NumberArray} b
+ * @return {Array<number>}
+ */
+deMath.max = function(a, b) {
+ if (a.length != b.length)
+ throw new Error('Arrays must have the same size');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(Math.max(a[i], b[i]));
+ return dst;
+};
+
+/**
+ * deMath.min(a, b) element by element
+ * @param {goog.NumberArray} a
+ * @param {goog.NumberArray} b
+ * @return {Array<number>}
+ */
+deMath.min = function(a, b) {
+ if (a.length != b.length)
+ throw new Error('Arrays must have the same size');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(Math.min(a[i], b[i]));
+ return dst;
+};
+
+// Nearest-even rounding in case of tie (fractional part 0.5), otherwise ordinary rounding.
+deMath.rint = function(a) {
+ var floorVal = Math.floor(a);
+ var fracVal = a - floorVal;
+
+ if (fracVal != 0.5)
+ return Math.round(a); // Ordinary case.
+
+ var roundUp = (floorVal % 2) != 0;
+
+ return floorVal + (roundUp ? 1 : 0);
+};
+
+/**
+ * wrap the number, so that it fits in the range [minValue, maxValue]
+ * @param {number} v
+ * @param {number} minValue
+ * @param {number} maxValue
+ * @return {number}
+ */
+deMath.wrap = function(v, minValue, maxValue) {
+ var range = maxValue - minValue + 1;
+
+ if (v < minValue) {
+ v += range * (Math.floor((minValue - v) / range) + 1);
+ }
+ return minValue + Math.floor((v - minValue) % range);
+};
+
+/**
+ * Round number to int by dropping fractional part
+ * it is equivalent of GLSL int() constructor
+ * @param {number} a
+ * @return {number}
+ */
+deMath.intCast = function(a) {
+ var v;
+ if (a >= 0)
+ v = Math.floor(a);
+ else
+ v = Math.ceil(a);
+ return deMath.wrap(v, -0x80000000, 0x7FFFFFFF);
+};
+
+/**
+ * Round number to uint by dropping fractional part
+ * it is equivalent of GLSL uint() constructor
+ * @param {number} a
+ * @return {number}
+ */
+deMath.uintCast = function(a) {
+ var v;
+ if (a >= 0)
+ v = Math.floor(a);
+ else
+ v = Math.ceil(a);
+ return deMath.wrap(v, 0, 0xFFFFFFFF);
+};
+
+/**
+ * @param {number} a
+ * @return {number}
+ */
+deMath.logToFloor = function(a) {
+ assertMsgOptions(a > 0, 'Value is less or equal than zero', false, true);
+ return 31 - deMath.clz32(a);
+};
+
+/**
+ * Find intersection of two rectangles
+ * @param {goog.NumberArray} a Array [x, y, width, height]
+ * @param {goog.NumberArray} b Array [x, y, width, height]
+ * @return {Array<number>}
+ */
+deMath.intersect = function(a, b) {
+ if (a.length != 4)
+ throw new Error('Array "a" must have length 4 but has length: ' + a.length);
+ if (b.length != 4)
+ throw new Error('Array "b" must have length 4 but has length: ' + b.length);
+ var x0 = Math.max(a[0], b[0]);
+ var y0 = Math.max(a[1], b[1]);
+ var x1 = Math.min(a[0] + a[2], b[0] + b[2]);
+ var y1 = Math.min(a[1] + a[3], b[1] + b[3]);
+ var w = Math.max(0, x1 - x0);
+ var h = Math.max(0, y1 - y0);
+
+ return [x0, y0, w, h];
+};
+
+/** deMath.deMathHash
+ * @param {number} a
+ * @return {number}
+ */
+deMath.deMathHash = function(a) {
+ var key = a;
+ key = (key ^ 61) ^ (key >> 16);
+ key = key + (key << 3);
+ key = key ^ (key >> 4);
+ key = key * 0x27d4eb2d; /* prime/odd constant */
+ key = key ^ (key >> 15);
+ return key;
+};
+
+/**
+ * Converts a byte array to a number. Cannot convert numbers larger than 52 bits.
+ * @param {Uint8Array} array
+ * @return {number}
+ */
+deMath.arrayToNumber = function(array) {
+ DE_ASSERT(array.length <= 6 || (array.length == 6 && array[5] <= 127));
+ /** @type {number} */ var result = 0;
+
+ for (var ndx = 0; ndx < array.length; ndx++) {
+ result += array[ndx] * Math.pow(256, ndx);
+ }
+
+ return result;
+};
+
+/**
+ * Fills a byte array with a number
+ * @param {Uint8Array} array Output array (already resized)
+ * @param {number} number
+ */
+deMath.numberToArray = function(array, number) {
+ DE_ASSERT(Number.isInteger(number));
+ for (var byteNdx = 0; byteNdx < array.length; byteNdx++) {
+ /** @type {number} */ var acumzndx = !byteNdx ? number : Math.floor(number / Math.pow(256, byteNdx));
+ array[byteNdx] = acumzndx & 0xFF;
+ }
+};
+
+/**
+ * Obtains the bit fragment from a number
+ * @param {number} x
+ * @param {number} firstNdx
+ * @param {number} lastNdx
+ * @return {number}
+ */
+deMath.getBitRange = function(x, firstNdx, lastNdx) {
+ DE_ASSERT(lastNdx - firstNdx <= 52);
+ var shifted = deMath.shiftRight(x, firstNdx);
+ var bitSize = lastNdx - firstNdx;
+ var mask;
+ if (bitSize < 32)
+ mask = (1 << bitSize) - 1;
+ else
+ mask = Math.pow(2, bitSize) - 1;
+ var masked = deMath.binaryAnd(shifted, mask);
+ return masked;
+};
+
+/**
+ * Obtains the bit fragment from a Uint32Array representing a number.
+ * (ArrayBuffer representations are used in tcuFloat.)
+ *
+ * Cannot return more than 52 bits ((lastNdx - firstNdx) <= 52).
+ *
+ * @param {Uint32Array} array
+ * @param {number} firstNdx
+ * @param {number} lastNdx
+ * @return {number}
+ */
+deMath.getArray32BitRange = function(array, firstNdx, lastNdx) {
+ DE_ASSERT(0 <= firstNdx && firstNdx < (array.length * 32));
+ DE_ASSERT(0 < lastNdx && lastNdx <= (array.length * 32));
+ DE_ASSERT((lastNdx - firstNdx) <= 52);
+
+ // Example of how this works for a 64-bit number (Uint32Array of length 2).
+ //
+ // * Note that the shift operators in the code << and >>> are pointing in
+ // the opposite direction of this diagram, since LSB is shown on the left.
+ //
+ // [array[0], array[1] ]
+ // [00000011111111111111111111111111, 11111111111100000000000000000000]
+ // ^LSB MSB^ ^LSB MSB^
+ //
+ // [00000011111111111111111111111111, 11111111111100000000000000000000]
+ // \ \
+ // firstNdx = 6 (inclusive) lastNdx = 44 (exclusive)
+ // blockIndexA = 0 blockIndexB = 1
+ //
+ // [00000011111111111111111111111111, 11111111111100000000000000000000]
+ // \-----\ \-------------------\
+ // bitsToBeginningOfBlock = 6 bitsFromEndOfBlock = 20
+ //
+ // -------------blockA------------- -------------blockB-------------
+ // [00000011111111111111111111111111, 11111111111100000000000000000000]
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^
+ // blockATruncated blockBTruncated
+ // \--blockATruncatedLength--\
+ //
+ // 11111111111111111111111111 111111111111
+ // ^^^^^^^^^^^^^^^^^^^^^^^^^^--^^^^^^^^^^^^ return value (38 bits)
+
+ /** @type {number} */ var blockIndexA = Math.floor(firstNdx / 32);
+ /** @type {number} */ var bitsToBeginningOfBlock = firstNdx % 32;
+ /** @type {number} */ var blockIndexB = Math.floor((lastNdx - 1) / 32);
+ /** @type {number} */ var bitsFromEndOfBlock = 31 - ((lastNdx - 1) % 32);
+
+ /** @type {number} */ var blockB = array[blockIndexB];
+ // Chop off the most significant `bitsFromEndOfBlock` bits from blockB.
+ // Note: Initially this logic used a bitmask instead. But there are subtle
+ // corner cases in JS that caused results to sometimes come out negative.
+ // This truncation method is just used to avoid that complexity.
+ /** @type {number} */ var blockBTruncated = (blockB << bitsFromEndOfBlock) >>> bitsFromEndOfBlock;
+
+ if (blockIndexA == blockIndexB) {
+ // firstNdx and lastNdx are in the same block.
+ // Chop off the least significant `bitsToBeginningOfBlock` bits from blockBTruncated.
+ return blockBTruncated >>> bitsToBeginningOfBlock;
+ } else {
+ // firstNdx and lastNdx are in different blocks.
+ /** @type {number} */ var blockA = array[blockIndexA];
+ // Chop off the least significant `bitsToBeginningOfBlock` bits from blockA.
+ /** @type {number} */ var blockATruncated = blockA >>> bitsToBeginningOfBlock;
+ /** @type {number} */ var blockATruncatedLength = 32 - bitsToBeginningOfBlock;
+
+ // Concatenate blockATruncated and blockBTruncated.
+ // Conceptually equivalent to:
+ // blockATruncated | (blockBTruncated << blockATruncatedLength)
+ // except that wouldn't work for numbers larger than 32 bits.
+ return blockATruncated + (blockBTruncated * Math.pow(2, blockATruncatedLength));
+ }
+};
+
+/**
+ * Split a large signed number into low and high 32bit dwords.
+ * @param {number} x
+ * @return {Array<number>}
+ */
+deMath.split32 = function(x) {
+ var ret = [];
+ ret[1] = Math.floor(x / 0x100000000);
+ ret[0] = x - ret[1] * 0x100000000;
+ return ret;
+};
+
+/**
+ * Split a signed number's low 32bit dwords into low and high 16bit dwords.
+ * @param {number} x
+ * @return {Array<number>}
+ */
+deMath.split16 = function(x) {
+ var ret = [];
+ x = x & 0xffffffff;
+ ret[1] = Math.floor(x / 0x10000);
+ ret[0] = x - ret[1] * 0x10000;
+ return ret;
+};
+
+/**
+ * Recontruct a number from high and low 32 bit dwords
+ * @param {Array<number>} x
+ * @return {number}
+ */
+deMath.join32 = function(x) {
+ var v0 = x[0] >= 0 ? x[0] : 0x100000000 + x[0];
+ var v1 = x[1];
+ var val = v1 * 0x100000000 + v0;
+ return val;
+};
+
+//Bit operations with the help of arrays
+
+/**
+ * @enum
+ */
+deMath.BinaryOp = {
+ AND: 0,
+ OR: 1,
+ XOR: 2
+};
+
+/**
+ * Performs a normal (native) binary operation
+ * @param {number} valueA First operand
+ * @param {number} valueB Second operand
+ * @param {deMath.BinaryOp} operation The desired operation to perform
+ * @return {number}
+ */
+deMath.doNativeBinaryOp = function(valueA, valueB, operation) {
+ switch (operation) {
+ case deMath.BinaryOp.AND:
+ return valueA & valueB;
+ case deMath.BinaryOp.OR:
+ return valueA | valueB;
+ case deMath.BinaryOp.XOR:
+ return valueA ^ valueB;
+ default:
+ throw new Error('Unknown operation: ' + operation);
+ }
+};
+
+/**
+ * Performs a binary operation between two operands
+ * with the help of arrays to avoid losing the internal binary representation.
+ * @param {number} valueA First operand
+ * @param {number} valueB Second operand
+ * @param {deMath.BinaryOp} binaryOpParm The desired operation to perform
+ * @return {number}
+ */
+deMath.binaryOp = function(valueA, valueB, binaryOpParm) {
+ //quick path if values fit in signed 32 bit range
+ if (deMath.deInRange32(valueA, -0x80000000, 0x7FFFFFFF) && deMath.deInRange32(valueB, -0x80000000, 0x7FFFFFFF))
+ return deMath.doNativeBinaryOp(valueA, valueB, binaryOpParm);
+
+ var x = deMath.split32(valueA);
+ var y = deMath.split32(valueB);
+ var z = [];
+ for (var i = 0; i < 2; i++)
+ z[i] = deMath.doNativeBinaryOp(x[i], y[i], binaryOpParm);
+ var ret = deMath.join32(z);
+ return ret;
+};
+
+/**
+ * @param {number} a
+ * @param {number} b
+ * @return {number}
+ */
+deMath.binaryAnd = function(a, b) {
+ return deMath.binaryOp(a, b, deMath.BinaryOp.AND);
+};
+
+/**
+ * @param {goog.NumberArray} a
+ * @param {number} b
+ * @return {Array<number>}
+ */
+deMath.binaryAndVecScalar = function(a, b) {
+ if (!Array.isArray(a))
+ throw new Error('First argument must be an array.');
+ if (typeof b !== 'number')
+ throw new Error('Second argument must be a number.');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(deMath.binaryOp(a[i], b, deMath.BinaryOp.AND));
+ return dst;
+};
+
+/**
+ * @param {number} a
+ * @param {number} b
+ * @return {number}
+ */
+deMath.binaryOr = function(a, b) {
+ return deMath.binaryOp(a, b, deMath.BinaryOp.OR);
+};
+
+/**
+ * @param {goog.NumberArray} a
+ * @param {number} b
+ * @return {Array<number>}
+ */
+deMath.binaryOrVecScalar = function(a, b) {
+ if (!Array.isArray(a))
+ throw new Error('First argument must be an array.');
+ if (typeof b !== 'number')
+ throw new Error('Second argument must be a number.');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(deMath.binaryOp(a[i], b, deMath.BinaryOp.OR));
+ return dst;
+};
+
+/**
+ * @param {number} a
+ * @param {number} b
+ * @return {number}
+ */
+deMath.binaryXor = function(a, b) {
+ return deMath.binaryOp(a, b, deMath.BinaryOp.XOR);
+};
+
+/**
+ * @param {goog.NumberArray} a
+ * @param {number} b
+ * @return {Array<number>}
+ */
+deMath.binaryXorVecScalar = function(a, b) {
+ if (!Array.isArray(a))
+ throw new Error('First argument must be an array.');
+ if (typeof b !== 'number')
+ throw new Error('Second argument must be a number.');
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(deMath.binaryOp(a[i], b, deMath.BinaryOp.XOR));
+ return dst;
+};
+
+/**
+ * Performs a binary NOT operation on an operand
+ * @param {number} value Operand
+ * @return {number}
+ */
+deMath.binaryNot = function(value) {
+ //quick path if value fits in signed 32 bit range
+ if (deMath.deInRange32(value, -0x80000000, 0x7FFFFFFF))
+ return ~value;
+
+ var x = deMath.split32(value);
+ x[0] = ~x[0];
+ x[1] = ~x[1];
+ var ret = deMath.join32(x);
+ return ret;
+};
+
+/**
+ * Shifts the given value 'steps' bits to the left. Replaces << operator
+ * This function should be used if the expected value will be wider than 32-bits.
+ * @param {number} value
+ * @param {number} steps
+ * @return {number}
+ */
+deMath.shiftLeft = function(value, steps) {
+ //quick path
+ if (steps < 31) {
+ var v = value * (1 << steps);
+ if (deMath.deInRange32(v, -0x80000000, 0x7FFFFFFF))
+ return v;
+ }
+
+ if (steps == 0)
+ return value;
+ else if (steps < 32) {
+ var mask = (1 << 32 - steps) - 1;
+ var x = deMath.split32(value);
+ var highBits = x[0] & (~mask);
+ var y = highBits >> (32 - steps);
+ if (highBits < 0) {
+ var m = (1 << steps) - 1;
+ y &= m;
+ }
+ var result = [];
+ result[0] = x[0] << steps;
+ result[1] = x[1] << steps;
+ result[1] |= y;
+
+ return deMath.join32(result);
+ } else {
+ var x = deMath.split32(value);
+ var result = [];
+ result[0] = 0;
+ result[1] = x[0] << steps - 32;
+ return deMath.join32(result);
+ }
+};
+
+/**
+ * @param {Array<number>} a
+ * @param {number} b
+ */
+deMath.shiftLeftVecScalar = function(a, b) {
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(deMath.shiftLeft(a[i], b));
+ return dst;
+};
+
+/**
+ * Shifts the given value 'steps' bits to the right. Replaces >> operator
+ * This function should be used if the value is wider than 32-bits
+ * @param {number} value
+ * @param {number} steps
+ * @return {number}
+ */
+deMath.shiftRight = function(value, steps) {
+ //quick path
+ if (deMath.deInRange32(value, -0x80000000, 0x7FFFFFFF) && steps < 32)
+ return value >> steps;
+
+ if (steps == 0)
+ return value;
+ else if (steps < 32) {
+ if (steps == 0)
+ return value;
+ var mask = (1 << steps) - 1;
+ var x = deMath.split32(value);
+ var lowBits = x[1] & mask;
+ var result = [];
+ var m = (1 << 32 - steps) - 1;
+ result[0] = (x[0] >> steps) & m;
+ result[1] = x[1] >> steps;
+ result[0] |= lowBits << 32 - steps;
+ return deMath.join32(result);
+ } else {
+ var x = deMath.split32(value);
+ var result = [];
+ result[0] = x[1] >> steps - 32;
+ result[1] = value < 0 ? -1 : 0;
+ return deMath.join32(result);
+ }
+};
+
+/**
+ * @param {Array<number>} a
+ * @param {number} b
+ */
+deMath.shiftRightVecScalar = function(a, b) {
+ var dst = [];
+ for (var i = 0; i < a.length; i++)
+ dst.push(deMath.shiftRight(a[i], b));
+ return dst;
+};
+
+/** deMath.logicalAndBool over two arrays of booleans
+ * @param {Array<boolean>} a
+ * @param {Array<boolean>} b
+ * @return {Array<boolean>}
+ */
+deMath.logicalAndBool = function(a, b) {
+ if (!Array.isArray(a))
+ throw new Error('The first parameter is not an array: (' + typeof(a) + ')' + a);
+ if (!Array.isArray(b))
+ throw new Error('The second parameter is not an array: (' + typeof(b) + ')' + b);
+ if (a.length != b.length)
+ throw new Error('The lengths of the passed arrays are not equivalent. (' + a.length + ' != ' + b.length + ')');
+
+ /** @type {Array<boolean>} */ var result = [];
+ for (var i = 0; i < a.length; i++) {
+ if (a[i] & b[i])
+ result.push(true);
+ else
+ result.push(false);
+ }
+ return result;
+};
+
+/** deMath.logicalOrBool over two arrays of booleans
+ * @param {Array<boolean>} a
+ * @param {Array<boolean>} b
+ * @return {Array<boolean>}
+ */
+deMath.logicalOrBool = function(a, b) {
+ if (!Array.isArray(a))
+ throw new Error('The first parameter is not an array: (' + typeof(a) + ')' + a);
+ if (!Array.isArray(b))
+ throw new Error('The second parameter is not an array: (' + typeof(b) + ')' + b);
+ if (a.length != b.length)
+ throw new Error('The lengths of the passed arrays are not equivalent. (' + a.length + ' != ' + b.length + ')');
+
+ /** @type {Array<boolean>} */ var result = [];
+ for (var i = 0; i < a.length; i++) {
+ if (a[i] | b[i])
+ result.push(true);
+ else
+ result.push(false);
+ }
+ return result;
+};
+
+/** deMath.logicalNotBool over an array of booleans
+ * @param {Array<boolean>} a
+ * @return {Array<boolean>}
+ */
+deMath.logicalNotBool = function(a) {
+ if (!Array.isArray(a))
+ throw new Error('The passed value is not an array: (' + typeof(a) + ')' + a);
+
+ /** @type {Array<boolean>} */ var result = [];
+ for (var i = 0; i < a.length; i++)
+ result.push(!a[i]);
+ return result;
+};
+
+/** deMath.greaterThan over two arrays of booleans
+ * @param {Array<number>} a
+ * @param {Array<number>} b
+ * @return {Array<boolean>}
+ */
+deMath.greaterThan = function(a, b) {
+ if (!Array.isArray(a))
+ throw new Error('The first parameter is not an array: (' + typeof(a) + ')' + a);
+ if (!Array.isArray(b))
+ throw new Error('The second parameter is not an array: (' + typeof(b) + ')' + b);
+ if (a.length != b.length)
+ throw new Error('The lengths of the passed arrays are not equivalent. (' + a.length + ' != ' + b.length + ')');
+
+ /** @type {Array<boolean>} */ var result = [];
+ for (var i = 0; i < a.length; i++)
+ result.push(a[i] > b[i]);
+ return result;
+};
+
+/** deMath.greaterThan over two arrays of booleans
+ * @param {Array<number>} a
+ * @param {Array<number>} b
+ * @return {Array<boolean>}
+ */
+deMath.greaterThanEqual = function(a, b) {
+ if (!Array.isArray(a))
+ throw new Error('The first parameter is not an array: (' + typeof(a) + ')' + a);
+ if (!Array.isArray(b))
+ throw new Error('The second parameter is not an array: (' + typeof(b) + ')' + b);
+ if (a.length != b.length)
+ throw new Error('The lengths of the passed arrays are not equivalent. (' + a.length + ' != ' + b.length + ')');
+
+ /** @type {Array<boolean>} */ var result = [];
+ for (var i = 0; i < a.length; i++)
+ result.push(a[i] >= b[i]);
+ return result;
+};
+
+/**
+ * Array of float to array of int (0, 255)
+ * @param {Array<number>} a
+ * @return {Array<number>}
+ */
+
+deMath.toIVec = function(a) {
+ /** @type {Array<number>} */ var res = [];
+ for (var i = 0; i < a.length; i++)
+ res.push(deMath.clamp(Math.floor(a[i] * 255), 0, 255));
+ return res;
+};
+
+/**
+ * @param {number} a
+ * @return {number}
+ */
+ deMath.clz32 = function(a) {
+ /** @type {number} */ var maxValue = 2147483648; // max 32 bit number
+ /** @type {number} */ var leadingZeros = 0;
+ while (a < maxValue) {
+ maxValue = maxValue >>> 1;
+ leadingZeros++;
+ }
+ return leadingZeros;
+};
+
+/**
+ * @param {number} a
+ * @param {number} exponent
+ * @return {number}
+ */
+deMath.deLdExp = function(a, exponent) {
+ return deMath.ldexp(a, exponent);
+};
+
+/**
+ * @param {number} a
+ * @param {number} exponent
+ * @return {number}
+ */
+deMath.deFloatLdExp = function(a, exponent) {
+ return deMath.ldexp(a, exponent);
+};
+
+/**
+ * @param {number} value
+ * @return {Array<number>}
+ */
+deMath.frexp = (function() {
+ var data = new DataView(new ArrayBuffer(8));
+
+ return function(value) {
+ if (value === 0) return [value, 0];
+ data.setFloat64(0, value);
+ var bits = (data.getUint32(0) >>> 20) & 0x7FF;
+ if (bits === 0) {
+ data.setFloat64(0, value * Math.pow(2, 64));
+ bits = ((data.getUint32(0) >>> 20) & 0x7FF) - 64;
+ }
+ var exponent = bits - 1022,
+ mantissa = deMath.ldexp(value, -exponent);
+ return [mantissa, exponent];
+ }
+})();
+
+/**
+ * @param {number} mantissa
+ * @param {number} exponent
+ * @return {number}
+ */
+deMath.ldexp = function(mantissa, exponent) {
+ return exponent > 1023 ? // avoid multiplying by infinity
+ mantissa * Math.pow(2, 1023) * Math.pow(2, exponent - 1023) :
+ exponent < -1074 ? // avoid multiplying by zero
+ mantissa * Math.pow(2, -1074) * Math.pow(2, exponent + 1074) :
+ mantissa * Math.pow(2, exponent);
+};
+
+/**
+ * @param {number} a
+ * @return {number}
+ */
+deMath.deCbrt = function(a) {
+ return deMath.deSign(a) * Math.pow(Math.abs(a), 1.0 / 3.0);
+};
+
+/**
+ * @param {number} x
+ * @return {number}
+ */
+deMath.deSign = function(x) {
+ return isNaN(x) ? x : ((x > 0.0) - (x < 0.0));
+};
+
+deMath.deFractExp = function(x) {
+ var result = {
+ significand: x,
+ exponent: 0
+ };
+
+ if (isFinite(x)) {
+ var r = deMath.frexp(x);
+ result.exponent = r[1] - 1;
+ result.significand = r[0] * 2;
+ }
+ return result;
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deRandom.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deRandom.js
new file mode 100644
index 0000000000..2246a2e9d3
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deRandom.js
@@ -0,0 +1,260 @@
+/*-------------------------------------------------------------------------
+ * 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.
+ *
+ */
+
+/**
+ * This class allows one to create a random integer, floating point number or boolean (TODO, deRandom.choose random items from a list and deRandom.shuffle an array)
+ */
+'use strict';
+goog.provide('framework.delibs.debase.deRandom');
+
+goog.scope(function() {
+
+var deRandom = framework.delibs.debase.deRandom;
+
+/**
+ * Array of pseudo random numbers based on seed
+ * @constructor
+ * @struct
+ */
+deRandom.deRandom = function() {
+ /** @type {number} */ this.x = 0;
+ /** @type {number} */ this.y = 0;
+ /** @type {number} */ this.z = 0;
+ /** @type {number} */ this.w = 0;
+};
+
+/**
+ * deRandom.Random number generator init
+ * @param {deRandom.deRandom} rnd Array to store random numbers
+ * @param {number} seed Number for seed
+ */
+deRandom.deRandom_init = function(rnd, seed) {
+ rnd.x = (-seed ^ 123456789);
+ rnd.y = (362436069 * seed);
+ rnd.z = (521288629 ^ (seed >> 7));
+ rnd.w = (88675123 ^ (seed << 3));
+};
+
+/**
+ * Function to get random int
+ * @param {deRandom.deRandom} rnd Initialised array of random numbers
+ * @param {Array<number>=} opts Min and max for range
+ * @return {number} deRandom.Random int
+ */
+deRandom.deRandom_getInt = function(rnd, opts) {
+ if (opts != undefined && opts[0] != undefined && opts[1] != undefined) {
+ if (opts[0] == 0x80000000 && opts[1] == 0x7fffffff) {
+ return deRandom.deRandom_getInt(rnd);
+ } else {
+ return opts[0] + (deRandom.deRandom_getInt(rnd) % (opts[1] - opts[0] + 1));
+ }
+ }
+ var w = rnd.w;
+ var t;
+
+ t = rnd.x ^ (rnd.x << 11);
+ rnd.x = rnd.y;
+ rnd.y = rnd.z;
+ rnd.z = w;
+ rnd.w = w = (w ^ (w >> 19)) ^ (t ^ (t >> 8));
+ return w;
+};
+
+/**
+ * Function to get random float
+ * @param {deRandom.deRandom} rnd Initialised array of random numbers
+ * @param {Array<number>=} opts Min and max for range
+ * @return {number} deRandom.Random float
+ */
+deRandom.deRandom_getFloat = function(rnd, opts) {
+ if (opts != undefined && opts[0] != undefined && opts[1] != undefined) {
+ if (opts[0] <= opts[1]) {
+ return opts[0] + (opts[1] - opts[0]) * deRandom.deRandom_getFloat(rnd);
+ }
+ } else {
+ return (deRandom.deRandom_getInt(rnd) & 0xFFFFFFF) / (0xFFFFFFF + 1);
+ }
+ throw new Error('Invalid arguments');
+};
+
+/**
+ * Function to get random boolean
+ * @param {deRandom.deRandom} rnd Initialised array of random numbers
+ * @return {boolean} deRandom.Random boolean
+ */
+deRandom.deRandom_getBool = function(rnd) {
+ var val;
+ val = deRandom.deRandom_getInt(rnd);
+ return ((val & 0xFFFFFF) < 0x800000);
+};
+
+/**
+ * Function to get a common base seed
+ * @return {number} constant
+ */
+deRandom.getBaseSeed = function() {
+ return 42;
+};
+
+/**
+ * TODO Function to deRandom.choose random items from a list
+ * @template T
+ * @param {deRandom.deRandom} rnd Initialised array of random numbers
+ * @param {Array<T>} elements Array segment already defined
+ * @param {Array<T>=} resultOut Array where to store the elements in. If undefined, default to array of (num) elements.
+ * @param {number=} num Number of items to store in resultOut. If undefined, default to 1.
+ * @return {Array<T>} Even though result is stored in resultOut, return it here as well.
+ */
+deRandom.choose = function(rnd, elements, resultOut, num) {
+ var items = num || 1;
+ var temp = elements.slice();
+ if (!resultOut)
+ resultOut = [];
+
+ while (items-- > 0) {
+ var index = deRandom.deRandom_getInt(rnd, [0, temp.length - 1]);
+ resultOut.push(temp[index]);
+ temp.splice(index, 1);
+ }
+ return resultOut;
+};
+
+/**
+ * TODO Function to deRandom.choose weighted random items from a list
+ * @param {deRandom.deRandom} rnd Initialised randomizer
+ * @param {Array<number>} array Array to choose items from
+ * @param {Array<number>} weights Weights array
+ * @return {number} Result output
+ */
+deRandom.chooseWeighted = function(rnd, array, weights) {
+ // Compute weight sum
+ /** @type {number} */ var weightSum = 0.0;
+ /** @type {number} */ var ndx;
+ for (ndx = 0; ndx < array.length; ndx++)
+ weightSum += weights[ndx];
+
+ // Random point in 0..weightSum
+ /** @type {number} */ var p = deRandom.deRandom_getFloat(rnd, [0.0, weightSum]);
+
+ // Find item in range
+ /** @type {number} */ var lastNonZero = array.length;
+ /** @type {number} */ var curWeight = 0.0;
+ for (ndx = 0; ndx != array.length; ndx++) {
+ /** @type {number} */ var w = weights[ndx];
+
+ curWeight += w;
+
+ if (p < curWeight)
+ return array[ndx];
+ else if (w > 0.0)
+ lastNonZero = ndx;
+ }
+
+ assertMsgOptions(lastNonZero != array.length, 'Index went out of bounds', false, true);
+ return array[lastNonZero];
+};
+
+/**
+ * TODO Function to deRandom.shuffle an array
+ * @param {deRandom.deRandom} rnd Initialised array of random numbers
+ * @param {Array} elements Array to deRandom.shuffle
+ * @return {Array} Shuffled array
+ */
+deRandom.shuffle = function(rnd, elements) {
+ var index = elements.length;
+
+ while (index > 0) {
+ var random = deRandom.deRandom_getInt(rnd, [0, index - 1]);
+ index -= 1;
+ var elem = elements[index];
+ elements[index] = elements[random];
+ elements[random] = elem;
+ }
+ return elements;
+};
+
+/**
+ * This function is used to create the deRandom.Random object and
+ * initialise the random number with a seed.
+ * It contains functions for generating random numbers in a variety of formats
+ * @constructor
+ * @param {number} seed Number to use as a seed
+ */
+deRandom.Random = function(seed) {
+ /**
+ * Instance of array of pseudo random numbers based on seeds
+ */
+ this.m_rnd = new deRandom.deRandom();
+
+ //initialise the random numbers based on seed
+ deRandom.deRandom_init(this.m_rnd, seed);
+};
+
+/**
+ * Function to get random boolean
+ * @return {boolean} deRandom.Random boolean
+ */
+deRandom.Random.prototype.getBool = function() { return deRandom.deRandom_getBool(this.m_rnd) == true; };
+/**
+ * Function to get random float
+ * @param {number=} min Min for range
+ * @param {number=} max Max for range
+ * @return {number} deRandom.Random float
+ */
+deRandom.Random.prototype.getFloat = function(min, max) { return deRandom.deRandom_getFloat(this.m_rnd, [min, max]) };
+/**
+ * Function to get random int
+ * @param {number=} min Min for range
+ * @param {number=} max Max for range
+ * @return {number} deRandom.Random int
+ */
+deRandom.Random.prototype.getInt = function(min, max) {return deRandom.deRandom_getInt(this.m_rnd, [min, max])};
+/**
+ * TODO Function to deRandom.choose random items from a list
+ * @template T
+ * @param {Array<T>} elements Array segment already defined
+ * @param {Array<T>=} resultOut Array where to store the elements in. If undefined, default to array of (num) elements.
+ * @param {number=} num Number of items to store in resultOut. If undefined, default to 1.
+ * @return {Array<T>} Even though result is stored in resultOut, return it here as well.
+ */
+deRandom.Random.prototype.choose = function(elements, resultOut, num) {return deRandom.choose(this.m_rnd, elements, resultOut, num)};
+/**
+ * choose weighted random items from a list
+ * @param {Array<number>} array Array to choose items from
+ * @param {Array<number>} weights Weights array
+ * @return {number} Result output
+ */
+deRandom.Random.prototype.chooseWeighted = function(array, weights) {return deRandom.chooseWeighted(this.m_rnd, array, weights)};
+/**
+ * TODO Function to deRandom.shuffle an array
+ * @param {Array} elements Array to deRandom.shuffle
+ * @return {Array} Shuffled array
+ */
+deRandom.Random.prototype.shuffle = function(elements) {return deRandom.shuffle(this.m_rnd, elements)};
+
+/**
+ * Function to get a common base seed
+ * @return {number} constant
+ */
+deRandom.Random.prototype.getBaseSeed = function() {
+ return deRandom.getBaseSeed();
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deString.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deString.js
new file mode 100644
index 0000000000..fc84a72327
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deString.js
@@ -0,0 +1,111 @@
+/*-------------------------------------------------------------------------
+ * 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.
+ *
+ */
+
+/**
+ * This class allows one to create a random integer, floating point number or boolean (TODO, choose random items from a list and shuffle an array)
+ */
+'use strict';
+goog.provide('framework.delibs.debase.deString');
+goog.require('framework.delibs.debase.deMath');
+
+goog.scope(function() {
+
+var deString = framework.delibs.debase.deString;
+var deMath = framework.delibs.debase.deMath;
+
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+ /**
+ * Compute hash from string.
+ * @param {?string} str String to compute hash value for.
+ * @return {number} Computed hash value.
+ */
+ deString.deStringHash = function(str) {
+ /* \note [pyry] This hash is used in DT_GNU_HASH and is proven
+ to be robust for symbol hashing. */
+ /* \see http://sources.redhat.com/ml/binutils/2006-06/msg00418.html */
+ /** @type {number} */ var hash = 5381;
+ /** @type {number} */ var c;
+
+ DE_ASSERT(str != undefined);
+ if (str !== null) {
+ var i = 0;
+ while (i < str.length) { //(c = (unsigned int)*str++) != 0)
+ c = str.charCodeAt(i); //trunc to 8-bit
+ hash = (hash << 5) + hash + c;
+ i++;
+ }
+ }
+ return hash;
+ };
+
+ /**
+ * Checks if a JS string is either empty or undefined
+ * @param {string} str
+ * @return {boolean}
+ */
+ deString.deIsStringEmpty = function(str) {
+ if (str === undefined || str.length == 0)
+ return true;
+ return false;
+ };
+
+ /**
+ * @private
+ * @param {Object} enumType
+ * @param {?} value
+ * @return {string}
+ */
+ deString.getString = function(enumType, value) {
+ for (var p in enumType)
+ if (enumType[p] == value)
+ return p;
+
+ if (typeof value === 'undefined')
+ return 'undefined';
+
+ if (!value)
+ return 'null';
+
+ return value.toString(10);
+ };
+
+ /**
+ * @param {Object} enumType
+ * @param {?} value
+ * @return {string}
+ */
+ deString.enumToString = function(enumType, value) {
+ if (typeof deString.enumToString[enumType] === 'undefined')
+ deString.enumToString[enumType] = {};
+
+ var table = deString.enumToString[enumType];
+ if (typeof table[value] === 'undefined') {
+ var v = deString.getString(enumType, value);
+ table[value] = v;
+ }
+
+ return table[value];
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deUtil.js
new file mode 100644
index 0000000000..56a90b6ff6
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/delibs/debase/deUtil.js
@@ -0,0 +1,90 @@
+/*-------------------------------------------------------------------------
+ * 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.delibs.debase.deUtil');
+goog.require('framework.delibs.debase.deMath');
+
+goog.scope(function() {
+
+ var deUtil = framework.delibs.debase.deUtil;
+ var deMath = framework.delibs.debase.deMath;
+
+ //! Get an element of an array with a specified size.
+ /**
+ * @param {Array} array
+ * @param {number} offset
+ * @return {*}
+ */
+ deUtil.getArrayElement = function(array, offset) {
+ assertMsgOptions(deMath.deInBounds32(offset, 0, array.length), 'Array element out of bounds', false, true);
+ return array[offset];
+ };
+
+ /**
+ * clone - If you need to pass/assign an object by value, call this
+ * @param {*} obj
+ * @return {*}
+ */
+ deUtil.clone = function(obj) {
+ if (obj == null || typeof(obj) != 'object')
+ return obj;
+
+ var temp = {};
+ if (ArrayBuffer.isView(obj)) {
+ temp = new obj.constructor(obj);
+ } else if (obj instanceof Array) {
+ temp = new Array(obj.length);
+ for (var akey in obj)
+ temp[akey] = deUtil.clone(obj[akey]);
+ } else if (obj instanceof ArrayBuffer) {
+ temp = new ArrayBuffer(obj.byteLength);
+ var dst = new Uint8Array(temp);
+ var src = new Uint8Array(obj);
+ dst.set(src);
+ } else {
+ temp = Object.create(obj.constructor.prototype);
+ temp.constructor = obj.constructor;
+ for (var key in obj)
+ temp[key] = deUtil.clone(obj[key]);
+ }
+ return temp;
+ };
+
+ /**
+ * Add a push_unique function to Array. Will insert only if there is no equal element.
+ * @template T
+ * @param {Array<T>} array Any array
+ * @param {T} object Any object
+ */
+ deUtil.dePushUniqueToArray = function(array, object) {
+ //Simplest implementation
+ for (var i = 0; i < array.length; i++) {
+ if (object.equals !== undefined)
+ if (object.equals(array[i]))
+ return undefined;
+ else if (object === array[i])
+ return undefined;
+ }
+
+ array.push(object);
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluDrawUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluDrawUtil.js
new file mode 100644
index 0000000000..baa05a9708
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluDrawUtil.js
@@ -0,0 +1,510 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('framework.opengl.gluDrawUtil');
+goog.require('framework.opengl.gluShaderProgram');
+
+goog.scope(function() {
+
+var gluDrawUtil = framework.opengl.gluDrawUtil;
+var gluShaderProgram = framework.opengl.gluShaderProgram;
+
+/**
+ * Description of a vertex array binding
+ * @constructor
+ * @param {number} type GL gluDrawUtil.Type of data
+ * @param {(number|undefined)} location Binding location
+ * @param {number} components Number of components per vertex
+ * @param {number} elements Number of elements in the array
+ * @param {Array<number>} data Source data
+ * @param {number=} stride
+ * @param {number=} offset
+ */
+gluDrawUtil.VertexArrayBinding = function(type, location, components, elements, data, stride, offset) {
+ this.type = type;
+ this.location = location === undefined ? -1 : location;
+ this.components = components;
+ this.elements = elements;
+ this.data = data;
+ /** @type {?string} */ this.name = null;
+ this.stride = stride || 0;
+ this.offset = offset || 0;
+};
+
+/**
+ * Description of a vertex array binding
+ * @param {gluDrawUtil.BindingPoint} binding
+ * @param {gluDrawUtil.VertexArrayPointer} pointer
+ * @param {number=} dataType GL Data Type
+ * @return {gluDrawUtil.VertexArrayBinding}
+ */
+gluDrawUtil.vabFromBindingPointAndArrayPointer = function(binding, pointer, dataType) {
+ var type = dataType === undefined ? gl.FLOAT : dataType;
+ var location = binding.location;
+ var components = pointer.numComponents;
+ var elements = pointer.numElements;
+ var data = pointer.data;
+ var vaBinding = new gluDrawUtil.VertexArrayBinding(type, location, components, elements, data);
+ vaBinding.componentType = pointer.componentType;
+ vaBinding.name = binding.name;
+ vaBinding.convert = pointer.convert;
+ vaBinding.stride = pointer.stride;
+ return vaBinding;
+};
+
+/**
+ * ! Lower named bindings to locations and eliminate bindings that are not used by program.
+ * @param {WebGL2RenderingContext} gl WebGL context
+ * @param {WebGLProgram} program
+ * @param {Array} inputArray - Array with the named binding locations
+ * @param {Array=} outputArray - Array with the lowered locations
+ * @return {Array} outputArray
+ */
+gluDrawUtil.namedBindingsToProgramLocations = function(gl, program, inputArray, outputArray) {
+ outputArray = outputArray || [];
+
+ for (var i = 0; i < inputArray.length; i++) {
+ var cur = inputArray[i];
+ if (cur.name) {
+ //assert(binding.location >= 0);
+ var location = gl.getAttribLocation(program, cur.name);
+ if (location >= 0) {
+ if (cur.location >= 0)
+ location += cur.location;
+ // Add binding.location as an offset to accomodate matrices.
+ outputArray.push(new gluDrawUtil.VertexArrayBinding(cur.type, location, cur.components, cur.elements, cur.data, cur.stride, cur.offset));
+ }
+ } else {
+ outputArray.push(cur);
+ }
+ }
+
+ return outputArray;
+};
+
+/**
+ * Creates vertex buffer, binds it and draws elements
+ * @param {WebGL2RenderingContext} gl WebGL context
+ * @param {WebGLProgram} program ID, vertexProgramID
+ * @param {Array<gluDrawUtil.VertexArrayBinding>} vertexArrays
+ * @param {gluDrawUtil.PrimitiveList} primitives to gluDrawUtil.draw
+ * @param { {beforeDrawCall:function(), afterDrawCall:function()}=} callback
+ */
+gluDrawUtil.draw = function(gl, program, vertexArrays, primitives, callback) {
+ /** TODO: finish implementation */
+ /** @type {Array<WebGLBuffer>} */ var objects = [];
+
+ // Lower bindings to locations
+ vertexArrays = gluDrawUtil.namedBindingsToProgramLocations(gl, program, vertexArrays);
+
+ for (var i = 0; i < vertexArrays.length; i++) {
+ /** @type {WebGLBuffer} */ var buffer = gluDrawUtil.vertexBuffer(gl, vertexArrays[i]);
+ objects.push(buffer);
+ }
+
+ if (primitives.indices) {
+ /** @type {WebGLBuffer} */ var elemBuffer = gluDrawUtil.indexBuffer(gl, primitives);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, elemBuffer);
+
+ if (callback)
+ callback.beforeDrawCall();
+
+ gluDrawUtil.drawIndexed(gl, primitives, 0);
+
+ if (callback)
+ callback.afterDrawCall();
+
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+ } else {
+ if (callback)
+ callback.beforeDrawCall();
+
+ gl.drawArrays(gluDrawUtil.getPrimitiveGLType(gl, primitives.type), 0, primitives.numElements);
+
+ if (callback)
+ callback.afterDrawCall();
+ }
+
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'drawArrays', false, true);
+ for (var i = 0; i < vertexArrays.length; i++) {
+ gl.disableVertexAttribArray(vertexArrays[i].location);
+ }
+ gl.bindBuffer(gl.ARRAY_BUFFER, null);
+};
+
+/**
+ * Creates vertex buffer, binds it and draws elements
+ * @param {WebGL2RenderingContext} gl WebGL context
+ * @param {gluDrawUtil.PrimitiveList} primitives Primitives to gluDrawUtil.draw
+ * @param {number} offset
+ */
+gluDrawUtil.drawIndexed = function(gl, primitives, offset) {
+/** @type {number} */ var mode = gluDrawUtil.getPrimitiveGLType(gl, primitives.type);
+ /** TODO: C++ implementation supports different index types, we use only int16.
+ Could it cause any issues?
+
+ deUint32 indexGLType = getIndexGLType(primitives.indexType);
+ */
+
+ gl.drawElements(mode, primitives.indices.length, gl.UNSIGNED_SHORT, offset);
+};
+
+/**
+ * Enums for primitive types
+ * @enum
+ */
+gluDrawUtil.primitiveType = {
+ TRIANGLES: 0,
+ TRIANGLE_STRIP: 1,
+ TRIANGLE_FAN: 2,
+
+ LINES: 3,
+ LINE_STRIP: 4,
+ LINE_LOOP: 5,
+
+ POINTS: 6,
+
+ PATCHES: 7
+};
+
+/**
+ * get GL type from primitive type
+ * @param {WebGL2RenderingContext} gl WebGL context
+ * @param {gluDrawUtil.primitiveType} type gluDrawUtil.primitiveType
+ * @return {number} GL primitive type
+ */
+gluDrawUtil.getPrimitiveGLType = function(gl, type) {
+ switch (type) {
+ case gluDrawUtil.primitiveType.TRIANGLES: return gl.TRIANGLES;
+ case gluDrawUtil.primitiveType.TRIANGLE_STRIP: return gl.TRIANGLE_STRIP;
+ case gluDrawUtil.primitiveType.TRIANGLE_FAN: return gl.TRIANGLE_FAN;
+ case gluDrawUtil.primitiveType.LINES: return gl.LINES;
+ case gluDrawUtil.primitiveType.LINE_STRIP: return gl.LINE_STRIP;
+ case gluDrawUtil.primitiveType.LINE_LOOP: return gl.LINE_LOOP;
+ case gluDrawUtil.primitiveType.POINTS: return gl.POINTS;
+// case gluDrawUtil.primitiveType.PATCHES: return gl.PATCHES;
+ default:
+ throw new Error('Unknown primitive type ' + type);
+ }
+};
+
+/**
+ * Calls gluDrawUtil.newPrimitiveListFromIndices() to create primitive list for Points
+ * @param {number} numElements
+ */
+gluDrawUtil.pointsFromElements = function(numElements) {
+ return new gluDrawUtil.PrimitiveList(gluDrawUtil.primitiveType.POINTS, numElements);
+};
+
+/**
+ * Calls gluDrawUtil.newPrimitiveListFromIndices() to create primitive list for Triangles
+ * @param {Array<number>} indices
+ */
+gluDrawUtil.triangles = function(indices) {
+ return gluDrawUtil.newPrimitiveListFromIndices(gluDrawUtil.primitiveType.TRIANGLES, indices);
+};
+
+/**
+ * Calls gluDrawUtil.newPrimitiveListFromIndices() to create primitive list for Patches
+ * @param {Array<number>} indices
+ */
+gluDrawUtil.patches = function(indices) {
+ return gluDrawUtil.newPrimitiveListFromIndices(gluDrawUtil.primitiveType.PATCHES, indices);
+};
+
+/**
+ * Creates primitive list for Triangles or Patches, depending on type
+ * @param {gluDrawUtil.primitiveType} type gluDrawUtil.primitiveType
+ * @param {number} numElements
+ * @constructor
+ */
+gluDrawUtil.PrimitiveList = function(type, numElements) {
+ this.type = type;
+ this.indices = 0;
+ this.numElements = numElements;
+};
+
+/**
+ * @param {gluDrawUtil.primitiveType} type
+ * @param {Array<number>} indices
+ * @return {gluDrawUtil.PrimitiveList}
+ */
+gluDrawUtil.newPrimitiveListFromIndices = function(type, indices) {
+ /** @type {gluDrawUtil.PrimitiveList} */ var primitiveList = new gluDrawUtil.PrimitiveList(type, 0);
+ primitiveList.indices = indices;
+ return primitiveList;
+};
+
+/**
+ * Create Element Array Buffer
+ * @param {WebGL2RenderingContext} gl WebGL context
+ * @param {gluDrawUtil.PrimitiveList} primitives to construct the buffer from
+ * @return {WebGLBuffer} indexObject buffer with elements
+ */
+gluDrawUtil.indexBuffer = function(gl, primitives) {
+ /** @type {WebGLBuffer} */ var indexObject = gl.createBuffer();
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indexObject);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'bindBuffer', false, true);
+ gl.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(primitives.indices), gl.STATIC_DRAW);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'bufferData', false, true);
+ gl.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, null);
+ return indexObject;
+};
+
+/**
+ * Create Array Buffer
+ * @param {WebGL2RenderingContext} gl WebGL context
+ * @param {gluDrawUtil.VertexArrayBinding} vertexArray primitives, Array buffer descriptor
+ * @return {WebGLBuffer} buffer of vertices
+ */
+gluDrawUtil.vertexBuffer = function(gl, vertexArray) {
+ /** @type {goog.TypedArray} */ var typedArray;
+ switch (vertexArray.type) {
+ case gl.BYTE: typedArray = new Int8Array(vertexArray.data); break;
+ case gl.UNSIGNED_BYTE: typedArray = new Uint8Array(vertexArray.data); break;
+ case gl.SHORT: typedArray = new Int16Array(vertexArray.data); break;
+ case gl.UNSIGNED_SHORT: typedArray = new Uint16Array(vertexArray.data); break;
+ case gl.INT: typedArray = new Int32Array(vertexArray.data); break;
+ case gl.UNSIGNED_INT: typedArray = new Uint32Array(vertexArray.data); break;
+ default: typedArray = new Float32Array(vertexArray.data); break;
+ }
+
+ /** @type {WebGLBuffer} */ var buffer = gl.createBuffer();
+ gl.bindBuffer(gl.ARRAY_BUFFER, buffer);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'bindBuffer', false, true);
+ gl.bufferData(gl.ARRAY_BUFFER, typedArray, gl.STATIC_DRAW);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'bufferData', false, true);
+ gl.enableVertexAttribArray(vertexArray.location);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'enableVertexAttribArray', false, true);
+ if (vertexArray.type === gl.FLOAT) {
+ gl.vertexAttribPointer(vertexArray.location, vertexArray.components, vertexArray.type, false, vertexArray.stride, vertexArray.offset);
+ } else {
+ gl.vertexAttribIPointer(vertexArray.location, vertexArray.components, vertexArray.type, vertexArray.stride, vertexArray.offset);
+ }
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'vertexAttribPointer', false, true);
+ return buffer;
+};
+
+/**
+ * @param {Array<number>} rgba
+ * @constructor
+ */
+gluDrawUtil.Pixel = function(rgba) {
+ this.rgba = rgba;
+};
+
+gluDrawUtil.Pixel.prototype.getRed = function() {
+ return this.rgba[0];
+};
+gluDrawUtil.Pixel.prototype.getGreen = function() {
+ return this.rgba[1];
+};
+gluDrawUtil.Pixel.prototype.getBlue = function() {
+ return this.rgba[2];
+};
+gluDrawUtil.Pixel.prototype.getAlpha = function() {
+ return this.rgba[3];
+};
+gluDrawUtil.Pixel.prototype.equals = function(otherPixel) {
+ return this.rgba[0] == otherPixel.rgba[0] &&
+ this.rgba[1] == otherPixel.rgba[1] &&
+ this.rgba[2] == otherPixel.rgba[2] &&
+ this.rgba[3] == otherPixel.rgba[3];
+};
+
+/**
+ * @constructor
+ */
+gluDrawUtil.Surface = function() {
+};
+
+gluDrawUtil.Surface.prototype.readSurface = function(gl, x, y, width, height) {
+ this.buffer = new Uint8Array(width * height * 4);
+ gl.readPixels(x, y, width, height, gl.RGBA, gl.UNSIGNED_BYTE, this.buffer);
+ this.x = x;
+ this.y = y;
+ this.width = width;
+ this.height = height;
+ return this.buffer;
+};
+
+gluDrawUtil.Surface.prototype.getPixel = function(x, y) {
+ /** @type {number} */ var base = (x + y * this.width) * 4;
+ /** @type {Array<number>} */
+ var rgba = [
+ this.buffer[base],
+ this.buffer[base + 1],
+ this.buffer[base + 2],
+ this.buffer[base + 3]
+ ];
+ return new gluDrawUtil.Pixel(rgba);
+};
+
+gluDrawUtil.Surface.prototype.getPixelUintRGB8 = function(x, y) {
+ /** @type {number} */ var base = (x + y * this.width) * 4;
+ /** @type {number} */
+ return (this.buffer[base] << 16) +
+ (this.buffer[base + 1] << 8) +
+ this.buffer[base + 2];
+};
+
+/**
+ * @enum
+ */
+gluDrawUtil.VertexComponentType = {
+ // Standard types: all conversion types apply.
+ VTX_COMP_UNSIGNED_INT8: 0,
+ VTX_COMP_UNSIGNED_INT16: 1,
+ VTX_COMP_UNSIGNED_INT32: 2,
+ VTX_COMP_SIGNED_INT8: 3,
+ VTX_COMP_SIGNED_INT16: 4,
+ VTX_COMP_SIGNED_INT32: 5,
+
+ // Special types: only CONVERT_NONE is allowed.
+ VTX_COMP_FIXED: 6,
+ VTX_COMP_HALF_FLOAT: 7,
+ VTX_COMP_FLOAT: 8
+};
+
+/**
+ * @enum
+ */
+gluDrawUtil.VertexComponentConversion = {
+ VTX_COMP_CONVERT_NONE: 0, //!< No conversion: integer types, or floating-point values.
+ VTX_COMP_CONVERT_NORMALIZE_TO_FLOAT: 1, //!< Normalize integers to range [0,1] or [-1,1] depending on type.
+ VTX_COMP_CONVERT_CAST_TO_FLOAT: 2 //!< Convert to floating-point directly.
+};
+
+/**
+ * gluDrawUtil.VertexArrayPointer
+ * @constructor
+ * @param {gluDrawUtil.VertexComponentType} componentType_
+ * @param {gluDrawUtil.VertexComponentConversion} convert_
+ * @param {number} numComponents_
+ * @param {number} numElements_
+ * @param {number} stride_
+ * @const @param {Array<number>} data_
+ */
+gluDrawUtil.VertexArrayPointer = function(componentType_, convert_, numComponents_, numElements_, stride_, data_) {
+ this.componentType = componentType_;
+ this.convert = convert_;
+ this.numComponents = numComponents_;
+ this.numElements = numElements_;
+ this.stride = stride_;
+ this.data = data_;
+};
+
+/**
+ * gluDrawUtil.BindingPoint
+ * @constructor
+ * @param {string} name
+ * @param {number} location
+ * @param {number=} offset
+ */
+gluDrawUtil.BindingPoint = function(name, location, offset) {
+ /** @type {string} */ this.name = name;
+ /** @type {number} */ this.location = location;
+ /** @type {number} */ this.offset = offset || 0;
+};
+
+/**
+ * bindingPointFromLocation
+ * @param {number} location
+ * return {gluDrawUtil.BindingPoint}
+ */
+gluDrawUtil.bindingPointFromLocation = function(location) {
+ return new gluDrawUtil.BindingPoint('', location);
+};
+
+/**
+ * bindingPointFromName
+ * @param {string} name
+ * @param {number=} location
+ * return {gluDrawUtil.BindingPoint}
+ */
+gluDrawUtil.bindingPointFromName = function(name, location) {
+ location = location === undefined ? -1 : location;
+ return new gluDrawUtil.BindingPoint(name, location);
+};
+
+/**
+ * @param {string} name
+ * @param {number} numComponents
+ * @param {number} numElements
+ * @param {number} stride
+ * @param {Array<number>} data
+ * @return {gluDrawUtil.VertexArrayBinding}
+ */
+gluDrawUtil.newInt32VertexArrayBinding = function(name, numComponents, numElements, stride, data) {
+ var bindingPoint = gluDrawUtil.bindingPointFromName(name);
+ var arrayPointer = new gluDrawUtil.VertexArrayPointer(gluDrawUtil.VertexComponentType.VTX_COMP_SIGNED_INT32,
+ gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE, numComponents, numElements, stride, data);
+ return gluDrawUtil.vabFromBindingPointAndArrayPointer(bindingPoint, arrayPointer, gl.INT);
+};
+
+/**
+ * @param {string} name
+ * @param {number} numComponents
+ * @param {number} numElements
+ * @param {number} stride
+ * @param {Array<number>} data
+ * @return {gluDrawUtil.VertexArrayBinding}
+ */
+gluDrawUtil.newUint32VertexArrayBinding = function(name, numComponents, numElements, stride, data) {
+ var bindingPoint = gluDrawUtil.bindingPointFromName(name);
+ var arrayPointer = new gluDrawUtil.VertexArrayPointer(gluDrawUtil.VertexComponentType.VTX_COMP_UNSIGNED_INT32,
+ gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE, numComponents, numElements, stride, data);
+ return gluDrawUtil.vabFromBindingPointAndArrayPointer(bindingPoint, arrayPointer, gl.UNSIGNED_INT);
+};
+
+/**
+ * @param {string} name
+ * @param {number} numComponents
+ * @param {number} numElements
+ * @param {number} stride
+ * @param {Array<number>} data
+ * @return {gluDrawUtil.VertexArrayBinding}
+ */
+gluDrawUtil.newFloatVertexArrayBinding = function(name, numComponents, numElements, stride, data) {
+ var bindingPoint = gluDrawUtil.bindingPointFromName(name);
+ var arrayPointer = new gluDrawUtil.VertexArrayPointer(gluDrawUtil.VertexComponentType.VTX_COMP_FLOAT,
+ gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE, numComponents, numElements, stride, data);
+ return gluDrawUtil.vabFromBindingPointAndArrayPointer(bindingPoint, arrayPointer);
+};
+
+/**
+ * @param {string} name
+ * @param {number} column
+ * @param {number} rows
+ * @param {number} numElements
+ * @param {number} stride
+ * @param {Array<number>} data
+ * @return {gluDrawUtil.VertexArrayBinding}
+ */
+gluDrawUtil.newFloatColumnVertexArrayBinding = function(name, column, rows, numElements, stride, data) {
+ var bindingPoint = gluDrawUtil.bindingPointFromName(name);
+ bindingPoint.location = column;
+ var arrayPointer = new gluDrawUtil.VertexArrayPointer(gluDrawUtil.VertexComponentType.VTX_COMP_FLOAT,
+ gluDrawUtil.VertexComponentConversion.VTX_COMP_CONVERT_NONE, rows, numElements, stride, data);
+ return gluDrawUtil.vabFromBindingPointAndArrayPointer(bindingPoint, arrayPointer);
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluObjectWrapper.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluObjectWrapper.js
new file mode 100644
index 0000000000..38f8a28f9c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluObjectWrapper.js
@@ -0,0 +1,117 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+'use strict';
+
+goog.provide('framework.opengl.gluObjectWrapper');
+
+goog.scope(function() {
+ var gluObjectWrapper = framework.opengl.gluObjectWrapper;
+
+ /**
+ * @typedef {function(this:WebGLRenderingContextBase): WebGLObject}
+ */
+ gluObjectWrapper.funcGenT;
+
+ /**
+ * @typedef {function(this:WebGLRenderingContextBase, WebGLObject)}
+ */
+ gluObjectWrapper.funcDelT;
+
+ /**
+ * @typedef {{name: string, funcGen: !gluObjectWrapper.funcGenT, funcDel: !gluObjectWrapper.funcDelT}}
+ */
+ gluObjectWrapper.traitsT;
+
+ /**
+ * Returns an object containing a configuration for an ObjectWrapper
+ * @param {string} name
+ * @param {gluObjectWrapper.funcGenT} funcGen
+ * @param {gluObjectWrapper.funcDelT} funcDel
+ * @return {gluObjectWrapper.traitsT}
+ */
+ gluObjectWrapper.traits = function(name, funcGen, funcDel) {
+ return {
+ name: name,
+ funcGen: funcGen,
+ funcDel: funcDel
+ };
+ };
+
+ /**
+ * @constructor
+ * @param {WebGLRenderingContextBase} gl
+ * @param {gluObjectWrapper.traitsT} traits
+ */
+ gluObjectWrapper.ObjectWrapper = function(gl, traits) {
+ /**
+ * @protected
+ * @type {WebGLRenderingContextBase}
+ */
+ this.m_gl = gl;
+
+ /**
+ * @protected
+ * @type {gluObjectWrapper.traitsT}
+ */
+ this.m_traits = traits;
+
+ /**
+ * @protected
+ * @type {WebGLObject}
+ */
+ this.m_object = this.m_traits.funcGen.call(gl);
+
+ };
+
+ /**
+ * Destorys the WebGLObject associated with this object.
+ */
+ gluObjectWrapper.ObjectWrapper.prototype.clear = function() {
+ this.m_traits.funcDel.call(this.m_gl, this.m_object);
+ };
+
+ /**
+ * Returns the WebGLObject associated with this object.
+ * @return {WebGLObject}
+ */
+ gluObjectWrapper.ObjectWrapper.prototype.get = function() {
+ return this.m_object;
+ };
+
+ /**
+ * @constructor
+ * @extends {gluObjectWrapper.ObjectWrapper}
+ * @param {WebGLRenderingContextBase} gl
+ */
+ gluObjectWrapper.Framebuffer = function(gl) {
+ gluObjectWrapper.ObjectWrapper.call(this, gl, gluObjectWrapper.traits(
+ 'framebuffer',
+ /** @type {gluObjectWrapper.funcGenT} */(gl.createFramebuffer),
+ /** @type {gluObjectWrapper.funcDelT} */(gl.deleteFramebuffer)
+ ));
+ };
+ gluObjectWrapper.Framebuffer.prototype = Object.create(gluObjectWrapper.ObjectWrapper.prototype);
+ gluObjectWrapper.Framebuffer.prototype.constructor = gluObjectWrapper.Framebuffer;
+
+ /**
+ * @return {WebGLFramebuffer}
+ */
+ gluObjectWrapper.Framebuffer.prototype.get;
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluPixelTransfer.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluPixelTransfer.js
new file mode 100644
index 0000000000..04b81a2a1a
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluPixelTransfer.js
@@ -0,0 +1,55 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('framework.opengl.gluPixelTransfer');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.opengl.gluTextureUtil');
+
+goog.scope(function() {
+
+var gluPixelTransfer = framework.opengl.gluPixelTransfer;
+var tcuTexture = framework.common.tcuTexture;
+var deMath = framework.delibs.debase.deMath;
+var gluTextureUtil = framework.opengl.gluTextureUtil;
+
+gluPixelTransfer.getTransferAlignment = function(format) {
+ var pixelSize = format.getPixelSize();
+ if (deMath.deIsPowerOfTwo32(pixelSize))
+ return Math.min(pixelSize, 8);
+ else
+ return 1;
+};
+
+gluPixelTransfer.readPixels = function(ctx, x, y, format, dst) {
+ var width = dst.getWidth();
+ var height = dst.getHeight();
+ var arrayType = tcuTexture.getTypedArray(format.type);
+ var transferFormat = gluTextureUtil.getTransferFormat(format);
+ ctx.pixelStorei(ctx.PACK_ALIGNMENT, gluPixelTransfer.getTransferAlignment(format));
+ var resultPixel = dst.getAccess().getDataPtr();
+ resultPixel = new arrayType(dst.getAccess().getBuffer());
+ ctx.readPixels(x, y, width, height, transferFormat.format, transferFormat.dataType, resultPixel);
+};
+
+/* TODO: implement other functions in C++ file */
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderProgram.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderProgram.js
new file mode 100644
index 0000000000..0c340ee380
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderProgram.js
@@ -0,0 +1,488 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality gluShaderProgram.Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('framework.opengl.gluShaderProgram');
+
+goog.scope(function() {
+
+var gluShaderProgram = framework.opengl.gluShaderProgram;
+
+/**
+ * gluShaderProgram.Shader type enum
+ * @enum {number}
+ */
+gluShaderProgram.shaderType = {
+ VERTEX: 0,
+ FRAGMENT: 1
+};
+
+/**
+ * gluShaderProgram.Shader type enum name
+ * @param {gluShaderProgram.shaderType} shaderType
+ * @return {string}
+ */
+gluShaderProgram.getShaderTypeName = function(shaderType) {
+ var s_names =
+ [
+ 'vertex',
+ 'fragment'
+ ];
+
+ return s_names[shaderType];
+};
+
+/**
+ * Get GL shader type from gluShaderProgram.shaderType
+ * @param {WebGL2RenderingContext} gl WebGL context
+ * @param {gluShaderProgram.shaderType} type gluShaderProgram.Shader Type
+ * @return {number} GL shader type
+ */
+gluShaderProgram.getGLShaderType = function(gl, type) {
+ var _glShaderType;
+ switch (type) {
+ case gluShaderProgram.shaderType.VERTEX: _glShaderType = gl.VERTEX_SHADER; break;
+ case gluShaderProgram.shaderType.FRAGMENT: _glShaderType = gl.FRAGMENT_SHADER; break;
+ default:
+ throw new Error('Unknown shader type ' + type);
+ }
+ return _glShaderType;
+};
+
+/**
+ * Declares shader information
+ * @constructor
+ * @param {gluShaderProgram.shaderType} type
+ * @param {string=} source
+ */
+gluShaderProgram.ShaderInfo = function(type, source) {
+ this.type = type; /** gluShaderProgram.Shader type. */
+ this.source = source; /** gluShaderProgram.Shader source. */
+ this.infoLog; /** Compile info log. */
+ this.compileOk = false; /** Did compilation succeed? */
+ this.compileTimeUs = 0; /** Compile time in microseconds (us). */
+};
+
+/**
+ * Generates vertex shader info from source
+ * @param {string} source
+ * @return {gluShaderProgram.ShaderInfo} vertex shader info
+ */
+gluShaderProgram.genVertexSource = function(source) {
+/** @type {gluShaderProgram.ShaderInfo} */ var shader = new gluShaderProgram.ShaderInfo(gluShaderProgram.shaderType.VERTEX, source);
+ return shader;
+};
+
+/**
+ * Generates fragment shader info from source
+ * @param {string} source
+ * @return {gluShaderProgram.ShaderInfo} fragment shader info
+ */
+gluShaderProgram.genFragmentSource = function(source) {
+/** @type {gluShaderProgram.ShaderInfo} */ var shader = new gluShaderProgram.ShaderInfo(gluShaderProgram.shaderType.FRAGMENT, source);
+ return shader;
+};
+
+/**
+ * Generates shader from WebGL context and type
+ * @constructor
+ * @param {WebGL2RenderingContext} gl WebGL context
+ * @param {gluShaderProgram.shaderType} type gluShaderProgram.Shader Type
+ */
+gluShaderProgram.Shader = function(gl, type) {
+ this.gl = gl;
+ this.info = new gluShaderProgram.ShaderInfo(type); /** Client-side clone of state for debug / perf reasons. */
+ this.shader = gl.createShader(gluShaderProgram.getGLShaderType(gl, type));
+ assertMsgOptions(gl.getError() == gl.NO_ERROR, 'gl.createShader()', false, true);
+
+ this.setSources = function(source) {
+ this.gl.shaderSource(this.shader, source);
+ assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'glshaderSource()', false, true);
+ this.info.source = source;
+ };
+
+ this.getCompileStatus = function() {
+ return this.info.compileOk;
+ };
+
+ this.compile = function() {
+ this.info.compileOk = false;
+ this.info.compileTimeUs = 0;
+ this.info.infoLog = '';
+
+ /** @type {Date} */ var compileStart = new Date();
+ this.gl.compileShader(this.shader);
+ /** @type {Date} */ var compileEnd = new Date();
+ this.info.compileTimeUs = 1000 * (compileEnd.getTime() - compileStart.getTime());
+
+ assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.compileShader()', false, true);
+
+ var compileStatus = this.gl.getShaderParameter(this.shader, this.gl.COMPILE_STATUS);
+ assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'glGetShaderParameter()', false, true);
+
+ this.info.compileOk = compileStatus;
+ this.info.infoLog = this.gl.getShaderInfoLog(this.shader);
+ };
+
+ this.getShader = function() {
+ return this.shader;
+ };
+
+ this.destroy = function() {
+ this.gl.deleteShader(this.shader);
+ };
+
+};
+/**
+ * Creates gluShaderProgram.ProgramInfo
+ * @constructor
+ */
+gluShaderProgram.ProgramInfo = function() {
+ /** @type {string} */ this.infoLog = ''; /** Link info log. */
+ /** @type {boolean} */ this.linkOk = false; /** Did link succeed? */
+ /** @type {number} */ this.linkTimeUs = 0; /** Link time in microseconds (us). */
+};
+
+/**
+ * Creates program.
+ * Inner methods: attach shaders, bind attributes location, link program and transform Feedback Varyings
+ * @constructor
+ * @param {WebGL2RenderingContext} gl WebGL context
+ * @param {WebGLProgram=} programID
+ */
+gluShaderProgram.Program = function(gl, programID) {
+ this.gl = gl;
+ this.program = programID || null;
+ this.info = new gluShaderProgram.ProgramInfo();
+
+ if (!programID) {
+ this.program = gl.createProgram();
+ assertMsgOptions(gl.getError() == gl.NO_ERROR, 'gl.createProgram()', false, true);
+ }
+};
+
+/**
+ * @return {WebGLProgram}
+ */
+gluShaderProgram.Program.prototype.getProgram = function() { return this.program; };
+
+/**
+ * @return {gluShaderProgram.ProgramInfo}
+ */
+gluShaderProgram.Program.prototype.getInfo = function() { return this.info; };
+
+/**
+ * @param {WebGLShader} shader
+ */
+gluShaderProgram.Program.prototype.attachShader = function(shader) {
+ this.gl.attachShader(this.program, shader);
+ assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.attachShader()', false, true);
+};
+
+/**
+ * @param {WebGLShader} shader
+ */
+gluShaderProgram.Program.prototype.detachShader = function(shader) {
+ this.gl.detachShader(this.program, shader);
+ assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.detachShader()', false, true);
+};
+
+/**
+ * @param {number} location
+ * @param {string} name
+ */
+gluShaderProgram.Program.prototype.bindAttribLocation = function(location, name) {
+ this.gl.bindAttribLocation(this.program, location, name);
+ assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.bindAttribLocation()', false, true);
+};
+
+gluShaderProgram.Program.prototype.link = function() {
+ this.info.linkOk = false;
+ this.info.linkTimeUs = 0;
+ this.info.infoLog = '';
+
+ /** @type {Date} */ var linkStart = new Date();
+ this.gl.linkProgram(this.program);
+ /** @type {Date} */ var linkEnd = new Date();
+ this.info.linkTimeUs = 1000 * (linkEnd.getTime() - linkStart.getTime());
+
+ assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.linkProgram()', false, true);
+
+ var linkStatus = this.gl.getProgramParameter(this.program, this.gl.LINK_STATUS);
+ assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.getProgramParameter()', false, true);
+ this.info.linkOk = linkStatus;
+ this.info.infoLog = this.gl.getProgramInfoLog(this.program);
+ if (!this.info.linkOk)
+ bufferedLogToConsole("program linking: " + this.info.infoLog);
+};
+
+/**
+ * return {boolean}
+ */
+gluShaderProgram.Program.prototype.getLinkStatus = function() {
+ return this.info.linkOk;
+};
+
+/**
+ * @param {Array<string>} varyings
+ * @param {number} bufferMode
+ */
+gluShaderProgram.Program.prototype.transformFeedbackVaryings = function(varyings, bufferMode) {
+ this.gl.transformFeedbackVaryings(this.program, varyings, bufferMode);
+ assertMsgOptions(this.gl.getError() == this.gl.NO_ERROR, 'gl.transformFeedbackVaryings()', false, true);
+};
+
+/**
+ * Assigns gl WebGL context and programSources. Declares array of shaders and new program()
+ * @constructor
+ * @param {WebGL2RenderingContext} gl WebGL context
+ * @param {gluShaderProgram.ProgramSources} programSources
+ */
+gluShaderProgram.ShaderProgram = function(gl, programSources) {
+ this.gl = gl;
+ this.programSources = programSources;
+ this.shaders = [];
+ this.program = new gluShaderProgram.Program(gl);
+
+ /** @type {boolean} */ this.shadersOK = true;
+
+ for (var i = 0; i < programSources.sources.length; i++) {
+ /** @type {gluShaderProgram.Shader} */ var shader = new gluShaderProgram.Shader(gl, programSources.sources[i].type);
+ shader.setSources(programSources.sources[i].source);
+ shader.compile();
+ this.shaders.push(shader);
+ this.shadersOK = this.shadersOK && shader.getCompileStatus();
+ if (!shader.getCompileStatus()) {
+ bufferedLogToConsole('gluShaderProgram.Shader:\n' + programSources.sources[i].source);
+ bufferedLogToConsole('Compile status: ' + shader.getCompileStatus());
+ bufferedLogToConsole('Shader infoLog: ' + shader.info.infoLog);
+ }
+ }
+
+ if (this.shadersOK) {
+ for (var i = 0; i < this.shaders.length; i++)
+ this.program.attachShader(this.shaders[i].getShader());
+
+ for (var attrib in programSources.attribLocationBindings)
+ this.program.bindAttribLocation(programSources.attribLocationBindings[attrib], attrib);
+
+ if (programSources.transformFeedbackBufferMode)
+ if (programSources.transformFeedbackBufferMode === gl.NONE)
+ assertMsgOptions(programSources.transformFeedbackVaryings.length === 0, 'Transform feedback sanity check', false, true);
+ else
+ this.program.transformFeedbackVaryings(programSources.transformFeedbackVaryings, programSources.transformFeedbackBufferMode);
+
+ /* TODO: GLES 3.1: set separable flag */
+
+ this.program.link();
+
+ }
+};
+
+/**
+ * return {WebGLProgram}
+ */
+gluShaderProgram.ShaderProgram.prototype.getProgram = function() {
+ return this.program.program;
+ };
+
+/**
+ * @return {gluShaderProgram.ProgramInfo}
+ */
+gluShaderProgram.ShaderProgram.prototype.getProgramInfo = function() {
+ return this.program.info;
+};
+
+gluShaderProgram.ShaderProgram.prototype.isOk = function() {
+ return this.shadersOK && this.program.getLinkStatus();
+};
+
+gluShaderProgram.containerTypes = {
+ ATTRIB_LOCATION_BINDING: 0,
+ TRANSFORM_FEEDBACK_MODE: 1,
+ TRANSFORM_FEEDBACK_VARYING: 2,
+ TRANSFORM_FEEDBACK_VARYINGS: 3,
+ SHADER_SOURCE: 4,
+ PROGRAM_SEPARABLE: 5,
+ PROGRAM_SOURCES: 6,
+
+ CONTAINER_TYPE_LAST: 7,
+ ATTACHABLE_BEGIN: 0, // ATTRIB_LOCATION_BINDING
+ ATTACHABLE_END: 5 + 1 // PROGRAM_SEPARABLE + 1
+};
+
+/**
+ * @constructor
+ */
+gluShaderProgram.AttribLocationBinding = function(name, location) {
+ this.name = name;
+ this.location = location;
+
+ this.getContainerType = function() {
+ return gluShaderProgram.containerTypes.ATTRIB_LOCATION_BINDING;
+ };
+};
+
+/**
+ * @constructor
+ */
+gluShaderProgram.TransformFeedbackMode = function(mode) {
+ this.mode = mode;
+
+ this.getContainerType = function() {
+ return gluShaderProgram.containerTypes.TRANSFORM_FEEDBACK_MODE;
+ };
+};
+
+/**
+ * @constructor
+ * @param {string} name
+ */
+gluShaderProgram.TransformFeedbackVarying = function(name) {
+ /** @type {string} */ this.name = name;
+
+ this.getContainerType = function() {
+ return gluShaderProgram.containerTypes.TRANSFORM_FEEDBACK_VARYING;
+ };
+};
+
+/**
+ * @constructor
+ * @param {Array<string>} array
+ */
+gluShaderProgram.TransformFeedbackVaryings = function(array) {
+ /** @type {Array<string>} */ this.array = array;
+
+ this.getContainerType = function() {
+ return gluShaderProgram.containerTypes.TRANSFORM_FEEDBACK_VARYINGS;
+ };
+};
+
+/**
+ * @constructor
+ */
+gluShaderProgram.ProgramSeparable = function(separable) {
+ this.separable = separable;
+
+ this.getContainerType = function() {
+ return gluShaderProgram.containerTypes.PROGRAM_SEPARABLE;
+ };
+};
+
+/**
+ * @constructor
+ */
+gluShaderProgram.VertexSource = function(str) {
+ this.shaderType = gluShaderProgram.shaderType.VERTEX;
+ this.source = str;
+
+ this.getContainerType = function() {
+ return gluShaderProgram.containerTypes.SHADER_SOURCE;
+ };
+};
+
+/**
+ * @constructor
+ */
+gluShaderProgram.FragmentSource = function(str) {
+ this.shaderType = gluShaderProgram.shaderType.FRAGMENT;
+ this.source = str;
+
+ this.getContainerType = function() {
+ return gluShaderProgram.containerTypes.SHADER_SOURCE;
+ };
+};
+
+/**
+ * Create gluShaderProgram.ProgramSources.
+ * @constructor
+ */
+gluShaderProgram.ProgramSources = function() {
+ /** @type {Array<gluShaderProgram.ShaderInfo>} */ this.sources = [];
+ this.attribLocationBindings = [];
+ /** @type {Array<string>} */ this.transformFeedbackVaryings = [];
+ this.transformFeedbackBufferMode = 0;
+ this.separable = false;
+};
+
+gluShaderProgram.ProgramSources.prototype.getContainerType = function() {
+ return gluShaderProgram.containerTypes.PROGRAM_SOURCES;
+};
+
+gluShaderProgram.ProgramSources.prototype.add = function(item) {
+ var type = undefined;
+ if (typeof(item.getContainerType) == 'function') {
+ type = item.getContainerType();
+ if (
+ typeof(type) != 'number' ||
+ type < gluShaderProgram.containerTypes.ATTACHABLE_BEGIN ||
+ type >= gluShaderProgram.containerTypes.ATTACHABLE_END
+ ) {
+ type = undefined;
+ }
+ }
+
+ switch (type) {
+ case gluShaderProgram.containerTypes.ATTRIB_LOCATION_BINDING:
+ this.attribLocationBindings.push(item);
+ break;
+
+ case gluShaderProgram.containerTypes.TRANSFORM_FEEDBACK_MODE:
+ this.transformFeedbackBufferMode = item.mode;
+ break;
+
+ case gluShaderProgram.containerTypes.TRANSFORM_FEEDBACK_VARYING:
+ this.transformFeedbackVaryings.push(item.name);
+ break;
+
+ case gluShaderProgram.containerTypes.TRANSFORM_FEEDBACK_VARYINGS:
+ this.transformFeedbackVaryings = this.transformFeedbackVaryings.concat(item.array);
+ break;
+
+ case gluShaderProgram.containerTypes.SHADER_SOURCE:
+ this.sources.push(new gluShaderProgram.ShaderInfo(item.shaderType, item.source));
+ break;
+
+ case gluShaderProgram.containerTypes.PROGRAM_SEPARABLE:
+ this.separable = item.separable;
+ break;
+
+ default:
+ throw new Error('Type \"' + type + '\" cannot be added to gluShaderProgram.ProgramSources.');
+ break;
+ }
+
+ return this;
+};
+
+/**
+ * //! Helper for constructing vertex-fragment source pair.
+ * @param {string} vertexSrc
+ * @param {string} fragmentSrc
+ * @return {gluShaderProgram.ProgramSources}
+ */
+gluShaderProgram.makeVtxFragSources = function(vertexSrc, fragmentSrc) {
+ /** @type  {gluShaderProgram.ProgramSources} */ var sources = new gluShaderProgram.ProgramSources();
+ sources.sources.push(gluShaderProgram.genVertexSource(vertexSrc));
+ sources.sources.push(gluShaderProgram.genFragmentSource(fragmentSrc));
+ return sources;
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderUtil.js
new file mode 100644
index 0000000000..1604dbc613
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluShaderUtil.js
@@ -0,0 +1,795 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('framework.opengl.gluShaderUtil');
+goog.require('framework.delibs.debase.deMath');
+
+goog.scope(function() {
+
+var gluShaderUtil = framework.opengl.gluShaderUtil;
+var deMath = framework.delibs.debase.deMath;
+
+/**
+ * ShadingLanguageVersion
+ * @enum
+ */
+gluShaderUtil.GLSLVersion = {
+ V100_ES: 0, //!< GLSL ES 1.0
+ V300_ES: 1 //!< GLSL ES 3.0
+};
+
+/**
+ * gluShaderUtil.glslVersionUsesInOutQualifiers
+ * @param {gluShaderUtil.GLSLVersion} version
+ * @return {boolean}
+ */
+gluShaderUtil.glslVersionUsesInOutQualifiers = function(version) {
+ return version == gluShaderUtil.GLSLVersion.V300_ES;
+};
+
+/**
+ * gluShaderUtil.isGLSLVersionSupported
+ * @param {WebGL2RenderingContext|WebGLRenderingContextBase} ctx
+ * @param {gluShaderUtil.GLSLVersion} version
+ * @return {boolean}
+ */
+gluShaderUtil.isGLSLVersionSupported = function(ctx, version) {
+ return version <= gluShaderUtil.getGLSLVersion(ctx);
+};
+
+/**
+ * gluShaderUtil.getGLSLVersion - Returns a gluShaderUtil.GLSLVersion based on a given webgl context.
+ * @param {WebGL2RenderingContext|WebGLRenderingContextBase} gl
+ * @return {gluShaderUtil.GLSLVersion}
+ */
+gluShaderUtil.getGLSLVersion = function(gl) {
+ var glslversion = gl.getParameter(gl.SHADING_LANGUAGE_VERSION);
+
+ // TODO: Versions are not yet well implemented... Firefox returns GLSL ES 1.0 in some cases,
+ // and Chromium returns GLSL ES 2.0 in some cases. Returning the right version for
+ // testing.
+ // return gluShaderUtil.GLSLVersion.V300_ES;
+
+ if (glslversion.indexOf('WebGL GLSL ES 1.0') != -1) return gluShaderUtil.GLSLVersion.V100_ES;
+ if (glslversion.indexOf('WebGL GLSL ES 3.0') != -1) return gluShaderUtil.GLSLVersion.V300_ES;
+
+ throw new Error('Invalid WebGL version');
+};
+
+/**
+ * gluShaderUtil.getGLSLVersionDeclaration - Returns a string declaration for the glsl version in a shader.
+ * @param {gluShaderUtil.GLSLVersion} version
+ * @return {string}
+ */
+gluShaderUtil.getGLSLVersionDeclaration = function(version) {
+ /** @type {Array<string>} */ var s_decl =
+ [
+ '#version 100',
+ '#version 300 es'
+ ];
+
+ if (version > s_decl.length - 1)
+ throw new Error('Unsupported GLSL version.');
+
+ return s_decl[version];
+};
+
+/**
+ * gluShaderUtil.getGLSLVersionString - Returns the same thing as
+ * getGLSLVersionDeclaration() but without the substring '#version'
+ * @param {gluShaderUtil.GLSLVersion} version
+ * @return {string}
+ */
+gluShaderUtil.getGLSLVersionString = function(version) {
+ /** @type {Array<string>} */ var s_decl =
+ [
+ '100',
+ '300 es'
+ ];
+
+ if (version > s_decl.length - 1)
+ throw new Error('Unsupported GLSL version.');
+
+ return s_decl[version];
+};
+
+/**
+ * @enum
+ */
+gluShaderUtil.precision = {
+ PRECISION_LOWP: 0,
+ PRECISION_MEDIUMP: 1,
+ PRECISION_HIGHP: 2
+};
+
+gluShaderUtil.getPrecisionName = function(prec) {
+ var s_names = [
+ 'lowp',
+ 'mediump',
+ 'highp'
+ ];
+
+ return s_names[prec];
+};
+
+/**
+ * The Type constants
+ * @enum {number}
+ */
+gluShaderUtil.DataType = {
+ INVALID: 0,
+
+ FLOAT: 1,
+ FLOAT_VEC2: 2,
+ FLOAT_VEC3: 3,
+ FLOAT_VEC4: 4,
+ FLOAT_MAT2: 5,
+ FLOAT_MAT2X3: 6,
+ FLOAT_MAT2X4: 7,
+ FLOAT_MAT3X2: 8,
+ FLOAT_MAT3: 9,
+ FLOAT_MAT3X4: 10,
+ FLOAT_MAT4X2: 11,
+ FLOAT_MAT4X3: 12,
+ FLOAT_MAT4: 13,
+
+ INT: 14,
+ INT_VEC2: 15,
+ INT_VEC3: 16,
+ INT_VEC4: 17,
+
+ UINT: 18,
+ UINT_VEC2: 19,
+ UINT_VEC3: 20,
+ UINT_VEC4: 21,
+
+ BOOL: 22,
+ BOOL_VEC2: 23,
+ BOOL_VEC3: 24,
+ BOOL_VEC4: 25,
+
+ SAMPLER_2D: 26,
+ SAMPLER_CUBE: 27,
+ SAMPLER_2D_ARRAY: 28,
+ SAMPLER_3D: 29,
+
+ SAMPLER_2D_SHADOW: 30,
+ SAMPLER_CUBE_SHADOW: 31,
+ SAMPLER_2D_ARRAY_SHADOW: 32,
+
+ INT_SAMPLER_2D: 33,
+ INT_SAMPLER_CUBE: 34,
+ INT_SAMPLER_2D_ARRAY: 35,
+ INT_SAMPLER_3D: 36,
+
+ UINT_SAMPLER_2D: 37,
+ UINT_SAMPLER_CUBE: 38,
+ UINT_SAMPLER_2D_ARRAY: 39,
+ UINT_SAMPLER_3D: 40
+};
+
+/**
+ * Returns type of float scalars
+ * @param {gluShaderUtil.DataType} dataType
+ * @return {string} type of float scalar
+ */
+gluShaderUtil.getDataTypeFloatScalars = function(dataType) {
+
+ switch (dataType) {
+ case gluShaderUtil.DataType.FLOAT: return 'float';
+ case gluShaderUtil.DataType.FLOAT_VEC2: return 'vec2';
+ case gluShaderUtil.DataType.FLOAT_VEC3: return 'vec3';
+ case gluShaderUtil.DataType.FLOAT_VEC4: return 'vec4';
+ case gluShaderUtil.DataType.FLOAT_MAT2: return 'mat2';
+ case gluShaderUtil.DataType.FLOAT_MAT2X3: return 'mat2x3';
+ case gluShaderUtil.DataType.FLOAT_MAT2X4: return 'mat2x4';
+ case gluShaderUtil.DataType.FLOAT_MAT3X2: return 'mat3x2';
+ case gluShaderUtil.DataType.FLOAT_MAT3: return 'mat3';
+ case gluShaderUtil.DataType.FLOAT_MAT3X4: return 'mat3x4';
+ case gluShaderUtil.DataType.FLOAT_MAT4X2: return 'mat4x2';
+ case gluShaderUtil.DataType.FLOAT_MAT4X3: return 'mat4x3';
+ case gluShaderUtil.DataType.FLOAT_MAT4: return 'mat4';
+ case gluShaderUtil.DataType.INT: return 'float';
+ case gluShaderUtil.DataType.INT_VEC2: return 'vec2';
+ case gluShaderUtil.DataType.INT_VEC3: return 'vec3';
+ case gluShaderUtil.DataType.INT_VEC4: return 'vec4';
+ case gluShaderUtil.DataType.UINT: return 'float';
+ case gluShaderUtil.DataType.UINT_VEC2: return 'vec2';
+ case gluShaderUtil.DataType.UINT_VEC3: return 'vec3';
+ case gluShaderUtil.DataType.UINT_VEC4: return 'vec4';
+ case gluShaderUtil.DataType.BOOL: return 'float';
+ case gluShaderUtil.DataType.BOOL_VEC2: return 'vec2';
+ case gluShaderUtil.DataType.BOOL_VEC3: return 'vec3';
+ case gluShaderUtil.DataType.BOOL_VEC4: return 'vec4';
+ }
+ throw Error('Unrecognized dataType ' + dataType);
+};
+
+/**
+ * gluShaderUtil.getDataTypeVector
+ * @param {gluShaderUtil.DataType} scalarType
+ * @param {number} size
+ * @return {gluShaderUtil.DataType}
+ */
+gluShaderUtil.getDataTypeVector = function(scalarType, size) {
+ var floats = [gluShaderUtil.DataType.FLOAT,
+ gluShaderUtil.DataType.FLOAT_VEC2,
+ gluShaderUtil.DataType.FLOAT_VEC3,
+ gluShaderUtil.DataType.FLOAT_VEC4];
+ var ints = [gluShaderUtil.DataType.INT,
+ gluShaderUtil.DataType.INT_VEC2,
+ gluShaderUtil.DataType.INT_VEC3,
+ gluShaderUtil.DataType.INT_VEC4];
+ var uints = [gluShaderUtil.DataType.UINT,
+ gluShaderUtil.DataType.UINT_VEC2,
+ gluShaderUtil.DataType.UINT_VEC3,
+ gluShaderUtil.DataType.UINT_VEC4];
+ var bools = [gluShaderUtil.DataType.BOOL,
+ gluShaderUtil.DataType.BOOL_VEC2,
+ gluShaderUtil.DataType.BOOL_VEC3,
+ gluShaderUtil.DataType.BOOL_VEC4];
+
+ switch (scalarType) {
+ case gluShaderUtil.DataType.FLOAT: return floats[size - 1];
+ case gluShaderUtil.DataType.INT: return ints[size - 1];
+ case gluShaderUtil.DataType.UINT: return uints[size - 1];
+ case gluShaderUtil.DataType.BOOL: return bools[size - 1];
+ default:
+ throw new Error('Scalar type is not a vectoe:' + scalarType);
+ }
+};
+
+/**
+ * gluShaderUtil.getDataTypeFloatVec
+ * @param {number} vecSize
+ * @return {gluShaderUtil.DataType}
+ */
+gluShaderUtil.getDataTypeFloatVec = function(vecSize) {
+ return gluShaderUtil.getDataTypeVector(gluShaderUtil.DataType.FLOAT, vecSize);
+};
+
+/**
+ * gluShaderUtil.isDataTypeBoolOrBVec
+ * @param {gluShaderUtil.DataType} dataType
+ * @return {boolean}
+ */
+gluShaderUtil.isDataTypeBoolOrBVec = function(dataType) {
+ return (dataType >= gluShaderUtil.DataType.BOOL) && (dataType <= gluShaderUtil.DataType.BOOL_VEC4);
+};
+
+/**
+ * Returns type of scalar
+ * @param {gluShaderUtil.DataType} dataType shader
+ * @return {string} type of scalar type
+ */
+gluShaderUtil.getDataTypeScalarType = function(dataType) {
+ switch (dataType) {
+ case gluShaderUtil.DataType.FLOAT: return 'float';
+ case gluShaderUtil.DataType.FLOAT_VEC2: return 'float';
+ case gluShaderUtil.DataType.FLOAT_VEC3: return 'float';
+ case gluShaderUtil.DataType.FLOAT_VEC4: return 'float';
+ case gluShaderUtil.DataType.FLOAT_MAT2: return 'float';
+ case gluShaderUtil.DataType.FLOAT_MAT2X3: return 'float';
+ case gluShaderUtil.DataType.FLOAT_MAT2X4: return 'float';
+ case gluShaderUtil.DataType.FLOAT_MAT3X2: return 'float';
+ case gluShaderUtil.DataType.FLOAT_MAT3: return 'float';
+ case gluShaderUtil.DataType.FLOAT_MAT3X4: return 'float';
+ case gluShaderUtil.DataType.FLOAT_MAT4X2: return 'float';
+ case gluShaderUtil.DataType.FLOAT_MAT4X3: return 'float';
+ case gluShaderUtil.DataType.FLOAT_MAT4: return 'float';
+ case gluShaderUtil.DataType.INT: return 'int';
+ case gluShaderUtil.DataType.INT_VEC2: return 'int';
+ case gluShaderUtil.DataType.INT_VEC3: return 'int';
+ case gluShaderUtil.DataType.INT_VEC4: return 'int';
+ case gluShaderUtil.DataType.UINT: return 'uint';
+ case gluShaderUtil.DataType.UINT_VEC2: return 'uint';
+ case gluShaderUtil.DataType.UINT_VEC3: return 'uint';
+ case gluShaderUtil.DataType.UINT_VEC4: return 'uint';
+ case gluShaderUtil.DataType.BOOL: return 'bool';
+ case gluShaderUtil.DataType.BOOL_VEC2: return 'bool';
+ case gluShaderUtil.DataType.BOOL_VEC3: return 'bool';
+ case gluShaderUtil.DataType.BOOL_VEC4: return 'bool';
+ case gluShaderUtil.DataType.SAMPLER_2D: return 'sampler2D';
+ case gluShaderUtil.DataType.SAMPLER_CUBE: return 'samplerCube';
+ case gluShaderUtil.DataType.SAMPLER_2D_ARRAY: return 'sampler2DArray';
+ case gluShaderUtil.DataType.SAMPLER_3D: return 'sampler3D';
+ case gluShaderUtil.DataType.SAMPLER_2D_SHADOW: return 'sampler2DShadow';
+ case gluShaderUtil.DataType.SAMPLER_CUBE_SHADOW: return 'samplerCubeShadow';
+ case gluShaderUtil.DataType.SAMPLER_2D_ARRAY_SHADOW: return 'sampler2DArrayShadow';
+ case gluShaderUtil.DataType.INT_SAMPLER_2D: return 'isampler2D';
+ case gluShaderUtil.DataType.INT_SAMPLER_CUBE: return 'isamplerCube';
+ case gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY: return 'isampler2DArray';
+ case gluShaderUtil.DataType.INT_SAMPLER_3D: return 'isampler3D';
+ case gluShaderUtil.DataType.UINT_SAMPLER_2D: return 'usampler2D';
+ case gluShaderUtil.DataType.UINT_SAMPLER_CUBE: return 'usamplerCube';
+ case gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY: return 'usampler2DArray';
+ case gluShaderUtil.DataType.UINT_SAMPLER_3D: return 'usampler3D';
+ }
+ throw new Error('Unrecognized datatype:' + dataType);
+};
+
+/**
+ * Returns type of scalar
+ * @param {?gluShaderUtil.DataType} dataType shader
+ * @return {gluShaderUtil.DataType} type of scalar type
+ */
+gluShaderUtil.getDataTypeScalarTypeAsDataType = function(dataType) {
+ switch (dataType) {
+ case gluShaderUtil.DataType.FLOAT: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.FLOAT_VEC2: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.FLOAT_VEC3: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.FLOAT_VEC4: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.FLOAT_MAT2: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.FLOAT_MAT2X3: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.FLOAT_MAT2X4: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.FLOAT_MAT3X2: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.FLOAT_MAT3: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.FLOAT_MAT3X4: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.FLOAT_MAT4X2: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.FLOAT_MAT4X3: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.FLOAT_MAT4: return gluShaderUtil.DataType.FLOAT;
+ case gluShaderUtil.DataType.INT: return gluShaderUtil.DataType.INT;
+ case gluShaderUtil.DataType.INT_VEC2: return gluShaderUtil.DataType.INT;
+ case gluShaderUtil.DataType.INT_VEC3: return gluShaderUtil.DataType.INT;
+ case gluShaderUtil.DataType.INT_VEC4: return gluShaderUtil.DataType.INT;
+ case gluShaderUtil.DataType.UINT: return gluShaderUtil.DataType.UINT;
+ case gluShaderUtil.DataType.UINT_VEC2: return gluShaderUtil.DataType.UINT;
+ case gluShaderUtil.DataType.UINT_VEC3: return gluShaderUtil.DataType.UINT;
+ case gluShaderUtil.DataType.UINT_VEC4: return gluShaderUtil.DataType.UINT;
+ case gluShaderUtil.DataType.BOOL: return gluShaderUtil.DataType.BOOL;
+ case gluShaderUtil.DataType.BOOL_VEC2: return gluShaderUtil.DataType.BOOL;
+ case gluShaderUtil.DataType.BOOL_VEC3: return gluShaderUtil.DataType.BOOL;
+ case gluShaderUtil.DataType.BOOL_VEC4: return gluShaderUtil.DataType.BOOL;
+ case gluShaderUtil.DataType.SAMPLER_2D:
+ case gluShaderUtil.DataType.SAMPLER_CUBE:
+ case gluShaderUtil.DataType.SAMPLER_2D_ARRAY:
+ case gluShaderUtil.DataType.SAMPLER_3D:
+ case gluShaderUtil.DataType.SAMPLER_2D_SHADOW:
+ case gluShaderUtil.DataType.SAMPLER_CUBE_SHADOW:
+ case gluShaderUtil.DataType.SAMPLER_2D_ARRAY_SHADOW:
+ case gluShaderUtil.DataType.INT_SAMPLER_2D:
+ case gluShaderUtil.DataType.INT_SAMPLER_CUBE:
+ case gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY:
+ case gluShaderUtil.DataType.INT_SAMPLER_3D:
+ case gluShaderUtil.DataType.UINT_SAMPLER_2D:
+ case gluShaderUtil.DataType.UINT_SAMPLER_CUBE:
+ case gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY:
+ case gluShaderUtil.DataType.UINT_SAMPLER_3D:
+ return dataType;
+ }
+ throw Error('Unrecognized dataType ' + dataType);
+};
+
+/**
+ * Checks if dataType is integer or vectors of integers
+ * @param {gluShaderUtil.DataType} dataType shader
+ * @return {boolean} Is dataType integer or integer vector
+ */
+gluShaderUtil.isDataTypeIntOrIVec = function(dataType) {
+ /** @type {boolean} */ var retVal = false;
+ switch (dataType) {
+ case gluShaderUtil.DataType.INT:
+ case gluShaderUtil.DataType.INT_VEC2:
+ case gluShaderUtil.DataType.INT_VEC3:
+ case gluShaderUtil.DataType.INT_VEC4:
+ retVal = true;
+ }
+
+ return retVal;
+};
+
+/**
+ * Checks if dataType is unsigned integer or vectors of unsigned integers
+ * @param {gluShaderUtil.DataType} dataType shader
+ * @return {boolean} Is dataType unsigned integer or unsigned integer vector
+ */
+gluShaderUtil.isDataTypeUintOrUVec = function(dataType) {
+ /** @type {boolean} */ var retVal = false;
+ switch (dataType) {
+ case gluShaderUtil.DataType.UINT:
+ case gluShaderUtil.DataType.UINT_VEC2:
+ case gluShaderUtil.DataType.UINT_VEC3:
+ case gluShaderUtil.DataType.UINT_VEC4:
+ retVal = true;
+ }
+
+ return retVal;
+};
+
+/**
+* Returns type of scalar size
+* @param {gluShaderUtil.DataType} dataType shader
+* @return {number} with size of the type of scalar
+*/
+gluShaderUtil.getDataTypeScalarSize = function(dataType) {
+ switch (dataType) {
+ case gluShaderUtil.DataType.FLOAT: return 1;
+ case gluShaderUtil.DataType.FLOAT_VEC2: return 2;
+ case gluShaderUtil.DataType.FLOAT_VEC3: return 3;
+ case gluShaderUtil.DataType.FLOAT_VEC4: return 4;
+ case gluShaderUtil.DataType.FLOAT_MAT2: return 4;
+ case gluShaderUtil.DataType.FLOAT_MAT2X3: return 6;
+ case gluShaderUtil.DataType.FLOAT_MAT2X4: return 8;
+ case gluShaderUtil.DataType.FLOAT_MAT3X2: return 6;
+ case gluShaderUtil.DataType.FLOAT_MAT3: return 9;
+ case gluShaderUtil.DataType.FLOAT_MAT3X4: return 12;
+ case gluShaderUtil.DataType.FLOAT_MAT4X2: return 8;
+ case gluShaderUtil.DataType.FLOAT_MAT4X3: return 12;
+ case gluShaderUtil.DataType.FLOAT_MAT4: return 16;
+ case gluShaderUtil.DataType.INT: return 1;
+ case gluShaderUtil.DataType.INT_VEC2: return 2;
+ case gluShaderUtil.DataType.INT_VEC3: return 3;
+ case gluShaderUtil.DataType.INT_VEC4: return 4;
+ case gluShaderUtil.DataType.UINT: return 1;
+ case gluShaderUtil.DataType.UINT_VEC2: return 2;
+ case gluShaderUtil.DataType.UINT_VEC3: return 3;
+ case gluShaderUtil.DataType.UINT_VEC4: return 4;
+ case gluShaderUtil.DataType.BOOL: return 1;
+ case gluShaderUtil.DataType.BOOL_VEC2: return 2;
+ case gluShaderUtil.DataType.BOOL_VEC3: return 3;
+ case gluShaderUtil.DataType.BOOL_VEC4: return 4;
+ case gluShaderUtil.DataType.SAMPLER_2D: return 1;
+ case gluShaderUtil.DataType.SAMPLER_CUBE: return 1;
+ case gluShaderUtil.DataType.SAMPLER_2D_ARRAY: return 1;
+ case gluShaderUtil.DataType.SAMPLER_3D: return 1;
+ case gluShaderUtil.DataType.SAMPLER_2D_SHADOW: return 1;
+ case gluShaderUtil.DataType.SAMPLER_CUBE_SHADOW: return 1;
+ case gluShaderUtil.DataType.SAMPLER_2D_ARRAY_SHADOW: return 1;
+ case gluShaderUtil.DataType.INT_SAMPLER_2D: return 1;
+ case gluShaderUtil.DataType.INT_SAMPLER_CUBE: return 1;
+ case gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY: return 1;
+ case gluShaderUtil.DataType.INT_SAMPLER_3D: return 1;
+ case gluShaderUtil.DataType.UINT_SAMPLER_2D: return 1;
+ case gluShaderUtil.DataType.UINT_SAMPLER_CUBE: return 1;
+ case gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY: return 1;
+ case gluShaderUtil.DataType.UINT_SAMPLER_3D: return 1;
+ }
+ throw Error('Unrecognized dataType ' + dataType);
+};
+
+/**
+ * Checks if dataType is float or vector
+ * @param {?gluShaderUtil.DataType} dataType shader
+ * @return {boolean} Is dataType float or vector
+ */
+gluShaderUtil.isDataTypeFloatOrVec = function(dataType) {
+ switch (dataType) {
+ case gluShaderUtil.DataType.FLOAT:
+ case gluShaderUtil.DataType.FLOAT_VEC2:
+ case gluShaderUtil.DataType.FLOAT_VEC3:
+ case gluShaderUtil.DataType.FLOAT_VEC4:
+ return true;
+ }
+ return false;
+};
+
+/**
+ * Checks if dataType is a matrix
+ * @param {gluShaderUtil.DataType} dataType shader
+ * @return {boolean} Is dataType matrix or not
+ */
+gluShaderUtil.isDataTypeMatrix = function(dataType) {
+ switch (dataType) {
+ case gluShaderUtil.DataType.FLOAT_MAT2:
+ case gluShaderUtil.DataType.FLOAT_MAT2X3:
+ case gluShaderUtil.DataType.FLOAT_MAT2X4:
+ case gluShaderUtil.DataType.FLOAT_MAT3X2:
+ case gluShaderUtil.DataType.FLOAT_MAT3:
+ case gluShaderUtil.DataType.FLOAT_MAT3X4:
+ case gluShaderUtil.DataType.FLOAT_MAT4X2:
+ case gluShaderUtil.DataType.FLOAT_MAT4X3:
+ case gluShaderUtil.DataType.FLOAT_MAT4:
+ return true;
+ }
+ return false;
+};
+
+/**
+ * Checks if dataType is a vector
+ * @param {gluShaderUtil.DataType} dataType shader
+ * @return {boolean} Is dataType vector or not
+ */
+gluShaderUtil.isDataTypeScalar = function(dataType) {
+ switch (dataType) {
+ case gluShaderUtil.DataType.FLOAT:
+ case gluShaderUtil.DataType.INT:
+ case gluShaderUtil.DataType.UINT:
+ case gluShaderUtil.DataType.BOOL:
+ return true;
+ }
+ return false;
+};
+
+/**
+ * Checks if dataType is a vector
+ * @param {gluShaderUtil.DataType} dataType shader
+ * @return {boolean} Is dataType vector or not
+ */
+gluShaderUtil.isDataTypeVector = function(dataType) {
+ switch (dataType) {
+ case gluShaderUtil.DataType.FLOAT_VEC2:
+ case gluShaderUtil.DataType.FLOAT_VEC3:
+ case gluShaderUtil.DataType.FLOAT_VEC4:
+ case gluShaderUtil.DataType.INT_VEC2:
+ case gluShaderUtil.DataType.INT_VEC3:
+ case gluShaderUtil.DataType.INT_VEC4:
+ case gluShaderUtil.DataType.UINT_VEC2:
+ case gluShaderUtil.DataType.UINT_VEC3:
+ case gluShaderUtil.DataType.UINT_VEC4:
+ case gluShaderUtil.DataType.BOOL_VEC2:
+ case gluShaderUtil.DataType.BOOL_VEC3:
+ case gluShaderUtil.DataType.BOOL_VEC4:
+ return true;
+ }
+ return false;
+};
+
+/**
+ * Checks if dataType is a vector or a scalar type
+ * @param {gluShaderUtil.DataType} dataType shader
+ * @return {boolean} Is dataType vector or scalar or not
+ */
+gluShaderUtil.isDataTypeScalarOrVector = function(dataType) {
+ switch (dataType) {
+ case gluShaderUtil.DataType.FLOAT:
+ case gluShaderUtil.DataType.FLOAT_VEC2:
+ case gluShaderUtil.DataType.FLOAT_VEC3:
+ case gluShaderUtil.DataType.FLOAT_VEC4:
+ case gluShaderUtil.DataType.INT:
+ case gluShaderUtil.DataType.INT_VEC2:
+ case gluShaderUtil.DataType.INT_VEC3:
+ case gluShaderUtil.DataType.INT_VEC4:
+ case gluShaderUtil.DataType.UINT:
+ case gluShaderUtil.DataType.UINT_VEC2:
+ case gluShaderUtil.DataType.UINT_VEC3:
+ case gluShaderUtil.DataType.UINT_VEC4:
+ case gluShaderUtil.DataType.BOOL:
+ case gluShaderUtil.DataType.BOOL_VEC2:
+ case gluShaderUtil.DataType.BOOL_VEC3:
+ case gluShaderUtil.DataType.BOOL_VEC4:
+ return true;
+ }
+ return false;
+};
+
+/**
+ * Checks if dataType is a sampler
+ * @param {gluShaderUtil.DataType} dataType shader
+ * @return {boolean} Is dataType vector or scalar or not
+ */
+gluShaderUtil.isDataTypeSampler = function(dataType) {
+ return (dataType >= gluShaderUtil.DataType.SAMPLER_2D) && (dataType <= gluShaderUtil.DataType.UINT_SAMPLER_3D);
+};
+
+/**
+ * Returns a gluShaderUtil.DataType based on given rows and columns
+ * @param {number} numCols
+ * @param {number} numRows
+ * @return {gluShaderUtil.DataType}
+ */
+gluShaderUtil.getDataTypeMatrix = function(numCols, numRows) {
+ if (!(deMath.deInRange32(numCols, 2, 4) && deMath.deInRange32(numRows, 2, 4)))
+ throw new Error('Out of bounds: (' + numCols + ',' + numRows + ')');
+
+ var size = numCols.toString() + 'x' + numRows.toString();
+ var datatypes = {
+ '2x2': gluShaderUtil.DataType.FLOAT_MAT2,
+ '2x3': gluShaderUtil.DataType.FLOAT_MAT2X3,
+ '2x4': gluShaderUtil.DataType.FLOAT_MAT2X4,
+ '3x2': gluShaderUtil.DataType.FLOAT_MAT3X2,
+ '3x3': gluShaderUtil.DataType.FLOAT_MAT3,
+ '3x4': gluShaderUtil.DataType.FLOAT_MAT3X4,
+ '4x2': gluShaderUtil.DataType.FLOAT_MAT4X2,
+ '4x3': gluShaderUtil.DataType.FLOAT_MAT4X3,
+ '4x4': gluShaderUtil.DataType.FLOAT_MAT4
+ };
+ return datatypes[size];
+};
+
+/**
+* Returns number of rows of a gluShaderUtil.DataType Matrix
+* @param {gluShaderUtil.DataType} dataType shader
+* @return {number} with number of rows depending on gluShaderUtil.DataType Matrix
+*/
+gluShaderUtil.getDataTypeMatrixNumRows = function(dataType) {
+ switch (dataType) {
+ case gluShaderUtil.DataType.FLOAT_MAT2: return 2;
+ case gluShaderUtil.DataType.FLOAT_MAT2X3: return 3;
+ case gluShaderUtil.DataType.FLOAT_MAT2X4: return 4;
+ case gluShaderUtil.DataType.FLOAT_MAT3X2: return 2;
+ case gluShaderUtil.DataType.FLOAT_MAT3: return 3;
+ case gluShaderUtil.DataType.FLOAT_MAT3X4: return 4;
+ case gluShaderUtil.DataType.FLOAT_MAT4X2: return 2;
+ case gluShaderUtil.DataType.FLOAT_MAT4X3: return 3;
+ case gluShaderUtil.DataType.FLOAT_MAT4: return 4;
+ }
+ throw Error('Unrecognized dataType ' + dataType);
+};
+
+/**
+* Returns number of columns of a gluShaderUtil.DataType Matrix
+* @param {gluShaderUtil.DataType} dataType shader
+* @return {number} with number of columns depending on gluShaderUtil.DataType Matrix
+*/
+gluShaderUtil.getDataTypeMatrixNumColumns = function(dataType) {
+ switch (dataType) {
+ case gluShaderUtil.DataType.FLOAT_MAT2: return 2;
+ case gluShaderUtil.DataType.FLOAT_MAT2X3: return 2;
+ case gluShaderUtil.DataType.FLOAT_MAT2X4: return 2;
+ case gluShaderUtil.DataType.FLOAT_MAT3X2: return 3;
+ case gluShaderUtil.DataType.FLOAT_MAT3: return 3;
+ case gluShaderUtil.DataType.FLOAT_MAT3X4: return 3;
+ case gluShaderUtil.DataType.FLOAT_MAT4X2: return 4;
+ case gluShaderUtil.DataType.FLOAT_MAT4X3: return 4;
+ case gluShaderUtil.DataType.FLOAT_MAT4: return 4;
+ }
+ throw Error('Unrecognized dataType ' + dataType);
+};
+
+/**
+ * @param {gluShaderUtil.DataType} dataType
+ * @return {number}
+ */
+gluShaderUtil.getDataTypeNumLocations = function(dataType) {
+ if (gluShaderUtil.isDataTypeScalarOrVector(dataType))
+ return 1;
+ else if (gluShaderUtil.isDataTypeMatrix(dataType))
+ return gluShaderUtil.getDataTypeMatrixNumColumns(dataType);
+ throw Error('Unrecognized dataType ' + dataType);
+};
+
+/**
+ * @param {gluShaderUtil.DataType} dataType
+ * @return {number}
+ */
+gluShaderUtil.getDataTypeNumComponents = function(dataType) {
+ if (gluShaderUtil.isDataTypeScalarOrVector(dataType))
+ return gluShaderUtil.getDataTypeScalarSize(dataType);
+ else if (gluShaderUtil.isDataTypeMatrix(dataType))
+ return gluShaderUtil.getDataTypeMatrixNumRows(dataType);
+
+ throw Error('Unrecognized dataType ' + dataType);
+};
+
+/**
+ * Returns name of the dataType
+ * @param {?gluShaderUtil.DataType} dataType shader
+ * @return {string} dataType name
+ */
+gluShaderUtil.getDataTypeName = function(dataType) {
+ switch (dataType) {
+ case gluShaderUtil.DataType.INVALID: return 'invalid';
+
+ case gluShaderUtil.DataType.FLOAT: return 'float';
+ case gluShaderUtil.DataType.FLOAT_VEC2: return 'vec2';
+ case gluShaderUtil.DataType.FLOAT_VEC3: return 'vec3';
+ case gluShaderUtil.DataType.FLOAT_VEC4: return 'vec4';
+ case gluShaderUtil.DataType.FLOAT_MAT2: return 'mat2';
+ case gluShaderUtil.DataType.FLOAT_MAT2X3: return 'mat2x3';
+ case gluShaderUtil.DataType.FLOAT_MAT2X4: return 'mat2x4';
+ case gluShaderUtil.DataType.FLOAT_MAT3X2: return 'mat3x2';
+ case gluShaderUtil.DataType.FLOAT_MAT3: return 'mat3';
+ case gluShaderUtil.DataType.FLOAT_MAT3X4: return 'mat3x4';
+ case gluShaderUtil.DataType.FLOAT_MAT4X2: return 'mat4x2';
+ case gluShaderUtil.DataType.FLOAT_MAT4X3: return 'mat4x3';
+ case gluShaderUtil.DataType.FLOAT_MAT4: return 'mat4';
+
+ case gluShaderUtil.DataType.INT: return 'int';
+ case gluShaderUtil.DataType.INT_VEC2: return 'ivec2';
+ case gluShaderUtil.DataType.INT_VEC3: return 'ivec3';
+ case gluShaderUtil.DataType.INT_VEC4: return 'ivec4';
+
+ case gluShaderUtil.DataType.UINT: return 'uint';
+ case gluShaderUtil.DataType.UINT_VEC2: return 'uvec2';
+ case gluShaderUtil.DataType.UINT_VEC3: return 'uvec3';
+ case gluShaderUtil.DataType.UINT_VEC4: return 'uvec4';
+
+ case gluShaderUtil.DataType.BOOL: return 'bool';
+ case gluShaderUtil.DataType.BOOL_VEC2: return 'bvec2';
+ case gluShaderUtil.DataType.BOOL_VEC3: return 'bvec3';
+ case gluShaderUtil.DataType.BOOL_VEC4: return 'bvec4';
+
+ case gluShaderUtil.DataType.SAMPLER_2D: return 'sampler2D';
+ case gluShaderUtil.DataType.SAMPLER_CUBE: return 'samplerCube';
+ case gluShaderUtil.DataType.SAMPLER_2D_ARRAY: return 'sampler2DArray';
+ case gluShaderUtil.DataType.SAMPLER_3D: return 'sampler3D';
+
+ case gluShaderUtil.DataType.SAMPLER_2D_SHADOW: return 'sampler2DShadow';
+ case gluShaderUtil.DataType.SAMPLER_CUBE_SHADOW: return 'samplerCubeShadow';
+ case gluShaderUtil.DataType.SAMPLER_2D_ARRAY_SHADOW: return 'sampler2DArrayShadow';
+
+ case gluShaderUtil.DataType.INT_SAMPLER_2D: return 'isampler2D';
+ case gluShaderUtil.DataType.INT_SAMPLER_CUBE: return 'isamplerCube';
+ case gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY: return 'isampler2DArray';
+ case gluShaderUtil.DataType.INT_SAMPLER_3D: return 'isampler3D';
+
+ case gluShaderUtil.DataType.UINT_SAMPLER_2D: return 'usampler2D';
+ case gluShaderUtil.DataType.UINT_SAMPLER_CUBE: return 'usamplerCube';
+ case gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY: return 'usampler2DArray';
+ case gluShaderUtil.DataType.UINT_SAMPLER_3D: return 'usampler3D';
+ }
+ throw Error('Unrecognized dataType ' + dataType);
+};
+
+/**
+ * Returns the gluShaderUtil.DataType from the GL type
+ * @param {number} glType
+ * @return {gluShaderUtil.DataType}
+ */
+gluShaderUtil.getDataTypeFromGLType = function(glType) {
+ switch (glType) {
+ case gl.FLOAT: return gluShaderUtil.DataType.FLOAT;
+ case gl.FLOAT_VEC2: return gluShaderUtil.DataType.FLOAT_VEC2;
+ case gl.FLOAT_VEC3: return gluShaderUtil.DataType.FLOAT_VEC3;
+ case gl.FLOAT_VEC4: return gluShaderUtil.DataType.FLOAT_VEC4;
+
+ case gl.FLOAT_MAT2: return gluShaderUtil.DataType.FLOAT_MAT2;
+ case gl.FLOAT_MAT2x3: return gluShaderUtil.DataType.FLOAT_MAT2X3;
+ case gl.FLOAT_MAT2x4: return gluShaderUtil.DataType.FLOAT_MAT2X4;
+
+ case gl.FLOAT_MAT3x2: return gluShaderUtil.DataType.FLOAT_MAT3X2;
+ case gl.FLOAT_MAT3: return gluShaderUtil.DataType.FLOAT_MAT3;
+ case gl.FLOAT_MAT3x4: return gluShaderUtil.DataType.FLOAT_MAT3X4;
+
+ case gl.FLOAT_MAT4x2: return gluShaderUtil.DataType.FLOAT_MAT4X2;
+ case gl.FLOAT_MAT4x3: return gluShaderUtil.DataType.FLOAT_MAT4X3;
+ case gl.FLOAT_MAT4: return gluShaderUtil.DataType.FLOAT_MAT4;
+
+ case gl.INT: return gluShaderUtil.DataType.INT;
+ case gl.INT_VEC2: return gluShaderUtil.DataType.INT_VEC2;
+ case gl.INT_VEC3: return gluShaderUtil.DataType.INT_VEC3;
+ case gl.INT_VEC4: return gluShaderUtil.DataType.INT_VEC4;
+
+ case gl.UNSIGNED_INT: return gluShaderUtil.DataType.UINT;
+ case gl.UNSIGNED_INT_VEC2: return gluShaderUtil.DataType.UINT_VEC2;
+ case gl.UNSIGNED_INT_VEC3: return gluShaderUtil.DataType.UINT_VEC3;
+ case gl.UNSIGNED_INT_VEC4: return gluShaderUtil.DataType.UINT_VEC4;
+
+ case gl.BOOL: return gluShaderUtil.DataType.BOOL;
+ case gl.BOOL_VEC2: return gluShaderUtil.DataType.BOOL_VEC2;
+ case gl.BOOL_VEC3: return gluShaderUtil.DataType.BOOL_VEC3;
+ case gl.BOOL_VEC4: return gluShaderUtil.DataType.BOOL_VEC4;
+
+ case gl.SAMPLER_2D: return gluShaderUtil.DataType.SAMPLER_2D;
+ case gl.SAMPLER_CUBE: return gluShaderUtil.DataType.SAMPLER_CUBE;
+ case gl.SAMPLER_2D_ARRAY: return gluShaderUtil.DataType.SAMPLER_2D_ARRAY;
+ case gl.SAMPLER_3D: return gluShaderUtil.DataType.SAMPLER_3D;
+
+ case gl.SAMPLER_2D_SHADOW: return gluShaderUtil.DataType.SAMPLER_2D_SHADOW;
+ case gl.SAMPLER_CUBE_SHADOW: return gluShaderUtil.DataType.SAMPLER_CUBE_SHADOW;
+ case gl.SAMPLER_2D_ARRAY_SHADOW: return gluShaderUtil.DataType.SAMPLER_2D_ARRAY_SHADOW;
+
+ case gl.INT_SAMPLER_2D: return gluShaderUtil.DataType.INT_SAMPLER_2D;
+ case gl.INT_SAMPLER_CUBE: return gluShaderUtil.DataType.INT_SAMPLER_CUBE;
+ case gl.INT_SAMPLER_2D_ARRAY: return gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY;
+ case gl.INT_SAMPLER_3D: return gluShaderUtil.DataType.INT_SAMPLER_3D;
+
+ case gl.UNSIGNED_INT_SAMPLER_2D: return gluShaderUtil.DataType.UINT_SAMPLER_2D;
+ case gl.UNSIGNED_INT_SAMPLER_CUBE: return gluShaderUtil.DataType.UINT_SAMPLER_CUBE;
+ case gl.UNSIGNED_INT_SAMPLER_2D_ARRAY: return gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY;
+ case gl.UNSIGNED_INT_SAMPLER_3D: return gluShaderUtil.DataType.UINT_SAMPLER_3D;
+
+ default:
+ throw new Error('Unrecognized GL type:' + glType);
+ }
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluStrUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluStrUtil.js
new file mode 100644
index 0000000000..b554db047a
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluStrUtil.js
@@ -0,0 +1,166 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('framework.opengl.gluStrUtil');
+
+goog.scope(function() {
+
+var gluStrUtil = framework.opengl.gluStrUtil;
+
+gluStrUtil.getPixelFormatName = function(value) {
+ switch (value) {
+ case gl.LUMINANCE: return 'gl.LUMINANCE';
+ case gl.LUMINANCE_ALPHA: return 'gl.LUMINANCE_ALPHA';
+ case gl.ALPHA: return 'gl.ALPHA';
+ case gl.RGB: return 'gl.RGB';
+ case gl.RGBA: return 'gl.RGBA';
+ case gl.RGBA4: return 'gl.RGBA4';
+ case gl.RGB5_A1: return 'gl.RGB5_A1';
+ case gl.RGB565: return 'gl.RGB565';
+ case gl.DEPTH_COMPONENT16: return 'gl.DEPTH_COMPONENT16';
+ case gl.STENCIL_INDEX8: return 'gl.STENCIL_INDEX8';
+ case gl.RG: return 'gl.RG';
+ case gl.RED: return 'gl.RED';
+ case gl.RGBA_INTEGER: return 'gl.RGBA_INTEGER';
+ case gl.RGB_INTEGER: return 'gl.RGB_INTEGER';
+ case gl.RG_INTEGER: return 'gl.RG_INTEGER';
+ case gl.RED_INTEGER: return 'gl.RED_INTEGER';
+ case gl.DEPTH_COMPONENT: return 'gl.DEPTH_COMPONENT';
+ case gl.DEPTH_STENCIL: return 'gl.DEPTH_STENCIL';
+ case gl.RGBA32F: return 'gl.RGBA32F';
+ case gl.RGBA32I: return 'gl.RGBA32I';
+ case gl.RGBA32UI: return 'gl.RGBA32UI';
+ // case gl.RGBA16: return 'gl.RGBA16';
+ // case gl.RGBA16_SNORM: return 'gl.RGBA16_SNORM';
+ case gl.RGBA16F: return 'gl.RGBA16F';
+ case gl.RGBA16I: return 'gl.RGBA16I';
+ case gl.RGBA16UI: return 'gl.RGBA16UI';
+ case gl.RGBA8: return 'gl.RGBA8';
+ case gl.RGBA8I: return 'gl.RGBA8I';
+ case gl.RGBA8UI: return 'gl.RGBA8UI';
+ case gl.SRGB8_ALPHA8: return 'gl.SRGB8_ALPHA8';
+ case gl.RGB10_A2: return 'gl.RGB10_A2';
+ case gl.RGB10_A2UI: return 'gl.RGB10_A2UI';
+ case gl.RGBA8_SNORM: return 'gl.RGBA8_SNORM';
+ case gl.RGB8: return 'gl.RGB8';
+ case gl.R11F_G11F_B10F: return 'gl.R11F_G11F_B10F';
+ case gl.RGB32F: return 'gl.RGB32F';
+ case gl.RGB32I: return 'gl.RGB32I';
+ case gl.RGB32UI: return 'gl.RGB32UI';
+ // case gl.RGB16: return 'gl.RGB16';
+ // case gl.RGB16_SNORM: return 'gl.RGB16_SNORM';
+ case gl.RGB16F: return 'gl.RGB16F';
+ case gl.RGB16I: return 'gl.RGB16I';
+ case gl.RGB16UI: return 'gl.RGB16UI';
+ case gl.RGB8_SNORM: return 'gl.RGB8_SNORM';
+ case gl.RGB8I: return 'gl.RGB8I';
+ case gl.RGB8UI: return 'gl.RGB8UI';
+ case gl.SRGB8: return 'gl.SRGB8';
+ case gl.RGB9_E5: return 'gl.RGB9_E5';
+ case gl.RG32F: return 'gl.RG32F';
+ case gl.RG32I: return 'gl.RG32I';
+ case gl.RG32UI: return 'gl.RG32UI';
+ // case gl.RG16: return 'gl.RG16';
+ // case gl.RG16_SNORM: return 'gl.RG16_SNORM';
+ case gl.RG16F: return 'gl.RG16F';
+ case gl.RG16I: return 'gl.RG16I';
+ case gl.RG16UI: return 'gl.RG16UI';
+ case gl.RG8: return 'gl.RG8';
+ case gl.RG8I: return 'gl.RG8I';
+ case gl.RG8UI: return 'gl.RG8UI';
+ case gl.RG8_SNORM: return 'gl.RG8_SNORM';
+ case gl.R32F: return 'gl.R32F';
+ case gl.R32I: return 'gl.R32I';
+ case gl.R32UI: return 'gl.R32UI';
+ // case gl.R16: return 'gl.R16';
+ // case gl.R16_SNORM: return 'gl.R16_SNORM';
+ case gl.R16F: return 'gl.R16F';
+ case gl.R16I: return 'gl.R16I';
+ case gl.R16UI: return 'gl.R16UI';
+ case gl.R8: return 'gl.R8';
+ case gl.R8I: return 'gl.R8I';
+ case gl.R8UI: return 'gl.R8UI';
+ case gl.R8_SNORM: return 'gl.R8_SNORM';
+ case gl.DEPTH_COMPONENT32F: return 'gl.DEPTH_COMPONENT32F';
+ case gl.DEPTH_COMPONENT24: return 'gl.DEPTH_COMPONENT24';
+ case gl.DEPTH32F_STENCIL8: return 'gl.DEPTH32F_STENCIL8';
+ case gl.DEPTH24_STENCIL8: return 'gl.DEPTH24_STENCIL8';
+ // case gl.RGB10: return 'gl.RGB10';
+ // case gl.DEPTH_COMPONENT32: return 'gl.DEPTH_COMPONENT32';
+ case gl.SRGB: return 'gl.SRGB';
+ // case gl.SRGB_ALPHA: return 'gl.SRGB_ALPHA';
+ default: return '';
+ }
+};
+
+gluStrUtil.getTypeName = function(value) {
+ switch (value) {
+ case gl.BYTE: return 'gl.BYTE';
+ case gl.UNSIGNED_BYTE: return 'gl.UNSIGNED_BYTE';
+ case gl.SHORT: return 'gl.SHORT';
+ case gl.UNSIGNED_SHORT: return 'gl.UNSIGNED_SHORT';
+ case gl.INT: return 'gl.INT';
+ case gl.UNSIGNED_INT: return 'gl.UNSIGNED_INT';
+ case gl.FLOAT: return 'gl.FLOAT';
+ // case gl.FIXED: return 'gl.FIXED';
+ case gl.UNSIGNED_SHORT_5_6_5: return 'gl.UNSIGNED_SHORT_5_6_5';
+ case gl.UNSIGNED_SHORT_4_4_4_4: return 'gl.UNSIGNED_SHORT_4_4_4_4';
+ case gl.UNSIGNED_SHORT_5_5_5_1: return 'gl.UNSIGNED_SHORT_5_5_5_1';
+ case gl.HALF_FLOAT: return 'gl.HALF_FLOAT';
+ case gl.INT_2_10_10_10_REV: return 'gl.INT_2_10_10_10_REV';
+ case gl.UNSIGNED_INT_2_10_10_10_REV: return 'gl.UNSIGNED_INT_2_10_10_10_REV';
+ case gl.UNSIGNED_INT_10F_11F_11F_REV: return 'gl.UNSIGNED_INT_10F_11F_11F_REV';
+ case gl.UNSIGNED_INT_5_9_9_9_REV: return 'gl.UNSIGNED_INT_5_9_9_9_REV';
+ case gl.UNSIGNED_INT_24_8: return 'gl.UNSIGNED_INT_24_8';
+ case gl.FLOAT_32_UNSIGNED_INT_24_8_REV: return 'gl.FLOAT_32_UNSIGNED_INT_24_8_REV';
+ case gl.SIGNED_NORMALIZED: return 'gl.SIGNED_NORMALIZED';
+ case gl.UNSIGNED_NORMALIZED: return 'gl.UNSIGNED_NORMALIZED';
+ // case gl.HALF_FLOAT_OES: return 'gl.HALF_FLOAT_OES';
+ default: return '';
+ }
+};
+
+gluStrUtil.getErrorName = function(value) {
+ switch (value) {
+ case gl.NO_ERROR: return 'gl.NO_ERROR';
+ case gl.INVALID_ENUM: return 'gl.INVALID_ENUM';
+ case gl.INVALID_VALUE: return 'gl.INVALID_VALUE';
+ case gl.INVALID_OPERATION: return 'gl.INVALID_OPERATION';
+ case gl.OUT_OF_MEMORY: return 'gl.OUT_OF_MEMORY';
+ // case gl.INVALID_FRAMEBUFFER_OPERATION: return 'gl.INVALID_FRAMEBUFFER_OPERATION';
+ default: return '';
+ }
+};
+
+gluStrUtil.getFramebufferStatusName = function(value) {
+ switch (value) {
+ case gl.FRAMEBUFFER_COMPLETE: return 'gl.FRAMEBUFFER_COMPLETE';
+ case gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT: return 'gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT';
+ case gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT: return 'gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT';
+ case gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS: return 'gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS';
+ case gl.FRAMEBUFFER_UNSUPPORTED: return 'gl.FRAMEBUFFER_UNSUPPORTED';
+ case gl.FRAMEBUFFER_INCOMPLETE_MULTISAMPLE: return 'gl.FRAMEBUFFER_INCOMPLETE_MULTISAMPLE';
+ // case: gl.FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS: return 'gl.FRAMEBUFFER_INCOMPLETE_LAYER_TARGETS';
+ default: return '';
+ }
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTexture.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTexture.js
new file mode 100644
index 0000000000..fcc33588e1
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTexture.js
@@ -0,0 +1,380 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('framework.opengl.gluTexture');
+goog.require('framework.common.tcuCompressedTexture');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.opengl.gluTextureUtil');
+
+goog.scope(function() {
+
+var gluTexture = framework.opengl.gluTexture;
+var gluTextureUtil = framework.opengl.gluTextureUtil;
+var tcuTexture = framework.common.tcuTexture;
+var tcuCompressedTexture = framework.common.tcuCompressedTexture;
+var deMath = framework.delibs.debase.deMath;
+
+var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+};
+
+/** @enum {number} */
+gluTexture.Type = {
+ TYPE_NONE: 0,
+ TYPE_2D: 1,
+ TYPE_CUBE_MAP: 2,
+ TYPE_2D_ARRAY: 3,
+ TYPE_3D: 4
+};
+
+/**
+ * @constructor
+ */
+gluTexture.Texture2D = function(gl, format, isCompressed, refTexture) {
+ this.gl = gl;
+ this.m_glTexture = gl.createTexture();
+ this.m_isCompressed = isCompressed;
+ this.m_format = format; // Internal format
+ this.m_refTexture = refTexture;
+ this.m_type = gluTexture.Type.TYPE_2D;
+};
+
+gluTexture.Texture2D.prototype.getType = function() {
+ return this.m_type;
+};
+
+gluTexture.Texture2D.prototype.getRefTexture = function() {
+ return this.m_refTexture;
+};
+
+gluTexture.Texture2D.prototype.getGLTexture = function() {
+ return this.m_glTexture;
+};
+
+gluTexture.texture2DFromFormat = function(gl, format, dataType, width, height) {
+ var tex = new gluTexture.Texture2D(gl, format, false, new tcuTexture.Texture2D(gluTextureUtil.mapGLTransferFormat(format, dataType), width, height));
+ return tex;
+};
+
+gluTexture.texture2DFromInternalFormat = function(gl, internalFormat, width, height) {
+ var tex = new gluTexture.Texture2D(gl, internalFormat, false, new tcuTexture.Texture2D(gluTextureUtil.mapGLInternalFormat(internalFormat), width, height));
+ return tex;
+};
+
+/**
+ * @param {number} numLevels
+ * @param {Array<tcuCompressedTexture.CompressedTexture>} levels
+ * @return {gluTexture.Texture2D}
+ */
+gluTexture.texture2DFromCompressedTexture = function(gl, numLevels, levels) {
+ var level = levels[0];
+ var format = gluTextureUtil.getGLFormat(level.getFormat());
+ var refTex = new tcuTexture.Texture2D(level.getUncompressedFormat(), level.getWidth(), level.getHeight());
+ /** @type {gluTexture.Texture2D} */ var tex2d = new gluTexture.Texture2D(gl, format, true, refTex);
+
+ tex2d.loadCompressed(numLevels, levels);
+
+ return tex2d;
+};
+/**
+ * @param {number} numLevels
+ * @param {Array<tcuCompressedTexture.CompressedTexture>} levels
+ */
+gluTexture.Texture2D.prototype.loadCompressed = function(numLevels, levels) {
+ /** @type {number} */ var compressedFormat = gluTextureUtil.getGLFormat(levels[0].getFormat());
+
+ assertMsgOptions(this.m_glTexture, 'm_glTexture not defined', false, true);
+ gl.bindTexture(gl.TEXTURE_2D, this.m_glTexture);
+
+ for (var levelNdx = 0; levelNdx < numLevels; levelNdx++) {
+ /** @type {tcuCompressedTexture.CompressedTexture} */ var level = levels[levelNdx];
+
+ // Decompress to reference texture.
+ this.m_refTexture.allocLevel(levelNdx);
+ /** @type {tcuTexture.PixelBufferAccess} */ var refLevelAccess = this.m_refTexture.getLevel(levelNdx);
+ assertMsgOptions(level.getWidth() == refLevelAccess.getWidth() && level.getHeight() == refLevelAccess.getHeight(), 'level and reference sizes not equal', false, true);
+ level.decompress(refLevelAccess);
+
+ // Upload to GL texture in compressed form.
+ gl.compressedTexImage2D(gl.TEXTURE_2D, levelNdx, compressedFormat,
+ level.getWidth(), level.getHeight(), 0, level.getData());
+ }
+};
+
+gluTexture.computePixelStore = function(/*const tcu::TextureFormat&*/ format) {
+ var pixelSize = format.getPixelSize();
+ if (deMath.deIsPowerOfTwo32(pixelSize))
+ return Math.min(pixelSize, 8);
+ else
+ return 1;
+};
+
+gluTexture.cubeFaceToGLFace = function(/*tcu::CubeFace*/ face) {
+ switch (face) {
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X: return gl.TEXTURE_CUBE_MAP_NEGATIVE_X;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X: return gl.TEXTURE_CUBE_MAP_POSITIVE_X;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y: return gl.TEXTURE_CUBE_MAP_NEGATIVE_Y;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y: return gl.TEXTURE_CUBE_MAP_POSITIVE_Y;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z: return gl.TEXTURE_CUBE_MAP_NEGATIVE_Z;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z: return gl.TEXTURE_CUBE_MAP_POSITIVE_Z;
+ }
+ throw new Error('Unrecognized face: ' + face);
+};
+
+gluTexture.Texture2D.prototype.upload = function() {
+ DE_ASSERT(!this.m_isCompressed);
+
+ if (this.m_glTexture == null)
+ testFailedOptions('Failed to create GL texture', true);
+
+ gl.bindTexture(gl.TEXTURE_2D, this.m_glTexture);
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, gluTexture.computePixelStore(this.m_refTexture.getFormat()));
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Setting pixel store failed', false, true);
+
+ var transferFormat = gluTextureUtil.getTransferFormat(this.m_refTexture.getFormat());
+
+ for (var levelNdx = 0; levelNdx < this.m_refTexture.getNumLevels(); levelNdx++) {
+ if (this.m_refTexture.isLevelEmpty(levelNdx))
+ continue; // Don't upload.
+
+ var access = this.m_refTexture.getLevel(levelNdx);
+ DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize() * access.getWidth());
+ var data = access.getDataPtr();
+ gl.texImage2D(gl.TEXTURE_2D, levelNdx, this.m_format, access.getWidth(), access.getHeight(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr());
+ }
+
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true);
+};
+
+/**
+ * @constructor
+ * @extends {gluTexture.Texture2D}
+ */
+gluTexture.TextureCube = function(gl, format, isCompressed, refTexture) {
+ gluTexture.Texture2D.call(this, gl, format, isCompressed, refTexture);
+ this.m_type = gluTexture.Type.TYPE_CUBE_MAP;
+};
+
+gluTexture.TextureCube.prototype = Object.create(gluTexture.Texture2D.prototype);
+gluTexture.TextureCube.prototype.constructor = gluTexture.TextureCube;
+
+gluTexture.TextureCube.prototype.upload = function() {
+ DE_ASSERT(!this.m_isCompressed);
+
+ if (this.m_glTexture == null)
+ testFailedOptions('Failed to create GL texture', true);
+
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.m_glTexture);
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, gluTexture.computePixelStore(this.m_refTexture.getFormat()));
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Setting pixel store failed', false, true);
+
+ var transferFormat = gluTextureUtil.getTransferFormat(this.m_refTexture.getFormat());
+
+ for (var face in tcuTexture.CubeFace) {
+ for (var levelNdx = 0; levelNdx < this.m_refTexture.getNumLevels(); levelNdx++) {
+ if (this.m_refTexture.isLevelEmpty(tcuTexture.CubeFace[face], levelNdx))
+ continue; // Don't upload.
+
+ /*tcu::ConstPixelBufferAccess*/ var access = this.m_refTexture.getLevelFace(levelNdx, tcuTexture.CubeFace[face]);
+ DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize() * access.getWidth());
+ gl.texImage2D(gluTexture.cubeFaceToGLFace(tcuTexture.CubeFace[face]), levelNdx, this.m_format, access.getWidth(), access.getHeight(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr());
+ }
+ }
+
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true);
+};
+
+gluTexture.cubeFromFormat = function(gl, format, dataType, size) {
+ var tex = new gluTexture.TextureCube(gl, format, false, new tcuTexture.TextureCube(gluTextureUtil.mapGLTransferFormat(format, dataType), size));
+ return tex;
+};
+
+gluTexture.cubeFromInternalFormat = function(gl, internalFormat, size) {
+ var tex = new gluTexture.TextureCube(gl, internalFormat, false, new tcuTexture.TextureCube(gluTextureUtil.mapGLInternalFormat(internalFormat), size));
+ return tex;
+};
+
+/**
+ * @constructor
+ * @extends {gluTexture.Texture2D}
+ */
+gluTexture.Texture2DArray = function(gl, format, isCompressed, refTexture) {
+ gluTexture.Texture2D.call(this, gl, format, isCompressed, refTexture);
+ this.m_type = gluTexture.Type.TYPE_2D_ARRAY;
+};
+
+gluTexture.Texture2DArray.prototype = Object.create(gluTexture.Texture2D.prototype);
+gluTexture.Texture2DArray.prototype.constructor = gluTexture.Texture2DArray;
+
+gluTexture.Texture2DArray.prototype.upload = function() {
+ if (!gl.texImage3D)
+ throw new Error('gl.TexImage3D() is not supported');
+
+ gl.bindTexture(gl.TEXTURE_2D_ARRAY, this.m_glTexture);
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, gluTexture.computePixelStore(this.m_refTexture.getFormat()));
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true);
+
+ var transferFormat = gluTextureUtil.getTransferFormat(this.m_refTexture.getFormat());
+
+ for (var levelNdx = 0; levelNdx < this.m_refTexture.getNumLevels(); levelNdx++) {
+ if (this.m_refTexture.isLevelEmpty(levelNdx))
+ continue; // Don't upload.
+
+ /*tcu::ConstPixelBufferAccess*/ var access = this.m_refTexture.getLevel(levelNdx);
+ DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize() * access.getWidth());
+ DE_ASSERT(access.getSlicePitch() == access.getFormat().getPixelSize() * access.getWidth() * access.getHeight());
+ gl.texImage3D(gl.TEXTURE_2D_ARRAY, levelNdx, this.m_format, access.getWidth(), access.getHeight(), access.getDepth(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr());
+ }
+
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true);
+};
+
+gluTexture.texture2DArrayFromFormat = function(gl, format, dataType, width, height, numLayers) {
+ var tex = new gluTexture.Texture2DArray(gl, format, false, new tcuTexture.Texture2DArray(gluTextureUtil.mapGLTransferFormat(format, dataType), width, height, numLayers));
+ return tex;
+};
+
+gluTexture.texture2DArrayFromInternalFormat = function(gl, internalFormat, width, height, numLayers) {
+ var tex = new gluTexture.Texture2DArray(gl, internalFormat, false, new tcuTexture.Texture2DArray(gluTextureUtil.mapGLInternalFormat(internalFormat), width, height, numLayers));
+ return tex;
+};
+
+/**
+ * @constructor
+ * @extends {gluTexture.Texture2D}
+ */
+gluTexture.Texture3D = function(gl, format, isCompressed, refTexture) {
+ gluTexture.Texture2D.call(this, gl, format, isCompressed, refTexture);
+ this.m_type = gluTexture.Type.TYPE_3D;
+};
+
+gluTexture.Texture3D.prototype = Object.create(gluTexture.Texture2D.prototype);
+gluTexture.Texture3D.prototype.constructor = gluTexture.Texture3D;
+
+gluTexture.Texture3D.prototype.upload = function() {
+ if (!gl.texImage3D)
+ throw new Error('gl.TexImage3D() is not supported');
+
+ gl.bindTexture(gl.TEXTURE_3D, this.m_glTexture);
+ gl.pixelStorei(gl.UNPACK_ALIGNMENT, gluTexture.computePixelStore(this.m_refTexture.getFormat()));
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true);
+
+ var transferFormat = gluTextureUtil.getTransferFormat(this.m_refTexture.getFormat());
+
+ for (var levelNdx = 0; levelNdx < this.m_refTexture.getNumLevels(); levelNdx++) {
+ if (this.m_refTexture.isLevelEmpty(levelNdx))
+ continue; // Don't upload.
+
+ /*tcu::ConstPixelBufferAccess*/ var access = this.m_refTexture.getLevel(levelNdx);
+ DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize() * access.getWidth());
+ DE_ASSERT(access.getSlicePitch() == access.getFormat().getPixelSize() * access.getWidth() * access.getHeight());
+ gl.texImage3D(gl.TEXTURE_3D, levelNdx, this.m_format, access.getWidth(), access.getHeight(), access.getDepth(), 0 /* border */, transferFormat.format, transferFormat.dataType, access.getDataPtr());
+ }
+
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true);
+};
+
+gluTexture.texture3DFromFormat = function(gl, format, dataType, width, height, depth) {
+ var tex = new gluTexture.Texture3D(gl, format, false, new tcuTexture.Texture3D(gluTextureUtil.mapGLTransferFormat(format, dataType), width, height, depth));
+ return tex;
+};
+
+gluTexture.texture3DFromInternalFormat = function(gl, internalFormat, width, height, depth) {
+ var tex = new gluTexture.Texture3D(gl, internalFormat, false, new tcuTexture.Texture3D(gluTextureUtil.mapGLInternalFormat(internalFormat), width, height, depth));
+ return tex;
+};
+
+/**
+ * @constructor
+ * @extends {gluTexture.Texture2D}
+ */
+gluTexture.Compressed2D = function(gl, format, isCompressed, refTexture) {
+ gluTexture.Texture2D.call(this, gl, format, isCompressed, refTexture);
+};
+
+gluTexture.Compressed2D.prototype = Object.create(gluTexture.Texture2D.prototype);
+gluTexture.Compressed2D.prototype.constructor = gluTexture.Compressed2D;
+
+gluTexture.Compressed2D.prototype.uploadLevel = function(level, source) {
+ DE_ASSERT(this.m_isCompressed);
+
+ if (this.m_glTexture == null)
+ testFailedOptions('Failed to create GL texture', true);
+
+ gl.bindTexture(gl.TEXTURE_2D, this.m_glTexture);
+
+ gl.compressedTexImage2D(gl.TEXTURE_2D, level, this.m_format, source.m_width, source.m_height, 0 /* border */, source.m_data);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true);
+};
+
+/**
+ * @constructor
+ * @extends {gluTexture.Texture2D}
+ */
+gluTexture.CompressedCube = function(gl, format, isCompressed, refTexture) {
+ gluTexture.Texture2D.call(this, gl, format, isCompressed, refTexture);
+};
+
+gluTexture.CompressedCube.prototype = Object.create(gluTexture.Texture2D.prototype);
+gluTexture.CompressedCube.prototype.constructor = gluTexture.CompressedCube;
+
+gluTexture.CompressedCube.prototype.uploadLevel = function(level, source) {
+ DE_ASSERT(this.m_isCompressed);
+
+ if (this.m_glTexture == null)
+ testFailedOptions('Failed to create GL texture', true);
+
+ gl.bindTexture(gl.TEXTURE_CUBE_MAP, this.m_glTexture);
+
+ for (var face in tcuTexture.CubeFace) {
+
+ // Upload to GL texture in compressed form.
+ gl.compressedTexImage2D(gluTexture.cubeFaceToGLFace(tcuTexture.CubeFace[face]), 0, this.m_format,
+ source.m_width, source.m_height, 0 /* border */, source.m_data);
+ assertMsgOptions(gl.getError() === gl.NO_ERROR, 'Texture upload failed', false, true);
+ }
+
+};
+
+gluTexture.compressed2DFromInternalFormat = function(gl, format, width, height, compressed) {
+ var tex = new gluTexture.Compressed2D(gl, gluTextureUtil.getGLFormat(format), true, new tcuTexture.Texture2D(compressed.getUncompressedFormat(), width, height));
+ tex.m_refTexture.allocLevel(0);
+ compressed.decompress(tex.m_refTexture.getLevel(0));
+ tex.uploadLevel(0, compressed);
+ return tex;
+};
+
+gluTexture.compressedCubeFromInternalFormat = function(gl, format, size, compressed) {
+ var tex = new gluTexture.CompressedCube(gl, gluTextureUtil.getGLFormat(format), true, new tcuTexture.TextureCube(compressed.getUncompressedFormat(), size));
+ for (var face in tcuTexture.CubeFace) {
+ tex.m_refTexture.allocLevel(tcuTexture.CubeFace[face], 0);
+
+ /*tcu::ConstPixelBufferAccess*/ var access = tex.m_refTexture.getLevelFace(0, tcuTexture.CubeFace[face]);
+ DE_ASSERT(access.getRowPitch() == access.getFormat().getPixelSize() * access.getWidth());
+ compressed.decompress(access);
+ }
+ tex.uploadLevel(0, compressed);
+ return tex;
+};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTextureUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTextureUtil.js
new file mode 100644
index 0000000000..06f3f5289d
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluTextureUtil.js
@@ -0,0 +1,1025 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+/*--------------------------------------------------------------------*//*!
+ * \brief Map tcuTexture.TextureFormat to GL pixel transfer format.
+ *
+ * Maps generic texture format description to GL pixel transfer format.
+ * If no mapping is found, throws tcu::InternalError.
+ *
+ * \param texFormat Generic texture format.
+ * \return GL pixel transfer format.
+ *//*--------------------------------------------------------------------*/
+'use strict';
+goog.provide('framework.opengl.gluTextureUtil');
+goog.require('framework.common.tcuCompressedTexture');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.common.tcuTextureUtil');
+goog.require('framework.delibs.debase.deString');
+goog.require('framework.opengl.gluShaderUtil');
+
+goog.scope(function() {
+
+var gluTextureUtil = framework.opengl.gluTextureUtil;
+var deString = framework.delibs.debase.deString;
+var tcuTexture = framework.common.tcuTexture;
+var tcuTextureUtil = framework.common.tcuTextureUtil;
+var tcuCompressedTexture = framework.common.tcuCompressedTexture;
+var gluShaderUtil = framework.opengl.gluShaderUtil;
+
+/**
+ * @param {number} format
+ * @param {number} dataType
+ * @constructor
+ */
+gluTextureUtil.TransferFormat = function(format, dataType) {
+ this.format = format; //!< Pixel format.
+ this.dataType = dataType; //!< Data type.
+};
+
+/**
+ * Map tcuTexture.TextureFormat to GL pixel transfer format.
+ *
+ * Maps generic texture format description to GL pixel transfer format.
+ * If no mapping is found, throws tcu::InternalError.
+ *
+ * @param {tcuTexture.TextureFormat} texFormat Generic texture format.
+ * @return {gluTextureUtil.TransferFormat} GL pixel transfer format.
+ * @throws {Error}
+ */
+gluTextureUtil.getTransferFormat = function(/* tcuTexture.TextureFormat */ texFormat) {
+ var format = gl.NONE;
+ var type = gl.NONE;
+ /*boolean*/ var isInt = false;
+
+ switch (texFormat.type) {
+ case tcuTexture.ChannelType.SIGNED_INT8:
+ case tcuTexture.ChannelType.SIGNED_INT16:
+ case tcuTexture.ChannelType.SIGNED_INT32:
+ case tcuTexture.ChannelType.UNSIGNED_INT8:
+ case tcuTexture.ChannelType.UNSIGNED_INT16:
+ case tcuTexture.ChannelType.UNSIGNED_INT32:
+ case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV:
+ isInt = true;
+ break;
+
+ default:
+ isInt = false;
+ break;
+ }
+
+ switch (texFormat.order) {
+ case tcuTexture.ChannelOrder.A: format = gl.ALPHA; break;
+ case tcuTexture.ChannelOrder.L: format = gl.LUMINANCE; break;
+ case tcuTexture.ChannelOrder.LA: format = gl.LUMINANCE_ALPHA; break;
+ case tcuTexture.ChannelOrder.R: format = isInt ? gl.RED_INTEGER : gl.RED; break;
+ case tcuTexture.ChannelOrder.RG: format = isInt ? gl.RG_INTEGER : gl.RG; break;
+ case tcuTexture.ChannelOrder.RGB: format = isInt ? gl.RGB_INTEGER : gl.RGB; break;
+ case tcuTexture.ChannelOrder.RGBA: format = isInt ? gl.RGBA_INTEGER : gl.RGBA; break;
+ case tcuTexture.ChannelOrder.sRGB: format = gl.RGB; break;
+ case tcuTexture.ChannelOrder.sRGBA: format = gl.RGBA; break;
+ case tcuTexture.ChannelOrder.D: format = gl.DEPTH_COMPONENT; break;
+ case tcuTexture.ChannelOrder.DS: format = gl.DEPTH_STENCIL; break;
+ case tcuTexture.ChannelOrder.S: format = gl.STENCIL_INDEX; break;
+
+ default:
+ throw new Error('Unknown ChannelOrder ' + texFormat.order);
+ }
+
+ switch (texFormat.type) {
+ case tcuTexture.ChannelType.SNORM_INT8: type = gl.BYTE; break;
+ case tcuTexture.ChannelType.SNORM_INT16: type = gl.SHORT; break;
+ case tcuTexture.ChannelType.UNORM_INT8: type = gl.UNSIGNED_BYTE; break;
+ case tcuTexture.ChannelType.UNORM_INT16: type = gl.UNSIGNED_SHORT; break;
+ case tcuTexture.ChannelType.UNORM_SHORT_565: type = gl.UNSIGNED_SHORT_5_6_5; break;
+ case tcuTexture.ChannelType.UNORM_SHORT_4444: type = gl.UNSIGNED_SHORT_4_4_4_4; break;
+ case tcuTexture.ChannelType.UNORM_SHORT_5551: type = gl.UNSIGNED_SHORT_5_5_5_1; break;
+ case tcuTexture.ChannelType.SIGNED_INT8: type = gl.BYTE; break;
+ case tcuTexture.ChannelType.SIGNED_INT16: type = gl.SHORT; break;
+ case tcuTexture.ChannelType.SIGNED_INT32: type = gl.INT; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT8: type = gl.UNSIGNED_BYTE; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT16: type = gl.UNSIGNED_SHORT; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT32: type = gl.UNSIGNED_INT; break;
+ case tcuTexture.ChannelType.FLOAT: type = gl.FLOAT; break;
+ case tcuTexture.ChannelType.UNORM_INT_101010: type = gl.UNSIGNED_INT_2_10_10_10_REV; break;
+ case tcuTexture.ChannelType.UNORM_INT_1010102_REV: type = gl.UNSIGNED_INT_2_10_10_10_REV; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV: type = gl.UNSIGNED_INT_2_10_10_10_REV; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV: type = gl.UNSIGNED_INT_10F_11F_11F_REV; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV: type = gl.UNSIGNED_INT_5_9_9_9_REV; break;
+ case tcuTexture.ChannelType.HALF_FLOAT: type = gl.HALF_FLOAT; break;
+ case tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV: type = gl.FLOAT_32_UNSIGNED_INT_24_8_REV; break;
+ case tcuTexture.ChannelType.UNSIGNED_INT_24_8: type = texFormat.order == tcuTexture.ChannelOrder.D ?
+ gl.UNSIGNED_INT : gl.UNSIGNED_INT_24_8; break;
+
+ default:
+ throw new Error("Can't map texture format to GL transfer format " + texFormat.type);
+ }
+
+ return new gluTextureUtil.TransferFormat(format, type);
+};
+
+/**
+ * Map tcuTexture.TextureFormat to GL internal sized format.
+ *
+ * Maps generic texture format description to GL internal format.
+ * If no mapping is found, throws Error.
+ *
+ * @param {tcuTexture.TextureFormat} texFormat Generic texture format.
+ * @return {number} GL texture format.
+ * @throws {Error}
+ */
+gluTextureUtil.getInternalFormat = function(texFormat) {
+
+ var stringify = function(order, type) {
+ return '' + order + ' ' + type;
+ };
+
+ switch (stringify(texFormat.order, texFormat.type)) {
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_5551): return gl.RGB5_A1;
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_4444): return gl.RGBA4;
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_SHORT_565): return gl.RGB565;
+ case stringify(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNORM_INT16): return gl.DEPTH_COMPONENT16;
+ case stringify(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT8): return gl.STENCIL_INDEX8;
+
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.FLOAT): return gl.RGBA32F;
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SIGNED_INT32): return gl.RGBA32I;
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT32): return gl.RGBA32UI;
+ // TODO: Check which ones are valid in WebGL 2 - case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT16): return gl.RGBA16;
+ //case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SNORM_INT16): return gl.RGBA16_SNORM;
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.HALF_FLOAT): return gl.RGBA16F;
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SIGNED_INT16): return gl.RGBA16I;
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT16): return gl.RGBA16UI;
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8): return gl.RGBA8;
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SIGNED_INT8): return gl.RGBA8I;
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT8): return gl.RGBA8UI;
+ case stringify(tcuTexture.ChannelOrder.sRGBA, tcuTexture.ChannelType.UNORM_INT8): return gl.SRGB8_ALPHA8;
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT_1010102_REV): return gl.RGB10_A2;
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV): return gl.RGB10_A2UI;
+ case stringify(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SNORM_INT8): return gl.RGBA8_SNORM;
+
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8): return gl.RGB8;
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV): return gl.R11F_G11F_B10F;
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.FLOAT): return gl.RGB32F;
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SIGNED_INT32): return gl.RGB32I;
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT32): return gl.RGB32UI;
+ //case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT16): return gl.RGB16;
+ //case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SNORM_INT16): return gl.RGB16_SNORM;
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.HALF_FLOAT): return gl.RGB16F;
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SIGNED_INT16): return gl.RGB16I;
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT16): return gl.RGB16UI;
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SNORM_INT8): return gl.RGB8_SNORM;
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SIGNED_INT8): return gl.RGB8I;
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT8): return gl.RGB8UI;
+ case stringify(tcuTexture.ChannelOrder.sRGB, tcuTexture.ChannelType.UNORM_INT8): return gl.SRGB8;
+ case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV): return gl.RGB9_E5;
+ //case stringify(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT_1010102_REV): return gl.RGB10;
+
+ case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.FLOAT): return gl.RG32F;
+ case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SIGNED_INT32): return gl.RG32I;
+ case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNSIGNED_INT32): return gl.RG32UI;
+ //case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNORM_INT16): return gl.RG16;
+ //case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SNORM_INT16): return gl.RG16_SNORM;
+ case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.HALF_FLOAT): return gl.RG16F;
+ case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SIGNED_INT16): return gl.RG16I;
+ case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNSIGNED_INT16): return gl.RG16UI;
+ case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNORM_INT8): return gl.RG8;
+ case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SIGNED_INT8): return gl.RG8I;
+ case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNSIGNED_INT8): return gl.RG8UI;
+ case stringify(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SNORM_INT8): return gl.RG8_SNORM;
+
+ case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.FLOAT): return gl.R32F;
+ case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SIGNED_INT32): return gl.R32I;
+ case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNSIGNED_INT32): return gl.R32UI;
+ //case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNORM_INT16): return gl.R16;
+ //case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SNORM_INT16): return gl.R16_SNORM;
+ case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.HALF_FLOAT): return gl.R16F;
+ case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SIGNED_INT16): return gl.R16I;
+ case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNSIGNED_INT16): return gl.R16UI;
+ case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNORM_INT8): return gl.R8;
+ case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SIGNED_INT8): return gl.R8I;
+ case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNSIGNED_INT8): return gl.R8UI;
+ case stringify(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SNORM_INT8): return gl.R8_SNORM;
+
+ case stringify(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.FLOAT): return gl.DEPTH_COMPONENT32F;
+ case stringify(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNSIGNED_INT_24_8): return gl.DEPTH_COMPONENT24;
+ //case stringify(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNSIGNED_INT32): return gl.DEPTH_COMPONENT32;
+ case stringify(tcuTexture.ChannelOrder.DS, tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV): return gl.DEPTH32F_STENCIL8;
+ case stringify(tcuTexture.ChannelOrder.DS, tcuTexture.ChannelType.UNSIGNED_INT_24_8): return gl.DEPTH24_STENCIL8;
+
+ default:
+ throw new Error("Can't map texture format to GL internal format");
+ }
+};
+
+/**
+ * Enable WEBGL_compressed_texture_etc support if available, by merging it
+ * into the WebGL2RenderingContext.
+ *
+ * This function may be called many times.
+ *
+ * @return {boolean} True if enabled.
+ */
+gluTextureUtil.enableCompressedTextureETC = (function() {
+ var enabled = undefined;
+ return function() {
+ if (enabled === undefined) {
+ enabled = false;
+
+ var WEBGL_compressed_texture_etc = gl.getExtension("WEBGL_compressed_texture_etc");
+ if (WEBGL_compressed_texture_etc) {
+ // Extend gl with enums from WEBGL_compressed_texture_etc
+ // (if it doesn't already have the etc texture formats).
+ var proto = Object.getPrototypeOf(WEBGL_compressed_texture_etc);
+ for (var prop in proto) {
+ if (proto.hasOwnProperty(prop)) {
+ gl[prop] = proto[prop];
+ }
+ }
+ enabled = true;
+ }
+ }
+ return enabled;
+ };
+})();
+
+/**
+ * Map generic compressed format to GL compressed format enum.
+ *
+ * Maps generic compressed format to GL compressed format enum value.
+ * If no mapping is found, throws Error.
+
+ * @param {tcuCompressedTexture.Format} format Generic compressed format.
+ * @return {number} GL compressed texture format.
+ * @throws {Error}
+ */
+gluTextureUtil.getGLFormat = function(/* tcuCompressedTexture.Format */ format) {
+ switch (format) {
+ // TODO: check which are available in WebGL 2 - case tcuCompressedTexture.Format.ETC1_RGB8: return gl.ETC1_RGB8_OES;
+ case tcuCompressedTexture.Format.EAC_R11: return gl.COMPRESSED_R11_EAC;
+ case tcuCompressedTexture.Format.EAC_SIGNED_R11: return gl.COMPRESSED_SIGNED_R11_EAC;
+ case tcuCompressedTexture.Format.EAC_RG11: return gl.COMPRESSED_RG11_EAC;
+ case tcuCompressedTexture.Format.EAC_SIGNED_RG11: return gl.COMPRESSED_SIGNED_RG11_EAC;
+ case tcuCompressedTexture.Format.ETC2_RGB8: return gl.COMPRESSED_RGB8_ETC2;
+ case tcuCompressedTexture.Format.ETC2_SRGB8: return gl.COMPRESSED_SRGB8_ETC2;
+ case tcuCompressedTexture.Format.ETC2_RGB8_PUNCHTHROUGH_ALPHA1: return gl.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+ case tcuCompressedTexture.Format.ETC2_SRGB8_PUNCHTHROUGH_ALPHA1: return gl.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2;
+ case tcuCompressedTexture.Format.ETC2_EAC_RGBA8: return gl.COMPRESSED_RGBA8_ETC2_EAC;
+ case tcuCompressedTexture.Format.ETC2_EAC_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
+
+ /*case tcuCompressedTexture.Format.ASTC_4x4_RGBA: return gl.COMPRESSED_RGBA_ASTC_4x4_KHR;
+ case tcuCompressedTexture.Format.ASTC_5x4_RGBA: return gl.COMPRESSED_RGBA_ASTC_5x4_KHR;
+ case tcuCompressedTexture.Format.ASTC_5x5_RGBA: return gl.COMPRESSED_RGBA_ASTC_5x5_KHR;
+ case tcuCompressedTexture.Format.ASTC_6x5_RGBA: return gl.COMPRESSED_RGBA_ASTC_6x5_KHR;
+ case tcuCompressedTexture.Format.ASTC_6x6_RGBA: return gl.COMPRESSED_RGBA_ASTC_6x6_KHR;
+ case tcuCompressedTexture.Format.ASTC_8x5_RGBA: return gl.COMPRESSED_RGBA_ASTC_8x5_KHR;
+ case tcuCompressedTexture.Format.ASTC_8x6_RGBA: return gl.COMPRESSED_RGBA_ASTC_8x6_KHR;
+ case tcuCompressedTexture.Format.ASTC_8x8_RGBA: return gl.COMPRESSED_RGBA_ASTC_8x8_KHR;
+ case tcuCompressedTexture.Format.ASTC_10x5_RGBA: return gl.COMPRESSED_RGBA_ASTC_10x5_KHR;
+ case tcuCompressedTexture.Format.ASTC_10x6_RGBA: return gl.COMPRESSED_RGBA_ASTC_10x6_KHR;
+ case tcuCompressedTexture.Format.ASTC_10x8_RGBA: return gl.COMPRESSED_RGBA_ASTC_10x8_KHR;
+ case tcuCompressedTexture.Format.ASTC_10x10_RGBA: return gl.COMPRESSED_RGBA_ASTC_10x10_KHR;
+ case tcuCompressedTexture.Format.ASTC_12x10_RGBA: return gl.COMPRESSED_RGBA_ASTC_12x10_KHR;
+ case tcuCompressedTexture.Format.ASTC_12x12_RGBA: return gl.COMPRESSED_RGBA_ASTC_12x12_KHR;
+ case tcuCompressedTexture.Format.ASTC_4x4_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_4x4_KHR;
+ case tcuCompressedTexture.Format.ASTC_5x4_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_5x4_KHR;
+ case tcuCompressedTexture.Format.ASTC_5x5_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_5x5_KHR;
+ case tcuCompressedTexture.Format.ASTC_6x5_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_6x5_KHR;
+ case tcuCompressedTexture.Format.ASTC_6x6_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_6x6_KHR;
+ case tcuCompressedTexture.Format.ASTC_8x5_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_8x5_KHR;
+ case tcuCompressedTexture.Format.ASTC_8x6_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_8x6_KHR;
+ case tcuCompressedTexture.Format.ASTC_8x8_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_8x8_KHR;
+ case tcuCompressedTexture.Format.ASTC_10x5_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_10x5_KHR;
+ case tcuCompressedTexture.Format.ASTC_10x6_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_10x6_KHR;
+ case tcuCompressedTexture.Format.ASTC_10x8_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_10x8_KHR;
+ case tcuCompressedTexture.Format.ASTC_10x10_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_10x10_KHR;
+ case tcuCompressedTexture.Format.ASTC_12x10_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR;
+ case tcuCompressedTexture.Format.ASTC_12x12_SRGB8_ALPHA8: return gl.COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR;*/
+
+ default:
+ throw new Error("Can't map compressed format to GL format");
+ }
+};
+
+/**
+ * @param {number} dataType
+ * @param {boolean} normalized
+ * @return {tcuTexture.ChannelType}
+ * @throws {Error}
+ */
+gluTextureUtil.mapGLChannelType = function(/* deMath.deUint32 */ dataType, /*boolean*/ normalized) {
+ // \note Normalized bit is ignored where it doesn't apply.
+
+ switch (dataType) {
+ case gl.UNSIGNED_BYTE: return normalized ? tcuTexture.ChannelType.UNORM_INT8 : tcuTexture.ChannelType.UNSIGNED_INT8;
+ case gl.BYTE: return normalized ? tcuTexture.ChannelType.SNORM_INT8 : tcuTexture.ChannelType.SIGNED_INT8;
+ case gl.UNSIGNED_SHORT: return normalized ? tcuTexture.ChannelType.UNORM_INT16 : tcuTexture.ChannelType.UNSIGNED_INT16;
+ case gl.SHORT: return normalized ? tcuTexture.ChannelType.SNORM_INT16 : tcuTexture.ChannelType.SIGNED_INT16;
+ case gl.UNSIGNED_INT: return normalized ? tcuTexture.ChannelType.UNORM_INT32 : tcuTexture.ChannelType.UNSIGNED_INT32;
+ case gl.INT: return normalized ? tcuTexture.ChannelType.SNORM_INT32 : tcuTexture.ChannelType.SIGNED_INT32;
+ case gl.FLOAT: return tcuTexture.ChannelType.FLOAT;
+ case gl.UNSIGNED_SHORT_4_4_4_4: return tcuTexture.ChannelType.UNORM_SHORT_4444;
+ case gl.UNSIGNED_SHORT_5_5_5_1: return tcuTexture.ChannelType.UNORM_SHORT_5551;
+ case gl.UNSIGNED_SHORT_5_6_5: return tcuTexture.ChannelType.UNORM_SHORT_565;
+ case gl.HALF_FLOAT: return tcuTexture.ChannelType.HALF_FLOAT;
+ case gl.UNSIGNED_INT_2_10_10_10_REV: return normalized ? tcuTexture.ChannelType.UNORM_INT_1010102_REV : tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV;
+ case gl.UNSIGNED_INT_10F_11F_11F_REV: return tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV;
+ case gl.UNSIGNED_INT_24_8: return tcuTexture.ChannelType.UNSIGNED_INT_24_8;
+ case gl.FLOAT_32_UNSIGNED_INT_24_8_REV: return tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV;
+ case gl.UNSIGNED_INT_5_9_9_9_REV: return tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV;
+
+ default:
+ throw new Error('Unsupported dataType ' + dataType);
+ }
+};
+
+/**
+ * @param {number} format Generic compressed format.
+ * @param {number} dataType
+ * @return {tcuTexture.TextureFormat} GL texture format.
+ * @throws {Error}
+ */
+gluTextureUtil.mapGLTransferFormat = function(format, dataType) {
+ switch (format) {
+ case gl.ALPHA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.A, gluTextureUtil.mapGLChannelType(dataType, true));
+ case gl.LUMINANCE: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.L, gluTextureUtil.mapGLChannelType(dataType, true));
+ case gl.LUMINANCE_ALPHA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.LA, gluTextureUtil.mapGLChannelType(dataType, true));
+ case gl.RGB: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, gluTextureUtil.mapGLChannelType(dataType, true));
+ case gl.RGBA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, gluTextureUtil.mapGLChannelType(dataType, true));
+ //case gl.BGRA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.BGRA, gluTextureUtil.mapGLChannelType(dataType, true));
+ case gl.RG: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, gluTextureUtil.mapGLChannelType(dataType, true));
+ case gl.RED: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, gluTextureUtil.mapGLChannelType(dataType, true));
+ case gl.RGBA_INTEGER: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, gluTextureUtil.mapGLChannelType(dataType, false));
+ case gl.RGB_INTEGER: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, gluTextureUtil.mapGLChannelType(dataType, false));
+ case gl.RG_INTEGER: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, gluTextureUtil.mapGLChannelType(dataType, false));
+ case gl.RED_INTEGER: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, gluTextureUtil.mapGLChannelType(dataType, false));
+
+ case gl.DEPTH_COMPONENT: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, gluTextureUtil.mapGLChannelType(dataType, true));
+ case gl.DEPTH_STENCIL: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.DS, gluTextureUtil.mapGLChannelType(dataType, true));
+
+ default:
+ throw new Error("Can't map GL pixel format (" + deString.enumToString(gl, format) + ', ' + deString.enumToString(gl, dataType) + ') to texture format');
+ }
+};
+
+ /**
+ * Map GL internal texture format to tcuTexture.TextureFormat.
+ *
+ * If no mapping is found, throws Error.
+ * @param {number} internalFormat
+ * @return {tcuTexture.TextureFormat} GL texture format.
+ * @throws {Error}
+ */
+gluTextureUtil.mapGLInternalFormat = function(/*deMath.deUint32*/ internalFormat) {
+ if (internalFormat === undefined)
+ throw new Error('internalformat is undefined');
+
+ switch (internalFormat) {
+ case gl.RGB5_A1: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_5551);
+ case gl.RGBA4: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_4444);
+ case gl.RGB565: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_SHORT_565);
+ case gl.DEPTH_COMPONENT16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNORM_INT16);
+ case gl.STENCIL_INDEX8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT8);
+
+ case gl.RGBA32F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.FLOAT);
+ case gl.RGBA32I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SIGNED_INT32);
+ case gl.RGBA32UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT32);
+ //TODO: Check which are available in WebGL 2 case gl.RGBA16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT16);
+ //case gl.RGBA16_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SNORM_INT16);
+ case gl.RGBA16F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.HALF_FLOAT);
+ case gl.RGBA16I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SIGNED_INT16);
+ case gl.RGBA16UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT16);
+ case gl.RGBA8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8);
+ case gl.RGBA8I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SIGNED_INT8);
+ case gl.RGBA8UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT8);
+ case gl.SRGB8_ALPHA8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.sRGBA, tcuTexture.ChannelType.UNORM_INT8);
+ case gl.RGB10_A2: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT_1010102_REV);
+ case gl.RGB10_A2UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNSIGNED_INT_1010102_REV);
+ case gl.RGBA8_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.SNORM_INT8);
+
+ case gl.RGB8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8);
+ case gl.R11F_G11F_B10F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT_11F_11F_10F_REV);
+ case gl.RGB32F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.FLOAT);
+ case gl.RGB32I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SIGNED_INT32);
+ case gl.RGB32UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT32);
+ //case gl.RGB16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT16);
+ //case gl.RGB16_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SNORM_INT16);
+ case gl.RGB16F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.HALF_FLOAT);
+ case gl.RGB16I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SIGNED_INT16);
+ case gl.RGB16UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT16);
+ case gl.RGB8_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SNORM_INT8);
+ case gl.RGB8I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.SIGNED_INT8);
+ case gl.RGB8UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT8);
+ case gl.SRGB8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.sRGB, tcuTexture.ChannelType.UNORM_INT8);
+ case gl.RGB9_E5: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNSIGNED_INT_999_E5_REV);
+ //case gl.RGB10: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT_1010102_REV);
+
+ case gl.RG32F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.FLOAT);
+ case gl.RG32I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SIGNED_INT32);
+ case gl.RG32UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNSIGNED_INT32);
+ //case gl.RG16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNORM_INT16);
+ //case gl.RG16_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SNORM_INT16);
+ case gl.RG16F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.HALF_FLOAT);
+ case gl.RG16I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SIGNED_INT16);
+ case gl.RG16UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNSIGNED_INT16);
+ case gl.RG8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNORM_INT8);
+ case gl.RG8I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SIGNED_INT8);
+ case gl.RG8UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.UNSIGNED_INT8);
+ case gl.RG8_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RG, tcuTexture.ChannelType.SNORM_INT8);
+
+ case gl.R32F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.FLOAT);
+ case gl.R32I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SIGNED_INT32);
+ case gl.R32UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNSIGNED_INT32);
+ //case gl.R16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNORM_INT16);
+ //case gl.R16_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SNORM_INT16);
+ case gl.R16F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.HALF_FLOAT);
+ case gl.R16I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SIGNED_INT16);
+ case gl.R16UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNSIGNED_INT16);
+ case gl.R8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNORM_INT8);
+ case gl.R8I: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SIGNED_INT8);
+ case gl.R8UI: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.UNSIGNED_INT8);
+ case gl.R8_SNORM: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.R, tcuTexture.ChannelType.SNORM_INT8);
+
+ case gl.DEPTH_COMPONENT32F: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.FLOAT);
+ case gl.DEPTH_COMPONENT24: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNSIGNED_INT_24_8);
+ //case gl.DEPTH_COMPONENT32: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNSIGNED_INT32);
+ case gl.DEPTH32F_STENCIL8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.DS, tcuTexture.ChannelType.FLOAT_UNSIGNED_INT_24_8_REV);
+ case gl.DEPTH24_STENCIL8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.DS, tcuTexture.ChannelType.UNSIGNED_INT_24_8);
+
+ default:
+ throw new Error("Can't map GL sized internal format (" + internalFormat.toString(16) + ') to texture format');
+ }
+};
+
+/**
+ * @param {number} format
+ * @return {boolean}
+ */
+gluTextureUtil.isGLInternalColorFormatFilterable = function(format) {
+ switch (format) {
+ case gl.R8:
+ case gl.R8_SNORM:
+ case gl.RG8:
+ case gl.RG8_SNORM:
+ case gl.RGB8:
+ case gl.RGB8_SNORM:
+ case gl.RGB565:
+ case gl.RGBA4:
+ case gl.RGB5_A1:
+ case gl.RGBA8:
+ case gl.RGBA8_SNORM:
+ case gl.RGB10_A2:
+ case gl.SRGB8:
+ case gl.SRGB8_ALPHA8:
+ case gl.R16F:
+ case gl.RG16F:
+ case gl.RGB16F:
+ case gl.RGBA16F:
+ case gl.R11F_G11F_B10F:
+ case gl.RGB9_E5:
+ return true;
+
+ case gl.RGB10_A2UI:
+ case gl.R32F:
+ case gl.RG32F:
+ case gl.RGB32F:
+ case gl.RGBA32F:
+ case gl.R8I:
+ case gl.R8UI:
+ case gl.R16I:
+ case gl.R16UI:
+ case gl.R32I:
+ case gl.R32UI:
+ case gl.RG8I:
+ case gl.RG8UI:
+ case gl.RG16I:
+ case gl.RG16UI:
+ case gl.RG32I:
+ case gl.RG32UI:
+ case gl.RGB8I:
+ case gl.RGB8UI:
+ case gl.RGB16I:
+ case gl.RGB16UI:
+ case gl.RGB32I:
+ case gl.RGB32UI:
+ case gl.RGBA8I:
+ case gl.RGBA8UI:
+ case gl.RGBA16I:
+ case gl.RGBA16UI:
+ case gl.RGBA32I:
+ case gl.RGBA32UI:
+ return false;
+
+ default:
+ throw new Error('Unrecognized format ' + format);
+ }
+};
+
+/**
+ * @param {number} wrapMode
+ * @return {tcuTexture.WrapMode}
+ */
+gluTextureUtil.mapGLWrapMode = function(wrapMode) {
+ switch (wrapMode) {
+ case gl.CLAMP_TO_EDGE: return tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ case gl.REPEAT: return tcuTexture.WrapMode.REPEAT_GL;
+ case gl.MIRRORED_REPEAT: return tcuTexture.WrapMode.MIRRORED_REPEAT_GL;
+ default:
+ throw new Error("Can't map GL wrap mode " + deString.enumToString(gl, wrapMode));
+ }
+};
+
+/**
+ * @param {number} filterMode
+ * @return {tcuTexture.FilterMode}
+ * @throws {Error}
+ */
+gluTextureUtil.mapGLFilterMode = function(filterMode) {
+ switch (filterMode) {
+ case gl.NEAREST: return tcuTexture.FilterMode.NEAREST;
+ case gl.LINEAR: return tcuTexture.FilterMode.LINEAR;
+ case gl.NEAREST_MIPMAP_NEAREST: return tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST;
+ case gl.NEAREST_MIPMAP_LINEAR: return tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR;
+ case gl.LINEAR_MIPMAP_NEAREST: return tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST;
+ case gl.LINEAR_MIPMAP_LINEAR: return tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR;
+ default:
+ throw new Error("Can't map GL filter mode" + filterMode);
+ }
+};
+
+/* TODO: Port the code below */
+// /*--------------------------------------------------------------------*//*!
+// * \brief Map GL sampler parameters to tcu::Sampler.
+// *
+// * If no mapping is found, throws tcu::InternalError.
+// *
+// * \param wrapS S-component wrap mode
+// * \param minFilter Minification filter mode
+// * \param magFilter Magnification filter mode
+// * \return Sampler description.
+// *//*--------------------------------------------------------------------*/
+// /*tcu::Sampler mapGLSamplerWrapS (deUint32 wrapS, deUint32 minFilter, deUint32 magFilter)
+// {
+// return mapGLSampler(wrapS, wrapS, wrapS, minFilter, magFilter);
+// }
+// */
+
+/**
+ * Map GL sampler parameters to tcu::Sampler.
+ *
+ * If no mapping is found, throws tcu::InternalError.
+ *
+ * @param {number} wrapS S-component wrap mode
+ * @param {number} wrapT T-component wrap mode
+ * @param {number} minFilter Minification filter mode
+ * @param {number} magFilter Magnification filter mode
+ * @return {tcuTexture.Sampler}
+ */
+gluTextureUtil.mapGLSamplerWrapST = function(wrapS, wrapT, minFilter, magFilter) {
+ return gluTextureUtil.mapGLSampler(wrapS, wrapT, wrapS, minFilter, magFilter);
+};
+
+/**
+ * Map GL sampler parameters to tcu::Sampler.
+ *
+ * If no mapping is found, throws tcu::InternalError.
+ * @param {number} wrapS S-component wrap mode
+ * @param {number} wrapT T-component wrap mode
+ * @param {number} wrapR R-component wrap mode
+ * @param {number} minFilter Minification filter mode
+ * @param {number} magFilter Magnification filter mode
+ * @return {tcuTexture.Sampler}
+ */
+gluTextureUtil.mapGLSampler = function(wrapS, wrapT, wrapR, minFilter, magFilter) {
+ return new tcuTexture.Sampler(
+ gluTextureUtil.mapGLWrapMode(wrapS),
+ gluTextureUtil.mapGLWrapMode(wrapT),
+ gluTextureUtil.mapGLWrapMode(wrapR),
+ gluTextureUtil.mapGLFilterMode(minFilter),
+ gluTextureUtil.mapGLFilterMode(magFilter),
+ 0.0,
+ true,
+ tcuTexture.CompareMode.COMPAREMODE_NONE,
+ 0,
+ [0.0, 0.0, 0.0, 0.0]);
+};
+
+// /*--------------------------------------------------------------------*//*!
+// * \brief Map GL compare function to tcu::Sampler::CompareMode.
+// *
+// * If no mapping is found, throws tcu::InternalError.
+// *
+// * \param mode GL compare mode
+// * \return Compare mode
+// *//*--------------------------------------------------------------------*/
+/**
+ * @param {number} mode
+ */
+gluTextureUtil.mapGLCompareFunc = function(mode) {
+ switch (mode) {
+ case gl.LESS: return tcuTexture.CompareMode.COMPAREMODE_LESS;
+ case gl.LEQUAL: return tcuTexture.CompareMode.COMPAREMODE_LESS_OR_EQUAL;
+ case gl.GREATER: return tcuTexture.CompareMode.COMPAREMODE_GREATER;
+ case gl.GEQUAL: return tcuTexture.CompareMode.COMPAREMODE_GREATER_OR_EQUAL;
+ case gl.EQUAL: return tcuTexture.CompareMode.COMPAREMODE_EQUAL;
+ case gl.NOTEQUAL: return tcuTexture.CompareMode.COMPAREMODE_NOT_EQUAL;
+ case gl.ALWAYS: return tcuTexture.CompareMode.COMPAREMODE_ALWAYS;
+ case gl.NEVER: return tcuTexture.CompareMode.COMPAREMODE_NEVER;
+ default:
+ throw new Error("Can't map GL compare mode " + mode);
+ }
+};
+
+/**
+ * Get GL wrap mode.
+ *
+ * If no mapping is found, throws tcu::InternalError.
+ *
+ * @param {tcuTexture.WrapMode} wrapMode
+ * @return {number} GL wrap mode
+ */
+gluTextureUtil.getGLWrapMode = function(wrapMode) {
+ switch (wrapMode) {
+ case tcuTexture.WrapMode.CLAMP_TO_EDGE: return gl.CLAMP_TO_EDGE;
+ case tcuTexture.WrapMode.REPEAT_GL: return gl.REPEAT;
+ case tcuTexture.WrapMode.MIRRORED_REPEAT_GL: return gl.MIRRORED_REPEAT;
+ default:
+ throw new Error("Can't map wrap mode");
+ }
+};
+
+/**
+ * Get GL filter mode.
+ *
+ * If no mapping is found, throws tcu::InternalError.
+ *
+ * @param {tcuTexture.FilterMode} filterMode Filter mode
+ * @return {number} GL filter mode
+ */
+gluTextureUtil.getGLFilterMode = function(filterMode) {
+ switch (filterMode) {
+ case tcuTexture.FilterMode.NEAREST: return gl.NEAREST;
+ case tcuTexture.FilterMode.LINEAR: return gl.LINEAR;
+ case tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST: return gl.NEAREST_MIPMAP_NEAREST;
+ case tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR: return gl.NEAREST_MIPMAP_LINEAR;
+ case tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST: return gl.LINEAR_MIPMAP_NEAREST;
+ case tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR: return gl.LINEAR_MIPMAP_LINEAR;
+ default:
+ throw new Error("Can't map filter mode");
+ }
+};
+
+/**
+ * Get GL compare mode.
+ *
+ * If no mapping is found, throws tcu::InternalError.
+ *
+ * @param {tcuTexture.CompareMode} compareMode Compare mode
+ * @return {number} GL compare mode
+ */
+gluTextureUtil.getGLCompareFunc = function(compareMode) {
+ switch (compareMode) {
+ case tcuTexture.CompareMode.COMPAREMODE_NONE: return gl.NONE;
+ case tcuTexture.CompareMode.COMPAREMODE_LESS: return gl.LESS;
+ case tcuTexture.CompareMode.COMPAREMODE_LESS_OR_EQUAL: return gl.LEQUAL;
+ case tcuTexture.CompareMode.COMPAREMODE_GREATER: return gl.GREATER;
+ case tcuTexture.CompareMode.COMPAREMODE_GREATER_OR_EQUAL: return gl.GEQUAL;
+ case tcuTexture.CompareMode.COMPAREMODE_EQUAL: return gl.EQUAL;
+ case tcuTexture.CompareMode.COMPAREMODE_NOT_EQUAL: return gl.NOTEQUAL;
+ case tcuTexture.CompareMode.COMPAREMODE_ALWAYS: return gl.ALWAYS;
+ case tcuTexture.CompareMode.COMPAREMODE_NEVER: return gl.NEVER;
+ default:
+ throw new Error("Can't map compare mode");
+ }
+};
+
+/**
+ * Get GL cube face.
+ *
+ * If no mapping is found, throws tcu::InternalError.
+ *
+ * @param {tcuTexture.CubeFace} face Cube face
+ * @return {number} GL cube face
+ */
+gluTextureUtil.getGLCubeFace = function(face) {
+ switch (face) {
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X:
+ return gl.TEXTURE_CUBE_MAP_NEGATIVE_X;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_X:
+ return gl.TEXTURE_CUBE_MAP_POSITIVE_X;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y:
+ return gl.TEXTURE_CUBE_MAP_NEGATIVE_Y;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y:
+ return gl.TEXTURE_CUBE_MAP_POSITIVE_Y;
+ case tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z:
+ return gl.TEXTURE_CUBE_MAP_NEGATIVE_Z;
+ case tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z:
+ return gl.TEXTURE_CUBE_MAP_POSITIVE_Z;
+ default:
+ throw Error("Can't map cube face");
+ }
+};
+
+// /*--------------------------------------------------------------------*//*!
+// * \brief Get GLSL sampler type for texture format.
+// *
+// * If no mapping is found, glu::TYPE_LAST is returned.
+// *
+// * \param format Texture format
+// * \return GLSL 1D sampler type for format
+// *//*--------------------------------------------------------------------*/
+// DataType getSampler1DType (tcu::TextureFormat format)
+// {
+// using tcu::TextureFormat;
+
+// if (format.order == tcuTexture.ChannelOrder.D || format.order == tcuTexture.ChannelOrder.DS)
+// return TYPE_SAMPLER_1D;
+
+// if (format.order == tcuTexture.ChannelOrder.S)
+// return TYPE_LAST;
+
+// switch (tcu::getTextureChannelClass(format.type))
+// {
+// case tcu::TEXTURECHANNELCLASS_FLOATING_POINT:
+// case tcu::TEXTURECHANNELCLASS_SIGNED_FIXED_POINT:
+// case tcu::TEXTURECHANNELCLASS_UNSIGNED_FIXED_POINT:
+// return glu::TYPE_SAMPLER_1D;
+
+// case tcu::TEXTURECHANNELCLASS_SIGNED_INTEGER:
+// return glu::TYPE_INT_SAMPLER_1D;
+
+// case tcu::TEXTURECHANNELCLASS_UNSIGNED_INTEGER:
+// return glu::TYPE_UINT_SAMPLER_1D;
+
+// default:
+// return glu::TYPE_LAST;
+// }
+// }
+
+/**
+ * Get GLSL sampler type for texture format.
+ * If no mapping is found, glu::TYPE_LAST is returned.
+ *
+ * @param {tcuTexture.TextureFormat} format
+ * @return {gluShaderUtil.DataType} GLSL 2D sampler type for format
+ */
+gluTextureUtil.getSampler2DType = function(format) {
+ if (format.order == tcuTexture.ChannelOrder.D || format.order == tcuTexture.ChannelOrder.DS)
+ return gluShaderUtil.DataType.SAMPLER_2D;
+
+ if (format.order == tcuTexture.ChannelOrder.S)
+ return /** @type {gluShaderUtil.DataType} */ (Object.keys(gluShaderUtil.DataType).length);
+
+ switch (tcuTexture.getTextureChannelClass(format.type)) {
+ case tcuTexture.TextureChannelClass.FLOATING_POINT:
+ case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT:
+ case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT:
+ return gluShaderUtil.DataType.SAMPLER_2D;
+
+ case tcuTexture.TextureChannelClass.SIGNED_INTEGER:
+ return gluShaderUtil.DataType.INT_SAMPLER_2D;
+
+ case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER:
+ return gluShaderUtil.DataType.UINT_SAMPLER_2D;
+
+ default:
+ return /** @type {gluShaderUtil.DataType} */ (Object.keys(gluShaderUtil.DataType).length);
+ }
+};
+
+/**
+ *
+ * @param {tcuTexture.TextureFormat} format
+ * @return {gluShaderUtil.DataType} GLSL 2D sampler type for format
+ */
+gluTextureUtil.getSampler3DType = function(format) {
+ if (format.order === tcuTexture.ChannelOrder.D || format.order === tcuTexture.ChannelOrder.DS)
+ return gluShaderUtil.DataType.SAMPLER_3D;
+
+ if (format.order === tcuTexture.ChannelOrder.S)
+ return /** @type {gluShaderUtil.DataType} */ (Object.keys(gluShaderUtil.DataType).length); // shouldn't we throw an error instead?
+
+ switch (tcuTexture.getTextureChannelClass(format.type)) {
+ case tcuTexture.TextureChannelClass.FLOATING_POINT:
+ case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT:
+ case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT:
+ return gluShaderUtil.DataType.SAMPLER_3D;
+
+ case tcuTexture.TextureChannelClass.SIGNED_INTEGER:
+ return gluShaderUtil.DataType.INT_SAMPLER_3D;
+
+ case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER:
+ return gluShaderUtil.DataType.UINT_SAMPLER_3D;
+
+ default:
+ return /** @type {gluShaderUtil.DataType} */ (Object.keys(gluShaderUtil.DataType).length);
+ }
+};
+
+/**
+ * \brief Get GLSL sampler type for texture format.
+ *
+ * @param {tcuTexture.TextureFormat} format
+ * @return {gluShaderUtil.DataType} GLSL 2D sampler type for format
+ */
+gluTextureUtil.getSamplerCubeType = function(format) {
+ if (format.order == tcuTexture.ChannelOrder.D || format.order == tcuTexture.ChannelOrder.DS)
+ return gluShaderUtil.DataType.SAMPLER_CUBE;
+
+ if (format.order == tcuTexture.ChannelOrder.S)
+ throw new Error('No cube sampler');
+
+ switch (tcuTexture.getTextureChannelClass(format.type)) {
+ case tcuTexture.TextureChannelClass.FLOATING_POINT:
+ case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT:
+ case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT:
+ return gluShaderUtil.DataType.SAMPLER_CUBE;
+
+ case tcuTexture.TextureChannelClass.SIGNED_INTEGER:
+ return gluShaderUtil.DataType.INT_SAMPLER_CUBE;
+
+ case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER:
+ return gluShaderUtil.DataType.UINT_SAMPLER_CUBE;
+
+ default:
+ throw new Error('No cube sampler');
+ }
+};
+
+/**
+ * \brief Get GLSL sampler type for texture format.
+ *
+ * If no mapping is found, glu::TYPE_LAST is returned.
+ *
+ * @param {tcuTexture.TextureFormat} format
+ * @return {gluShaderUtil.DataType} GLSL 2D sampler type for format
+ */
+gluTextureUtil.getSampler2DArrayType = function(format) {
+
+ if (format.order == tcuTexture.ChannelOrder.D || format.order == tcuTexture.ChannelOrder.DS)
+ return gluShaderUtil.DataType.SAMPLER_2D_ARRAY;
+
+ if (format.order == tcuTexture.ChannelOrder.S)
+ throw new Error('No 2d array sampler');
+
+ switch (tcuTexture.getTextureChannelClass(format.type)) {
+ case tcuTexture.TextureChannelClass.FLOATING_POINT:
+ case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT:
+ case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT:
+ return gluShaderUtil.DataType.SAMPLER_2D_ARRAY;
+
+ case tcuTexture.TextureChannelClass.SIGNED_INTEGER:
+ return gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY;
+
+ case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER:
+ return gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY;
+
+ default:
+ throw new Error('No 2d array sampler');
+ }
+};
+
+/**
+ * \brief Get GLSL sampler type for texture format.
+ *
+ * If no mapping is found, glu::TYPE_LAST is returned.
+ *
+ * @param {tcuTexture.TextureFormat} format
+ * @return {gluShaderUtil.DataType} GLSL 2D sampler type for format
+ */
+gluTextureUtil.getSampler3D = function(format) {
+ if (format.order == tcuTexture.ChannelOrder.D || format.order == tcuTexture.ChannelOrder.DS)
+ return gluShaderUtil.DataType.SAMPLER_3D;
+
+ if (format.order == tcuTexture.ChannelOrder.S)
+ throw new Error('No 3d sampler');
+
+ switch (tcuTexture.getTextureChannelClass(format.type)) {
+ case tcuTexture.TextureChannelClass.FLOATING_POINT:
+ case tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT:
+ case tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT:
+ return gluShaderUtil.DataType.SAMPLER_3D;
+
+ case tcuTexture.TextureChannelClass.SIGNED_INTEGER:
+ return gluShaderUtil.DataType.INT_SAMPLER_3D;
+
+ case tcuTexture.TextureChannelClass.UNSIGNED_INTEGER:
+ return gluShaderUtil.DataType.UINT_SAMPLER_3D;
+
+ default:
+ throw new Error('No 3d sampler');
+ }
+};
+
+gluTextureUtil.RenderableType = {
+ RENDERABLE_COLOR: (1<<0),
+ RENDERABLE_DEPTH: (1<<1),
+ RENDERABLE_STENCIL: (1<<2)
+};
+
+/**
+ * \brief Get renderable bits.
+ * \note Works currently only on ES3 context.
+ *
+ * @param {number} internalFormat
+ * @return {gluTextureUtil.RenderableType}
+ */
+gluTextureUtil.getRenderableBitsES3 = function(internalFormat)
+{
+ switch (internalFormat)
+ {
+ // Color-renderable formats
+ case gl.RGBA32I:
+ case gl.RGBA32UI:
+ case gl.RGBA16I:
+ case gl.RGBA16UI:
+ case gl.RGBA8:
+ case gl.RGBA8I:
+ case gl.RGBA8UI:
+ case gl.SRGB8_ALPHA8:
+ case gl.RGB10_A2:
+ case gl.RGB10_A2UI:
+ case gl.RGBA4:
+ case gl.RGB5_A1:
+ case gl.RGB8:
+ case gl.RGB565:
+ case gl.RG32I:
+ case gl.RG32UI:
+ case gl.RG16I:
+ case gl.RG16UI:
+ case gl.RG8:
+ case gl.RG8I:
+ case gl.RG8UI:
+ case gl.R32I:
+ case gl.R32UI:
+ case gl.R16I:
+ case gl.R16UI:
+ case gl.R8:
+ case gl.R8I:
+ case gl.R8UI:
+ return gluTextureUtil.RenderableType.RENDERABLE_COLOR;
+
+ // EXT_color_buffer_float
+ case gl.RGBA32F:
+ case gl.R11F_G11F_B10F:
+ case gl.RG32F:
+ case gl.R32F:
+ case gl.RGBA16F:
+ case gl.RG16F:
+ case gl.R16F:
+ if (gl.getExtension("EXT_color_buffer_float"))
+ return gluTextureUtil.RenderableType.RENDERABLE_COLOR;
+ else
+ return 0;
+
+ // Depth formats
+ case gl.DEPTH_COMPONENT32F:
+ case gl.DEPTH_COMPONENT24:
+ case gl.DEPTH_COMPONENT16:
+ return gluTextureUtil.RenderableType.RENDERABLE_DEPTH;
+
+ // Depth+stencil formats
+ case gl.DEPTH32F_STENCIL8:
+ case gl.DEPTH24_STENCIL8:
+ return gluTextureUtil.RenderableType.RENDERABLE_DEPTH | gluTextureUtil.RenderableType.RENDERABLE_STENCIL;
+
+ // Stencil formats
+ case gl.STENCIL_INDEX8:
+ return gluTextureUtil.RenderableType.RENDERABLE_STENCIL;
+
+ default:
+ return 0;
+ }
+}
+
+/**
+ * \brief Check if sized internal format is color-renderable.
+ * \note Works currently only on ES3 context.
+ *
+ * @param {number} sizedFormat
+ * @return {boolean}
+ */
+gluTextureUtil.isSizedFormatColorRenderable = function(sizedFormat)
+{
+ var renderable = 0;
+ renderable = gluTextureUtil.getRenderableBitsES3(sizedFormat);
+ return (renderable & gluTextureUtil.RenderableType.RENDERABLE_COLOR) != 0;
+}
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarType.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarType.js
new file mode 100644
index 0000000000..a05f1c1e5c
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarType.js
@@ -0,0 +1,814 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('framework.opengl.gluVarType');
+goog.require('framework.opengl.gluShaderUtil');
+
+goog.scope(function() {
+
+ var gluVarType = framework.opengl.gluVarType;
+ var gluShaderUtil = framework.opengl.gluShaderUtil;
+
+ /**
+ * gluVarType.VarType types enum
+ * @enum {number}
+ */
+ gluVarType.Type = {
+ TYPE_BASIC: 0,
+ TYPE_ARRAY: 1,
+ TYPE_STRUCT: 2
+ };
+
+ /**
+ * gluVarType.TypeArray struct
+ * @param {gluVarType.VarType} elementType
+ * @param {number} arraySize
+ * @constructor
+ */
+ gluVarType.TypeArray = function(elementType, arraySize) {
+ /** @type {gluVarType.VarType} */ this.elementType = gluVarType.newClone(elementType);
+ /** @type {number} */ this.size = arraySize;
+ };
+
+ /**
+ * gluVarType.VarType class
+ * @constructor
+ */
+ gluVarType.VarType = function() {
+ /**
+ * @type {gluShaderUtil.precision}
+ * @private
+ */
+ this.m_flags;
+
+ /**
+ * @type {number}
+ * @private
+ */
+ this.m_type = -1;
+
+ /**
+ * m_data used to be a 'Data' union in C++. Using a var is enough here.
+ * it will contain any necessary value.
+ * case TYPE_BASIC: number
+ * case TYPE_ARRAY: gluVarType.TypeArray
+ * case TYPE_STRUCT: gluVarType.StructType
+ * @private
+ * @type {(number|gluVarType.TypeArray|gluVarType.StructType)}
+ */
+ this.m_data = null;
+ };
+
+ gluVarType.VarType.UNSIZED_ARRAY = -1;
+
+ /**
+ * Creates a basic type gluVarType.VarType. Use this after the constructor call.
+ * @param {number} basicType
+ * @param {gluShaderUtil.precision} flags
+ * @return {gluVarType.VarType} The currently modified object
+ */
+ gluVarType.VarType.prototype.VarTypeBasic = function(basicType, flags) {
+ this.m_type = gluVarType.Type.TYPE_BASIC;
+ this.m_flags = flags;
+ this.m_data = basicType;
+
+ return this;
+ };
+
+ /**
+ * Creates a basic type gluVarType.VarType with type boolean and undefined precision.
+ * @param {number} basicType
+ * @return {gluVarType.VarType} The currently modified object
+ */
+ gluVarType.VarType.prototype.VarTypeBoolean = function(basicType) {
+ this.m_type = gluVarType.Type.TYPE_BASIC;
+ this.m_data = basicType;
+
+ return this;
+ };
+
+ /**
+ * Creates an array type gluVarType.VarType. Use this after the constructor call.
+ * @param {gluVarType.VarType} elementType
+ * @param {number} arraySize
+ * @return {gluVarType.VarType} The currently modified object
+ */
+ gluVarType.VarType.prototype.VarTypeArray = function(elementType, arraySize) {
+ this.m_type = gluVarType.Type.TYPE_ARRAY;
+ if (!(arraySize >= 0 || arraySize == gluVarType.VarType.UNSIZED_ARRAY))
+ throw new Error('Illegal array size: ' + arraySize);
+ this.m_data = new gluVarType.TypeArray(elementType, arraySize);
+
+ return this;
+ };
+
+ /**
+ * Creates a struct type gluVarType.VarType. Use this after the constructor call.
+ * @param {gluVarType.StructType} structPtr
+ * @return {gluVarType.VarType} The currently modified object
+ */
+ gluVarType.VarType.prototype.VarTypeStruct = function(structPtr) {
+ this.m_type = gluVarType.Type.TYPE_STRUCT;
+ this.m_data = structPtr;
+
+ return this;
+ };
+
+ /**
+ * Creates a gluVarType.VarType, the same type as the passed in object.
+ * Use this after the constructor call.
+ * @param {gluVarType.VarType} object
+ * @return {gluVarType.VarType} The currently modified object
+ */
+ gluVarType.VarType.prototype.VarTypeClone = function(object) {
+
+ this.m_type = object.m_type;
+
+ switch (this.m_type) {
+ case gluVarType.Type.TYPE_BASIC:
+ this.m_flags = object.m_flags;
+ this.m_data = object.m_data;
+ break;
+ case gluVarType.Type.TYPE_BASIC:
+ this.m_data = new gluVarType.TypeArray(object.m_data.elementType, object.m_data.size);
+ break;
+ case gluVarType.Type.TYPE_STRUCT:
+ this.m_data = object.m_data;
+ break;
+ default:
+ throw new Error('unknown type: ' + this.m_type);
+ }
+
+ return this;
+ };
+
+ /** isBasicType
+ * @return {boolean} true if the gluVarType.VarType represents a basic type.
+ */
+ gluVarType.VarType.prototype.isBasicType = function() {
+ return this.m_type == gluVarType.Type.TYPE_BASIC;
+ };
+
+ /** isArrayType
+ * @return {boolean} true if the gluVarType.VarType represents an array.
+ */
+ gluVarType.VarType.prototype.isArrayType = function() {
+ return this.m_type == gluVarType.Type.TYPE_ARRAY;
+ };
+
+ /** isStructType
+ * @return {boolean} true if the gluVarType.VarType represents a struct.
+ */
+ gluVarType.VarType.prototype.isStructType = function() {
+ return this.m_type == gluVarType.Type.TYPE_STRUCT;
+ };
+
+ /** getFlags
+ * @return {number} returns the flags of the gluVarType.VarType.
+ */
+ gluVarType.VarType.prototype.getFlags = function() {
+ return this.m_flags;
+ };
+
+ /** getBasicType
+ * @return {gluShaderUtil.DataType<number>} returns the basic data type of the gluVarType.VarType.
+ */
+ gluVarType.VarType.prototype.getBasicType = function() {
+ if (!this.isBasicType())
+ throw new Error('VarType is not a basic type.');
+ return /** @type {gluShaderUtil.DataType<number>} */ (this.m_data);
+ };
+
+ /** getPrecision
+ * @return {gluShaderUtil.precision} returns the precision flag.
+ */
+ gluVarType.VarType.prototype.getPrecision = function() {
+ if (!this.isBasicType())
+ throw new Error('VarType is not a basic type.');
+ return this.m_flags;
+ };
+
+ /** getElementType
+ * @return {gluVarType.VarType} returns the gluVarType.VarType of the element in case of an Array.
+ */
+ gluVarType.VarType.prototype.getElementType = function() {
+ if (!this.isArrayType())
+ throw new Error('VarType is not an array type.');
+ return this.m_data.elementType;
+ };
+
+ /** getArraySize
+ * (not to be confused with a javascript array)
+ * @return {number} returns the size of the array in case it is an array.
+ */
+ gluVarType.VarType.prototype.getArraySize = function() {
+ if (!this.isArrayType())
+ throw new Error('VarType is not an array type.');
+ return this.m_data.size;
+ };
+
+ /** getStruct
+ * @return {gluVarType.StructType} returns the structure when it is a gluVarType.StructType.
+ */
+ gluVarType.VarType.prototype.getStruct = function() {
+ if (!this.isStructType())
+ throw new Error('VarType is not a struct type.');
+ return /** @type {gluVarType.StructType} */ (this.m_data);
+ };
+
+ /**
+ * getScalarSize
+ * @return {number} size of the scalar
+ */
+ gluVarType.VarType.prototype.getScalarSize = function() {
+ switch (this.m_type) {
+ case gluVarType.Type.TYPE_BASIC: {
+ return gluShaderUtil.getDataTypeScalarSize(/** @type {gluShaderUtil.DataType} */(this.getBasicType()));
+ }
+
+ // TODO: check implementation below: return m_data.array.elementType->getScalarSize()*m_data.array.size;
+ case gluVarType.Type.TYPE_ARRAY: {
+ var m_data = /** @type {gluVarType.TypeArray} */(this.m_data);
+ return m_data.elementType.getScalarSize() * m_data.size;
+ }
+
+ case gluVarType.Type.TYPE_STRUCT: {
+ var size = 0;
+
+ var struct = /** @type {gluVarType.StructType} */ (this.m_data);
+
+ // TODO: check loop conditions below
+ // for (gluVarType.StructType::ConstIterator iter = m_data.structPtr->begin(); iter != m_data.structPtr->end(); iter++)
+ for (var iter = 0; struct.m_members[iter] < struct.getSize(); iter++)
+ size += struct.getMember(iter).m_type.getScalarSize();
+ return size;
+ }
+
+ default:
+ // throw new Error('Unexpected type.');
+ return 0;
+ }
+ };
+
+ /**
+ * is
+ * @return {boolean} returns true if the current object is equivalent to other.
+ */
+ gluVarType.VarType.prototype.is = function(other) {
+ if (this.m_type != other.m_type)
+ return false;
+
+ switch (this.m_type) {
+ case gluVarType.Type.TYPE_BASIC:
+ return this.m_data == other.m_data &&
+ this.m_flags == other.m_flags;
+
+ case gluVarType.Type.TYPE_ARRAY:
+ return this.m_data.elementType == other.m_data.elementType &&
+ this.m_data.size == other.m_data.size;
+
+ case gluVarType.Type.TYPE_STRUCT:
+ return this.m_data === other.m_data;
+
+ default:
+ // throw new Error('Unexpected type.');
+ return false;
+ }
+ };
+
+ /**
+ * isnt
+ * @return {boolean} returns true if the current object is not equivalent to other.
+ */
+ gluVarType.VarType.prototype.isnt = function(other) {
+ return !(this.is(other));
+ };
+
+ /**
+ * Creates a basic type gluVarType.VarType.
+ * @param {gluShaderUtil.DataType} basicType
+ * @param {framework.opengl.gluShaderUtil.precision=} flags
+ * @return {gluVarType.VarType}
+ */
+ gluVarType.newTypeBasic = function(basicType, flags) {
+ if (!gluShaderUtil.isDataTypeBoolOrBVec(basicType))
+ return new gluVarType.VarType().VarTypeBasic(basicType, /** @type {framework.opengl.gluShaderUtil.precision}*/ (flags));
+ else
+ return new gluVarType.VarType().VarTypeBoolean(basicType);
+ };
+
+ /**
+ * Creates an array type gluVarType.VarType.
+ * @param {gluVarType.VarType} elementType
+ * @param {number} arraySize
+ * @return {gluVarType.VarType}
+ */
+ gluVarType.newTypeArray = function(elementType, arraySize) {
+ return new gluVarType.VarType().VarTypeArray(elementType, arraySize);
+ };
+
+ /**
+ * Creates a struct type gluVarType.VarType.
+ * @param {gluVarType.StructType} structPtr
+ * @return {gluVarType.VarType}
+ */
+ gluVarType.newTypeStruct = function(structPtr) {
+ return new gluVarType.VarType().VarTypeStruct(structPtr);
+ };
+
+ /**
+ * Creates a struct type gluVarType.VarType.
+ * @param {gluVarType.VarType} object
+ * @return {gluVarType.VarType}
+ */
+ gluVarType.newClone = function(object) {
+ return new gluVarType.VarType().VarTypeClone(object);
+ };
+
+ /**
+ * gluVarType.StructMember class
+ * @constructor
+ */
+ gluVarType.StructMember = function() {
+ /** @type {string} */ this.m_name;
+ /** @type {gluVarType.VarType} */ this.m_type;
+ /** @type {number} */ // this.m_flags = 0; // only in glsUniformBlockCase
+ };
+
+ /**
+ * Creates a gluVarType.StructMember. Use this after the constructor call.
+ * @param {string} name
+ * @param {gluVarType.VarType} type
+ * @return {gluVarType.StructMember} The currently modified object
+ */
+ gluVarType.StructMember.prototype.Constructor = function(name, type) {
+ this.m_type = type;
+ this.m_name = name;
+
+ return this;
+ };
+
+ /** getName
+ * @return {string} name of the gluVarType.StructMember object.
+ */
+ gluVarType.StructMember.prototype.getName = function() {
+ return this.m_name;
+ };
+
+ /** getType
+ * @return {gluVarType.VarType} type of the gluVarType.StructMember object.
+ */
+ gluVarType.StructMember.prototype.getType = function() {
+ return this.m_type;
+ };
+
+ /**
+ * Creates a gluVarType.StructMember.
+ * @param {string} name
+ * @param {gluVarType.VarType} type
+ * @return {gluVarType.StructMember}
+ */
+ gluVarType.newStructMember = function(name, type) {
+ return new gluVarType.StructMember().Constructor(name, type);
+ };
+
+ /**
+ * gluVarType.StructType class
+ * @constructor
+ */
+ gluVarType.StructType = function() {
+ /** @type {string} */ this.m_typeName = '';
+ /** @type {Array<gluVarType.StructMember>} */ this.m_members = [];
+ };
+
+ /**
+ * Creates a gluVarType.StructType. Use this after the constructor call.
+ * @param {string} name
+ * @return {gluVarType.StructType} The currently modified object
+ */
+ gluVarType.StructType.prototype.Constructor = function(name) {
+ /** @type {string}*/ this.m_typeName = this.setTypeName(name);
+ return this;
+ };
+
+ /** hasTypeName
+ * Checks if the gluVarType.StructType m_typeName is defined
+ * @return {boolean}
+ */
+ gluVarType.StructType.prototype.hasTypeName = function() {
+ return (this.m_typeName !== 'undefined');
+ };
+
+ /** setTypeName
+ * @param {string} name
+ * @return {string} returns gluVarType.StructType.m_typeName
+ */
+ gluVarType.StructType.prototype.setTypeName = function(name) {
+ return this.m_typeName = name;
+ };
+
+ /** getTypeName
+ * @return {string}
+ */
+ gluVarType.StructType.prototype.getTypeName = function() {
+ return this.m_typeName;
+ };
+
+ /** getNumMembers
+ * @return {number}
+ */
+ gluVarType.StructType.prototype.getNumMembers = function() {
+ return this.m_members.length;
+ };
+
+ /** getMember
+ * @param {number} memberNdx The index of the member to retrieve.
+ * @return {gluVarType.StructMember}
+ */
+ gluVarType.StructType.prototype.getMember = function(memberNdx) {
+ if (memberNdx >= 0 && memberNdx < this.m_members.length)
+ return this.m_members[memberNdx];
+ else {
+ throw new Error('Invalid member index for StructTypes members');
+ }
+ };
+
+ /** getSize
+ * @return {number} The size of the m_members array.
+ */
+ gluVarType.StructType.prototype.getSize = function() {
+ return this.m_members.length;
+ };
+
+ /** addMember
+ * @param {string} name
+ * @param {gluVarType.VarType} type
+ */
+ gluVarType.StructType.prototype.addMember = function(name, type) {
+ var member = gluVarType.newStructMember(name, type);
+ this.m_members.push(member);
+ };
+
+ /**
+ * Creates a gluVarType.StructType.
+ * @param {string} name
+ * @return {gluVarType.StructType}
+ */
+ gluVarType.newStructType = function(name) {
+ return new gluVarType.StructType().Constructor(name);
+ };
+
+ /**
+ * @param {number} level
+ * @return {string}
+ */
+ gluVarType.indent = function(level) {
+ /** @type {string} */ var str = '';
+ for (var i = 0; i < level; i++)
+ str += '\t';
+ return str;
+ };
+
+ /**
+ * @param {gluVarType.VarType} varType
+ * @param {string} name
+ * @param {number=} level
+ * @return {string}
+ */
+ gluVarType.declareVariable = function(varType, name, level) {
+ /** @type {string} */ var str = '';
+ /** @type {gluVarType.VarType} */ var type = varType;
+ /** @type {gluVarType.VarType} */ var curType = type;
+ /** @type {Array<number>} */ var arraySizes = [];
+
+ // Handle arrays.
+ while (curType.isArrayType()) {
+ arraySizes.push(curType.getArraySize());
+ curType = curType.getElementType();
+ }
+
+ if (curType.isBasicType()) {
+ if (curType.getPrecision() !== undefined)
+ str += gluShaderUtil.getPrecisionName(curType.getPrecision()) + ' ';
+ str += gluShaderUtil.getDataTypeName(/** @type {gluShaderUtil.DataType} */(curType.getBasicType()));
+ } else if (curType.isStructType()) {
+ /** @type {gluVarType.StructType} */ var structPtr = curType.getStruct();
+
+ if (structPtr.hasTypeName())
+ str += structPtr.getTypeName();
+ else
+ str += gluVarType.declareStructType(structPtr, level); // Generate inline declaration.
+ } else
+ throw new Error('Unexpected Array typed VarType.');
+
+ str += ' ' + name;
+
+ // Print array sizes.
+ for (var size = 0; size < arraySizes.length; size++) { //std::vector<int>::const_iterator sizeIter = arraySizes.begin(); sizeIter != arraySizes.end(); sizeIter++) {
+ /** @type {number} */ var arrSize = arraySizes[size];
+ if (arrSize == gluVarType.VarType.UNSIZED_ARRAY)
+ str += '[]';
+ else
+ str += '[' + arrSize + ']';
+ }
+
+ return str;
+ };
+
+ /**
+ * @param {gluVarType.StructType} structType
+ * @param {number=} level
+ * @return {string}
+ */
+ gluVarType.declareStructType = function(structType, level) {
+ /** @type {string} */ var str = 'struct';
+ level = level || 0;
+
+ // gluVarType.Type name is optional.
+ if (structType.hasTypeName())
+ str += ' ' + structType.getTypeName();
+
+ str += '\n' + gluVarType.indent(level) + ' {\n';
+
+ for (var memberNdx = 0; memberNdx < structType.getSize(); memberNdx++) { //gluVarType.StructType::ConstIterator memberIter = decl.structPtr->begin(); memberIter != decl.structPtr->end(); memberIter++) {
+ /** @type {gluVarType.StructMember} */ var memberIter = structType.getMember(memberNdx);
+ str += gluVarType.indent(level + 1);
+ str += gluVarType.declareVariable(memberIter.getType(), memberIter.getName(), level + 1) + ';\n';
+ }
+
+ str += gluVarType.indent(level) + '}';
+
+ return str;
+ };
+
+ /**
+ * @param {*} T
+ * @param {number=} size
+ * @param {gluShaderUtil.precision=} precision
+ * @return {gluVarType.VarType}
+ */
+ gluVarType.getVarTypeOf = function(T, size, precision) {
+ size = size || 1;
+ precision = precision || gluShaderUtil.precision.PRECISION_LOWP;
+ switch (size) {
+ case 4: return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC4, precision);
+ case 3: return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC3, precision);
+ case 2: return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC2, precision);
+ }
+ switch (T) {
+ case 'float' : return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT, precision);
+ case 'vec4': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC4, precision);
+ case 'vec3': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC3, precision);
+ case 'vec2': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_VEC2, precision);
+ case 'mat2': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT2, precision);
+ case 'mat2x3': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT2X3, precision);
+ case 'mat2x4': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT2X4, precision);
+ case 'mat3x2': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT3X2, precision);
+ case 'mat3': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT3, precision);
+ case 'mat3x4': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT3X4, precision);
+ case 'mat4x2': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT4X2, precision);
+ case 'mat4x3': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT4X3, precision);
+ case 'mat4': return gluVarType.newTypeBasic(gluShaderUtil.DataType.FLOAT_MAT4, precision);
+ }
+ throw new Error('Invalid input type ' + T + ' or size ' + size);
+ };
+
+ /**
+ * @enum
+ */
+ gluVarType.Storage = {
+ STORAGE_IN: 0,
+ STORAGE_OUT: 1,
+ STORAGE_CONST: 2,
+ STORAGE_UNIFORM: 3,
+ STORAGE_BUFFER: 4
+ };
+
+ /**
+ * @param {gluVarType.Storage} storage
+ * @return {string}
+ */
+ gluVarType.getStorageName = function(storage) {
+ switch (storage) {
+ case gluVarType.Storage.STORAGE_IN: return 'in';
+ case gluVarType.Storage.STORAGE_OUT: return 'out';
+ case gluVarType.Storage.STORAGE_CONST: return 'const';
+ case gluVarType.Storage.STORAGE_UNIFORM: return 'uniform';
+ case gluVarType.Storage.STORAGE_BUFFER: return 'buffer';
+ default:
+ throw new Error('Unknown storage: ' + storage);
+ }
+ };
+
+ /**
+ * @enum
+ */
+ gluVarType.Interpolation = {
+ INTERPOLATION_SMOOTH: 0,
+ INTERPOLATION_FLAT: 1,
+ INTERPOLATION_CENTROID: 2
+ };
+
+ /**
+ * @param {gluVarType.Interpolation} interpolation
+ * @return {string}
+ */
+ gluVarType.getInterpolationName = function(interpolation) {
+ switch (interpolation) {
+ case gluVarType.Interpolation.INTERPOLATION_SMOOTH: return 'smooth';
+ case gluVarType.Interpolation.INTERPOLATION_FLAT: return 'flat';
+ case gluVarType.Interpolation.INTERPOLATION_CENTROID: return 'centrod';
+ default:
+ throw new Error('Unknown interpolation: ' + interpolation);
+ }
+ };
+
+ /**
+ * @enum
+ */
+ gluVarType.FormatLayout = {
+ FORMATLAYOUT_RGBA32F: 0,
+ FORMATLAYOUT_RGBA16F: 1,
+ FORMATLAYOUT_R32F: 2,
+ FORMATLAYOUT_RGBA8: 3,
+ FORMATLAYOUT_RGBA8_SNORM: 4,
+
+ FORMATLAYOUT_RGBA32I: 5,
+ FORMATLAYOUT_RGBA16I: 6,
+ FORMATLAYOUT_RGBA8I: 7,
+ FORMATLAYOUT_R32I: 8,
+
+ FORMATLAYOUT_RGBA32UI: 9,
+ FORMATLAYOUT_RGBA16UI: 10,
+ FORMATLAYOUT_RGBA8UI: 11,
+ FORMATLAYOUT_R32UI: 12
+ };
+
+ /**
+ * @param {gluVarType.FormatLayout} layout
+ * @return {string}
+ */
+ gluVarType.getFormatLayoutName = function(layout) {
+ switch (layout) {
+ case gluVarType.FormatLayout.FORMATLAYOUT_RGBA32F: return 'rgba32f';
+ case gluVarType.FormatLayout.FORMATLAYOUT_RGBA16F: return 'rgba16f';
+ case gluVarType.FormatLayout.FORMATLAYOUT_R32F: return 'r32f';
+ case gluVarType.FormatLayout.FORMATLAYOUT_RGBA8: return 'rgba8';
+ case gluVarType.FormatLayout.FORMATLAYOUT_RGBA8_SNORM: return 'rgba8_snorm';
+ case gluVarType.FormatLayout.FORMATLAYOUT_RGBA32I: return 'rgba32i';
+ case gluVarType.FormatLayout.FORMATLAYOUT_RGBA16I: return 'rgba16i';
+ case gluVarType.FormatLayout.FORMATLAYOUT_RGBA8I: return 'rgba8i';
+ case gluVarType.FormatLayout.FORMATLAYOUT_R32I: return 'r32i';
+ case gluVarType.FormatLayout.FORMATLAYOUT_RGBA32UI: return 'rgba32ui';
+ case gluVarType.FormatLayout.FORMATLAYOUT_RGBA16UI: return 'rgba16ui';
+ case gluVarType.FormatLayout.FORMATLAYOUT_RGBA8UI: return 'rgba8ui';
+ case gluVarType.FormatLayout.FORMATLAYOUT_R32UI: return 'r32ui';
+ default:
+ throw new Error('Unknown layout: ' + layout);
+ }
+ };
+
+ /**
+ * @enum
+ */
+ gluVarType.MatrixOrder = {
+ MATRIXORDER_COLUMN_MAJOR: 0,
+ MATRIXORDER_ROW_MAJOR: 1
+ };
+
+ /**
+ * @param {gluVarType.MatrixOrder} qualifier
+ * @return {string}
+ */
+ gluVarType.getMatrixOrderName = function(qualifier) {
+ switch (qualifier) {
+ case gluVarType.MatrixOrder.MATRIXORDER_COLUMN_MAJOR: return 'column_major';
+ case gluVarType.MatrixOrder.MATRIXORDER_ROW_MAJOR: return 'row_major';
+ default:
+ throw new Error('Unknown qualifier: ' + qualifier);
+ }
+ };
+
+ gluVarType.MemoryAccessQualifier = {
+ MEMORYACCESSQUALIFIER_COHERENT_BIT: 0x01,
+ MEMORYACCESSQUALIFIER_VOLATILE_BIT: 0x02,
+ MEMORYACCESSQUALIFIER_RESTRICT_BIT: 0x04,
+ MEMORYACCESSQUALIFIER_READONLY_BIT: 0x08,
+ MEMORYACCESSQUALIFIER_WRITEONLY_BIT: 0x10
+ };
+ gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_MASK = (gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_WRITEONLY_BIT << 1) - 1;
+
+ /**
+ * @param {number} qualifier
+ * @return {string}
+ */
+ gluVarType.getMemoryAccessQualifierName = function(qualifier) {
+ switch (qualifier) {
+ case gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_COHERENT_BIT: return 'coherent';
+ case gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_VOLATILE_BIT: return 'volatile';
+ case gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_RESTRICT_BIT: return 'restrict';
+ case gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_READONLY_BIT: return 'readonly';
+ case gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_WRITEONLY_BIT: return 'writeonly';
+ default:
+ throw new Error('Unknown qualifier: ' + qualifier);
+ }
+ };
+
+ /**
+ * @constructor
+ * @param {number=} location
+ * @param {number=} binding
+ * @param {number=} offset
+ * @param {gluVarType.FormatLayout=} format
+ * @param {gluVarType.MatrixOrder=} matrixOrder
+ */
+ gluVarType.Layout = function(location, binding, offset, format, matrixOrder) {
+ this.location = location;
+ this.binding = binding;
+ this.offset = offset;
+ this.format = format;
+ this.matrixOrder = matrixOrder;
+ };
+
+ gluVarType.Layout.prototype.toString = function() {
+ var strings = [];
+ var str = '';
+ if (typeof this.location !== 'undefined')
+ strings.push('location=' + this.location);
+ if (typeof this.binding !== 'undefined')
+ strings.push('binding=' + this.binding);
+ if (typeof this.offset !== 'undefined')
+ strings.push('offset=' + this.offset);
+ if (typeof this.format !== 'undefined')
+ strings.push(gluVarType.getFormatLayoutName(this.format));
+ if (typeof this.matrixOrder !== 'undefined')
+ strings.push(gluVarType.getMatrixOrderName(this.matrixOrder));
+
+ if (strings.length > 0) {
+ str += 'layout(' + strings[0];
+
+ for (var i = 1; i < strings.length; i++)
+ str += ', ' + strings[i];
+ str += ')';
+ }
+
+ return str;
+ };
+
+ /**
+ * @constructor
+ * @param {gluVarType.VarType} varType
+ * @param {string} name
+ * @param {gluVarType.Storage=} storage
+ * @param {gluVarType.Interpolation=} interpolation
+ * @param {gluVarType.Layout=} layout
+ * @param {number=} memoryAccessQualifierBits
+ */
+ gluVarType.VariableDeclaration = function(varType, name, storage, interpolation, layout, memoryAccessQualifierBits) {
+ this.varType = varType;
+ this.name = name;
+ this.storage = storage;
+ this.interpolation = interpolation;
+ this.layout = layout;
+ this.memoryAccessQualifierBits = memoryAccessQualifierBits || 0;
+ };
+
+ gluVarType.VariableDeclaration.prototype.toString = function() {
+ var str = '';
+ if (typeof this.layout !== 'undefined')
+ str += this.layout.toString() + ' ';
+
+ for (var bitNdx = 0; (1 << bitNdx) & gluVarType.MemoryAccessQualifier.MEMORYACCESSQUALIFIER_MASK; ++bitNdx)
+ if (this.memoryAccessQualifierBits & (1 << bitNdx))
+ str += gluVarType.getMemoryAccessQualifierName((1 << bitNdx)) + ' ';
+
+ if (typeof this.interpolation !== 'undefined')
+ str += gluVarType.getInterpolationName(this.interpolation) + ' ';
+
+ if (typeof this.storage !== 'undefined')
+ str += gluVarType.getStorageName(this.storage) + ' ';
+
+ str += gluVarType.declareVariable(this.varType, this.name);
+
+ return str;
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarTypeUtil.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarTypeUtil.js
new file mode 100644
index 0000000000..30e198a606
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/gluVarTypeUtil.js
@@ -0,0 +1,693 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('framework.opengl.gluVarTypeUtil');
+goog.require('framework.opengl.gluShaderUtil');
+goog.require('framework.opengl.gluVarType');
+
+goog.scope(function() {
+
+ var gluVarTypeUtil = framework.opengl.gluVarTypeUtil;
+ var gluVarType = framework.opengl.gluVarType;
+ var gluShaderUtil = framework.opengl.gluShaderUtil;
+
+ gluVarTypeUtil.isNum = function(c) { return /^[0-9]$/.test(c); };
+ gluVarTypeUtil.isAlpha = function(c) { return /^[a-zA-Z]$/.test(c); };
+ gluVarTypeUtil.isIdentifierChar = function(c) { return /^[a-zA-Z0-9_]$/.test(c); };
+ gluVarTypeUtil.array_op_equivalent = function(arr1, arr2) {
+ if (arr1.length != arr2.length) return false;
+ for (var i = 0; i < arr1.length; ++i) {
+ if (arr1[i].isnt(arr2[1])) return false;
+ }
+ return true;
+ };
+
+ /**
+ * gluVarTypeUtil.VarTokenizer class.
+ * @param {string} str
+ * @constructor
+ */
+ gluVarTypeUtil.VarTokenizer = function(str) {
+
+ /** @private */
+ this.m_str = str;
+ /** @private */
+ this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.length;
+ /** @private */
+ this.m_tokenStart = 0;
+ /** @private */
+ this.m_tokenLen = 0;
+
+ this.advance();
+
+ };
+ gluVarTypeUtil.VarTokenizer.s_Token = {
+ IDENTIFIER: 0,
+ LEFT_BRACKET: 1,
+ RIGHT_BRACKET: 2,
+ PERIOD: 3,
+ NUMBER: 4,
+ END: 5
+ };
+ gluVarTypeUtil.VarTokenizer.s_Token.length = Object.keys(gluVarTypeUtil.VarTokenizer.s_Token).length;
+
+ gluVarTypeUtil.VarTokenizer.prototype.getToken = function() {
+ return this.m_token;
+ };
+ gluVarTypeUtil.VarTokenizer.prototype.getIdentifier = function() {
+ return this.m_str.substr(this.m_tokenStart, this.m_tokenLen);
+ };
+ gluVarTypeUtil.VarTokenizer.prototype.getNumber = function() {
+ return parseInt(this.getIdentifier(), 10);
+ };
+ gluVarTypeUtil.VarTokenizer.prototype.getCurrentTokenStartLocation = function() {
+ return this.m_tokenStart;
+ };
+ gluVarTypeUtil.VarTokenizer.prototype.getCurrentTokenEndLocation = function() {
+ return this.m_tokenStart + this.m_tokenLen;
+ };
+
+ gluVarTypeUtil.VarTokenizer.prototype.advance = function() {
+
+ if (this.m_token == gluVarTypeUtil.VarTokenizer.s_Token.END) {
+ throw new Error('No more tokens.');
+ }
+
+ this.m_tokenStart += this.m_tokenLen;
+ this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.length;
+ this.m_tokenLen = 1;
+
+ if (this.m_tokenStart >= this.m_str.length) {
+ this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.END;
+
+ } else if (this.m_str[this.m_tokenStart] == '[') {
+ this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.LEFT_BRACKET;
+
+ } else if (this.m_str[this.m_tokenStart] == ']') {
+ this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.RIGHT_BRACKET;
+
+ } else if (this.m_str[this.m_tokenStart] == '.') {
+ this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.PERIOD;
+
+ } else if (gluVarTypeUtil.isNum(this.m_str[this.m_tokenStart])) {
+ this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.NUMBER;
+ while (gluVarTypeUtil.isNum(this.m_str[this.m_tokenStart + this.m_tokenLen])) {
+ this.m_tokenLen += 1;
+ }
+
+ } else if (gluVarTypeUtil.isIdentifierChar(this.m_str[this.m_tokenStart])) {
+ this.m_token = gluVarTypeUtil.VarTokenizer.s_Token.IDENTIFIER;
+ while (gluVarTypeUtil.isIdentifierChar(this.m_str[this.m_tokenStart + this.m_tokenLen])) {
+ this.m_tokenLen += 1;
+ }
+
+ } else {
+ throw new Error('Unexpected character');
+ }
+
+ };
+
+ /**
+ * VarType subtype path utilities class.
+ * @param {gluVarTypeUtil.VarTypeComponent.s_Type} type
+ * @param {number} index
+ * @constructor
+ */
+ gluVarTypeUtil.VarTypeComponent = function(type, index) {
+ /** @type {gluVarTypeUtil.VarTypeComponent.s_Type} */ this.type = type;
+ this.index = index || 0;
+ };
+
+ gluVarTypeUtil.VarTypeComponent.prototype.is = function(other) {
+ return this.type == other.type && this.index == other.index;
+ };
+ gluVarTypeUtil.VarTypeComponent.prototype.isnt = function(other) {
+ return this.type != other.type || this.index != other.index;
+ };
+
+ /**
+ * @enum
+ */
+ gluVarTypeUtil.VarTypeComponent.s_Type = {
+ STRUCT_MEMBER: 0,
+ ARRAY_ELEMENT: 1,
+ MATRIX_COLUMN: 2,
+ VECTOR_COMPONENT: 3
+ };
+
+ /**
+ * Type path formatter.
+ * @param {gluVarType.VarType} type_
+ * @param {Array<gluVarTypeUtil.VarTypeComponent>} path_
+ * @constructor
+ */
+ gluVarTypeUtil.TypeAccessFormat = function(type_, path_) {
+ this.type = type_;
+ this.path = path_;
+ };
+
+ gluVarTypeUtil.TypeAccessFormat.prototype.toString = function() {
+ var curType = this.type;
+ var str = '';
+
+ for (var i = 0; i < this.path.length; i++) {
+ var iter = this.path[i];
+ switch (iter.type) {
+ case gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT:
+ curType = curType.getElementType(); // Update current type.
+ // Fall-through.
+
+ case gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN:
+ case gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT:
+ str += '[' + iter.index + ']';
+ break;
+
+ case gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER: {
+ var member = curType.getStruct().getMember(i);
+ str += '.' + member.getName();
+ curType = member.getType();
+ break;
+ }
+
+ default:
+ throw new Error('Unrecognized type:' + iter.type);
+ }
+ }
+
+ return str;
+ };
+
+ /** gluVarTypeUtil.SubTypeAccess
+ * @param {gluVarType.VarType} type
+ * @constructor
+ */
+ gluVarTypeUtil.SubTypeAccess = function(type) {
+
+ this.m_type = null; // VarType
+ this.m_path = []; // TypeComponentVector
+
+ };
+
+ /** @private */
+ gluVarTypeUtil.SubTypeAccess.prototype.helper = function(type, ndx) {
+ this.m_path.push(new gluVarTypeUtil.VarTypeComponent(type, ndx));
+ if (!this.isValid()) {
+ throw new Error;
+ }
+ return this;
+ };
+
+ gluVarTypeUtil.SubTypeAccess.prototype.member = function(ndx) {
+ return this.helper(gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER, ndx);
+ };
+ gluVarTypeUtil.SubTypeAccess.prototype.element = function(ndx) {
+ return this.helper(gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT, ndx);
+ };
+ gluVarTypeUtil.SubTypeAccess.prototype.column = function(ndx) {
+ return this.helper(gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN, ndx);
+ };
+ gluVarTypeUtil.SubTypeAccess.prototype.component = function(ndx) {
+ return this.helper(gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT, ndx);
+ };
+ gluVarTypeUtil.SubTypeAccess.prototype.parent = function() {
+ if (!this.m_path.length) {
+ throw new Error;
+ }
+ this.m_path.pop();
+ return this;
+ };
+
+ gluVarTypeUtil.SubTypeAccess.prototype.isValid = function() {
+ return gluVarTypeUtil.isValidTypePath(this.m_type, this.m_path);
+ };
+ gluVarTypeUtil.SubTypeAccess.prototype.getType = function() {
+ return gluVarTypeUtil.getVarType(this.m_type, this.m_path);
+ };
+ gluVarTypeUtil.SubTypeAccess.prototype.getPath = function() {
+ return this.m_path;
+ };
+ gluVarTypeUtil.SubTypeAccess.prototype.empty = function() {
+ return !this.m_path.length;
+ };
+ gluVarTypeUtil.SubTypeAccess.prototype.is = function(other) {
+ return (
+ gluVarTypeUtil.array_op_equivalent(this.m_path, other.m_path) &&
+ this.m_type.is(other.m_type)
+ );
+ };
+ gluVarTypeUtil.SubTypeAccess.prototype.isnt = function(other) {
+ return (
+ !gluVarTypeUtil.array_op_equivalent(this.m_path, other.m_path) ||
+ this.m_type.isnt(other.m_type)
+ );
+ };
+
+ /**
+ * Subtype iterator parent class.
+ * basic usage for all child classes:
+ * for (var i = new gluVarTypeUtil.BasicTypeIterator(type) ; !i.end() ; i.next()) {
+ * var j = i.getType();
+ * }
+ * @constructor
+ */
+ gluVarTypeUtil.SubTypeIterator = function(type) {
+
+ /** @private */
+ this.m_type = null; // const VarType*
+ /** @private */
+ this.m_path = []; // TypeComponentVector
+
+ if (type) {
+ this.m_type = type;
+ this.findNext();
+ }
+
+ };
+
+ gluVarTypeUtil.SubTypeIterator.prototype.isExpanded = function(type) {
+ throw new Error('This function must be overriden in child class');
+ };
+
+ /** removeTraversed
+ * @private
+ */
+ gluVarTypeUtil.SubTypeIterator.prototype.removeTraversed = function() {
+
+ while (this.m_path.length) {
+ var curComp = this.m_path[this.m_path.length - 1]; // gluVarTypeUtil.VarTypeComponent&
+ var parentType = gluVarTypeUtil.getVarType(this.m_type, this.m_path, 0, this.m_path.length - 1); // VarType
+
+ if (curComp.type == gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN) {
+ if (!gluShaderUtil.isDataTypeMatrix(parentType.getBasicType())) {
+ throw new Error('Isn\'t a matrix.');
+ }
+ if (curComp.index + 1 < gluShaderUtil.getDataTypeMatrixNumColumns(parentType.getBasicType())) {
+ break;
+ }
+
+ } else if (curComp.type == gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT) {
+ if (!gluShaderUtil.isDataTypeVector(parentType.getBasicType())) {
+ throw new Error('Isn\'t a vector.');
+ }
+ if (curComp.index + 1 < gluShaderUtil.getDataTypeScalarSize(parentType.getBasicType())) {
+ break;
+ }
+
+ } else if (curComp.type == gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT) {
+ if (!parentType.isArrayType()) {
+ throw new Error('Isn\'t an array.');
+ }
+ if (curComp.index + 1 < parentType.getArraySize()) {
+ break;
+ }
+
+ } else if (curComp.type == gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER) {
+ if (!parentType.isStructType()) {
+ throw new Error('Isn\'t a struct.');
+ }
+ if (curComp.index + 1 < parentType.getStruct().getNumMembers()) {
+ break;
+ }
+
+ }
+
+ this.m_path.pop();
+ }
+ };
+ gluVarTypeUtil.SubTypeIterator.prototype.findNext = function() {
+
+ if (this.m_path.length > 0) {
+ // Increment child counter in current level.
+ var curComp = this.m_path[this.m_path.length - 1]; // gluVarTypeUtil.VarTypeComponent&
+ curComp.index += 1;
+ }
+
+ for (;;) {
+
+ var curType = gluVarTypeUtil.getVarType(this.m_type, this.m_path); // VarType
+
+ if (this.isExpanded(curType))
+ break;
+
+ // Recurse into child type.
+ if (curType.isBasicType()) {
+ var basicType = curType.getBasicType(); // DataType
+
+ if (gluShaderUtil.isDataTypeMatrix(basicType)) {
+ this.m_path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN, 0));
+
+ } else if (gluShaderUtil.isDataTypeVector(basicType)) {
+ this.m_path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT, 0));
+
+ } else {
+ throw new Error('Cant expand scalars - isExpanded() is buggy.');
+ }
+
+ } else if (curType.isArrayType()) {
+ this.m_path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT, 0));
+
+ } else if (curType.isStructType()) {
+ this.m_path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER, 0));
+
+ } else {
+ throw new Error();
+ }
+ }
+
+ };
+ gluVarTypeUtil.SubTypeIterator.prototype.end = function() {
+ return (this.m_type == null);
+ };
+ /** next
+ * equivelant to operator++(), doesnt return.
+ */
+ gluVarTypeUtil.SubTypeIterator.prototype.next = function() {
+ if (this.m_path.length > 0) {
+ // Remove traversed nodes.
+ this.removeTraversed();
+
+ if (this.m_path.length > 0)
+ this.findNext();
+ else
+ this.m_type = null; // Unset type to signal end.
+ } else {
+ if (!this.isExpanded(gluVarTypeUtil.getVarType(this.m_type, this.m_path))) {
+ throw new Error('First type was already expanded.');
+ }
+ this.m_type = null;
+ }
+ };
+ gluVarTypeUtil.SubTypeIterator.prototype.getType = function() {
+ return gluVarTypeUtil.getVarType(this.m_type, this.m_path);
+ };
+ gluVarTypeUtil.SubTypeIterator.prototype.getPath = function() {
+ return this.m_path;
+ };
+
+ gluVarTypeUtil.SubTypeIterator.prototype.toString = function() {
+ var x = new gluVarTypeUtil.TypeAccessFormat(this.m_type, this.m_path);
+ return x.toString();
+ };
+
+ /** gluVarTypeUtil.BasicTypeIterator
+ * @param {gluVarType.VarType} type
+ * @constructor
+ * @extends {gluVarTypeUtil.SubTypeIterator}
+ */
+ gluVarTypeUtil.BasicTypeIterator = function(type) {
+ gluVarTypeUtil.SubTypeIterator.call(this, type);
+ };
+ gluVarTypeUtil.BasicTypeIterator.prototype = Object.create(gluVarTypeUtil.SubTypeIterator.prototype);
+ gluVarTypeUtil.BasicTypeIterator.prototype.constructor = gluVarTypeUtil.BasicTypeIterator;
+
+ gluVarTypeUtil.BasicTypeIterator.prototype.isExpanded = function(type) {
+ return type.isBasicType();
+ };
+
+ /** gluVarTypeUtil.VectorTypeIterator
+ * @param {gluVarType.VarType} type
+ * @constructor
+ * @extends {gluVarTypeUtil.SubTypeIterator}
+ */
+ gluVarTypeUtil.VectorTypeIterator = function(type) {
+ gluVarTypeUtil.SubTypeIterator.call(this, type);
+ };
+ gluVarTypeUtil.VectorTypeIterator.prototype = Object.create(gluVarTypeUtil.SubTypeIterator.prototype);
+ gluVarTypeUtil.VectorTypeIterator.prototype.constructor = gluVarTypeUtil.VectorTypeIterator;
+
+ gluVarTypeUtil.VectorTypeIterator.prototype.isExpanded = function(type) {
+ return type.isBasicType() && gluShaderUtil.isDataTypeScalarOrVector(type.getBasicType());
+ };
+
+ /** gluVarTypeUtil.ScalarTypeIterator
+ * @param {gluVarType.VarType} type
+ * @constructor
+ * @extends {gluVarTypeUtil.SubTypeIterator}
+ */
+ gluVarTypeUtil.ScalarTypeIterator = function(type) {
+ gluVarTypeUtil.SubTypeIterator.call(this, type);
+ };
+ gluVarTypeUtil.ScalarTypeIterator.prototype = Object.create(gluVarTypeUtil.SubTypeIterator.prototype);
+ gluVarTypeUtil.ScalarTypeIterator.prototype.constructor = gluVarTypeUtil.ScalarTypeIterator;
+
+ gluVarTypeUtil.ScalarTypeIterator.prototype.isExpanded = function(type) {
+ return type.isBasicType() && gluShaderUtil.isDataTypeScalar(type.getBasicType());
+ };
+
+ gluVarTypeUtil.inBounds = (function(x, a, b) { return a <= x && x < b; });
+
+ /** gluVarTypeUtil.isValidTypePath
+ * @param {gluVarType.VarType} type
+ * @param {Array<gluVarTypeUtil.VarTypeComponent>} array
+ * @param {number=} begin
+ * @param {number=} end
+ * @return {boolean}
+ */
+ gluVarTypeUtil.isValidTypePath = function(type, array, begin, end) {
+
+ if (typeof(begin) == 'undefined') {begin = 0;}
+ if (typeof(end) == 'undefined') {begin = array.length;}
+
+ var curType = type; // const VarType*
+ var pathIter = begin; // Iterator
+
+ // Process struct member and array element parts of path.
+ while (pathIter != end) {
+ var element = array[pathIter];
+
+ if (element.type == gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER) {
+
+ if (!curType.isStructType() || !gluVarTypeUtil.inBounds(element.index, 0, curType.getStruct().getNumMembers())) {
+ return false;
+ }
+
+ curType = curType.getStruct().getMember(element.index).getType();
+
+ } else if (element.type == gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT) {
+ if (
+ !curType.isArrayType() ||
+ (
+ curType.getArraySize() != gluVarType.VarType.UNSIZED_ARRAY &&
+ !gluVarTypeUtil.inBounds(element.index, 0, curType.getArraySize())
+ )
+ ) {
+ return false;
+ }
+
+ curType = curType.getElementType();
+ } else {
+ break;
+ }
+
+ ++pathIter;
+ }
+
+ if (pathIter != end) {
+ if (!(
+ array[pathIter].type == gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN ||
+ array[pathIter].type == gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT
+ )) {
+ throw new Error('Not a matrix or a vector');
+ }
+
+ // Current type should be basic type.
+ if (!curType.isBasicType()) {
+ return false;
+ }
+
+ var basicType = curType.getBasicType(); // DataType
+
+ if (array[pathIter].type == gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN) {
+ if (!gluShaderUtil.isDataTypeMatrix(basicType)) {
+ return false;
+ }
+
+ basicType = gluShaderUtil.getDataTypeFloatVec(gluShaderUtil.getDataTypeMatrixNumRows(basicType));
+ ++pathIter;
+ }
+
+ if (pathIter != end && array[pathIter].type == gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT) {
+ if (!gluShaderUtil.isDataTypeVector(basicType))
+ return false;
+
+ basicType = gluShaderUtil.getDataTypeScalarType(basicType);
+ ++pathIter;
+ }
+ }
+
+ return pathIter == end;
+ };
+
+ /** gluVarTypeUtil.getVarType
+ * @param {gluVarType.VarType} type
+ * @param {Array<gluVarTypeUtil.VarTypeComponent>} array
+ * @param {number=} start
+ * @param {number=} end
+ * @return {gluVarType.VarType}
+ */
+ gluVarTypeUtil.getVarType = function(type, array, start, end) {
+
+ if (typeof(start) == 'undefined') start = 0;
+ if (typeof(end) == 'undefined') end = array.length;
+
+ if (!gluVarTypeUtil.isValidTypePath(type, array, start, end)) {
+ throw new Error('Type is invalid');
+ }
+
+ var curType = type; // const VarType*
+ var element = null; // Iterator
+ var pathIter = 0;
+
+ // Process struct member and array element parts of path.
+ for (pathIter = start; pathIter != end; ++pathIter) {
+ element = array[pathIter];
+
+ if (element.type == gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER) {
+ curType = curType.getStruct().getMember(element.index).getType();
+
+ } else if (element.type == gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT) {
+ curType = curType.getElementType();
+
+ } else {
+ break;
+
+ }
+ }
+
+ if (pathIter != end) {
+
+ var basicType = curType.getBasicType(); // DataType
+ var precision = curType.getPrecision(); // Precision
+
+ if (element.type == gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN) {
+ basicType = gluShaderUtil.getDataTypeFloatVec(gluShaderUtil.getDataTypeMatrixNumRows(basicType));
+ element = array[++pathIter];
+ }
+
+ if (pathIter != end && element.type == gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT) {
+ basicType = gluShaderUtil.getDataTypeScalarTypeAsDataType(basicType);
+ element = array[++pathIter];
+ }
+
+ if (pathIter != end) {
+ throw new Error();
+ }
+ return gluVarType.newTypeBasic(basicType, precision);
+ } else {
+ /* TODO: Original code created an object copy. We are returning reference to the same object */
+ return curType;
+ }
+ };
+
+ gluVarTypeUtil.parseVariableName = function(nameWithPath) {
+ var tokenizer = new gluVarTypeUtil.VarTokenizer(nameWithPath);
+ if (tokenizer.getToken() != gluVarTypeUtil.VarTokenizer.s_Token.IDENTIFIER) {
+ throw new Error('Not an identifier.');
+ }
+ return tokenizer.getIdentifier();
+ };
+
+ // returns an array (TypeComponentVector& path)
+ // params: const char*, const VarType&
+ gluVarTypeUtil.parseTypePath = function(nameWithPath, type) {
+
+ var tokenizer = new gluVarTypeUtil.VarTokenizer(nameWithPath);
+
+ if (tokenizer.getToken() == gluVarTypeUtil.VarTokenizer.s_Token.IDENTIFIER) {
+ tokenizer.advance();
+ }
+
+ var path = [];
+
+ while (tokenizer.getToken() != gluVarTypeUtil.VarTokenizer.s_Token.END) {
+
+ var curType = gluVarTypeUtil.getVarType(type, path);
+
+ if (tokenizer.getToken() == gluVarTypeUtil.VarTokenizer.s_Token.PERIOD) {
+
+ tokenizer.advance();
+ if (tokenizer.getToken() != gluVarTypeUtil.VarTokenizer.s_Token.IDENTIFIER) {
+ throw new Error();
+ }
+ if (!curType.isStructType()) {
+ throw new Error('Invalid field selector');
+ }
+
+ // Find member.
+ var memberName = tokenizer.getIdentifier();
+ var ndx = 0;
+ for (; ndx < curType.getStruct().getSize(); ++ndx) {
+
+ if (memberName == curType.getStruct().getMember(ndx).getName()) {
+ break;
+ }
+
+ }
+ if (ndx >= curType.getStruct().getSize()) {
+ throw new Error('Member not found in type: ' + memberName);
+ }
+
+ path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.STRUCT_MEMBER, ndx));
+ tokenizer.advance();
+
+ } else if (tokenizer.getToken() == gluVarTypeUtil.VarTokenizer.s_Token.LEFT_BRACKET) {
+
+ tokenizer.advance();
+ if (tokenizer.getToken() != gluVarTypeUtil.VarTokenizer.s_Token.NUMBER) {
+ throw new Error();
+ }
+
+ var ndx = tokenizer.getNumber();
+
+ if (curType.isArrayType()) {
+ if (!gluVarTypeUtil.inBounds(ndx, 0, curType.getArraySize())) throw new Error;
+ path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.ARRAY_ELEMENT, ndx));
+
+ } else if (curType.isBasicType() && gluShaderUtil.isDataTypeMatrix(curType.getBasicType())) {
+ if (!gluVarTypeUtil.inBounds(ndx, 0, gluShaderUtil.getDataTypeMatrixNumColumns(curType.getBasicType()))) throw new Error;
+ path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.MATRIX_COLUMN, ndx));
+
+ } else if (curType.isBasicType() && gluShaderUtil.isDataTypeVector(curType.getBasicType())) {
+ if (!gluVarTypeUtil.inBounds(ndx, 0, gluShaderUtil.getDataTypeScalarSize(curType.getBasicType()))) throw new Error;
+ path.push(new gluVarTypeUtil.VarTypeComponent(gluVarTypeUtil.VarTypeComponent.s_Type.VECTOR_COMPONENT, ndx));
+
+ } else {
+ //TCU_FAIL
+ throw new Error('Invalid subscript');
+ }
+
+ tokenizer.advance();
+ if (tokenizer.getToken() != gluVarTypeUtil.VarTokenizer.s_Token.RIGHT_BRACKET) {
+ throw new Error('Expected token RIGHT_BRACKET');
+ }
+ tokenizer.advance();
+
+ } else {
+ // TCU_FAIL
+ throw new Error('Unexpected token');
+ }
+ }
+
+ return path;
+
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/00_test_list.txt b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/00_test_list.txt
new file mode 100644
index 0000000000..7db3d9d5c7
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/00_test_list.txt
@@ -0,0 +1 @@
+referencecontext.html \ No newline at end of file
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/referencecontext.html b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/referencecontext.html
new file mode 100644
index 0000000000..f3ba0ed262
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/referencecontext.html
@@ -0,0 +1,32 @@
+<html>
+<html>
+<head>
+<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
+<title>Reference context test</title>
+<link rel="stylesheet" href="../../../../resources/js-test-style.css"/>
+<script src="../../../../js/js-test-pre.js"></script>
+<script src="../../../../js/webgl-test-utils.js"></script>
+
+<script src="../../../../closure-library/closure/goog/base.js"></script>
+<script src="../../../deqp-deps.js"></script>
+<script>goog.require('framework.opengl.simplereference.sglrReferenceContextTest');</script>
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<canvas id="canvas" width="200" height="100"> </canvas>
+<script>
+var wtu = WebGLTestUtils;
+var gl = wtu.create3DContext('canvas', {preserveDrawingBuffer: true}, 2);
+
+ try {
+ framework.opengl.simplereference.sglrReferenceContextTest.run(gl);
+ }
+ catch(err)
+ {
+ bufferedLogToConsole(err);
+ }
+
+</script>
+</body>
+</html>
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrGLContext.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrGLContext.js
new file mode 100644
index 0000000000..13f75e8f5e
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrGLContext.js
@@ -0,0 +1,231 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('framework.opengl.simplereference.sglrGLContext');
+goog.require('framework.common.tcuPixelFormat');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.common.tcuTextureUtil');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.delibs.debase.deUtil');
+goog.require('framework.opengl.gluShaderProgram');
+goog.require('framework.opengl.gluShaderUtil');
+goog.require('framework.opengl.gluTextureUtil');
+goog.require('framework.opengl.simplereference.sglrShaderProgram');
+goog.require('framework.referencerenderer.rrDefs');
+goog.require('framework.referencerenderer.rrMultisamplePixelBufferAccess');
+goog.require('framework.referencerenderer.rrRenderState');
+goog.require('framework.referencerenderer.rrRenderer');
+goog.require('framework.referencerenderer.rrVertexAttrib');
+
+goog.scope(function() {
+
+ var sglrGLContext = framework.opengl.simplereference.sglrGLContext;
+ var tcuTexture = framework.common.tcuTexture;
+ var deUtil = framework.delibs.debase.deUtil;
+ var deMath = framework.delibs.debase.deMath;
+ var tcuTextureUtil = framework.common.tcuTextureUtil;
+ var tcuPixelFormat = framework.common.tcuPixelFormat;
+ var gluShaderProgram = framework.opengl.gluShaderProgram;
+ var gluShaderUtil = framework.opengl.gluShaderUtil;
+ var gluTextureUtil = framework.opengl.gluTextureUtil;
+ var sglrShaderProgram = framework.opengl.simplereference.sglrShaderProgram;
+ var rrDefs = framework.referencerenderer.rrDefs;
+ var rrMultisamplePixelBufferAccess = framework.referencerenderer.rrMultisamplePixelBufferAccess;
+ var rrRenderer = framework.referencerenderer.rrRenderer;
+ var rrRenderState = framework.referencerenderer.rrRenderState;
+ var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib;
+
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+ /**
+ * sglrGLContext.GLContext wraps the standard WebGL context to be able to be used interchangeably with the ReferenceContext
+ * @constructor
+ * @extends {WebGL2RenderingContext}
+ * @param {?WebGL2RenderingContext} context
+ * @param {Array<number>=} viewport
+ */
+ sglrGLContext.GLContext = function(context, viewport) {
+ DE_ASSERT(context);
+
+ var functionwrapper = function(context, fname) {
+ return function() {
+ return context[fname].apply(context, arguments);
+ };
+ };
+
+ var wrap = {};
+ for (var i in context) {
+ try {
+ if (typeof context[i] == 'function') {
+ wrap[i] = functionwrapper(context, i);
+ } else {
+ wrap[i] = context[i];
+ }
+ } catch (e) {
+ throw new Error('GLContext: Error accessing ' + i);
+ }
+ }
+ if (viewport)
+ context.viewport(viewport[0], viewport[1], viewport[2], viewport[3]);
+
+ /**
+ * createProgram
+ * @override
+ * @param {sglrShaderProgram.ShaderProgram=} shader
+ * @return {!WebGLProgram}
+ */
+ this.createProgram = function(shader) {
+ var program = new gluShaderProgram.ShaderProgram(
+ context,
+ gluShaderProgram.makeVtxFragSources(
+ shader.m_vertSrc,
+ shader.m_fragSrc
+ )
+ );
+
+ if (!program.isOk()) {
+ bufferedLogToConsole(program.toString());
+ testFailedOptions('Compile failed', true);
+ }
+ return program.getProgram();
+ };
+ wrap['createProgram'] = this.createProgram;
+
+ /**
+ * Draws quads from vertex arrays
+ * @param {number} primitive Primitive type
+ * @param {number} first First vertex to begin drawing with
+ * @param {number} count Number of vertices
+ */
+ var drawQuads = function(primitive, first, count) {
+ context.drawArrays(primitive, first, count);
+ };
+ wrap['drawQuads'] = drawQuads;
+
+ /**
+ * @return {number}
+ */
+ var getWidth = function() {
+ if(viewport)
+ return viewport[2];
+ else
+ return context.drawingBufferWidth;
+ };
+ wrap['getWidth'] = getWidth;
+
+ /**
+ * @return {number}
+ */
+ var getHeight = function() {
+ if(viewport)
+ return viewport[3];
+ else
+ return context.drawingBufferHeight;
+ };
+ wrap['getHeight'] = getHeight;
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width
+ * @param {number} height
+ * @param {number} format
+ * @param {number} dataType
+ * @param {ArrayBuffer|ArrayBufferView} data
+ */
+ var readPixels = function(x, y, width, height, format, dataType, data) {
+ /** @type {?ArrayBufferView} */ var dataArr;
+ if (!ArrayBuffer.isView(data)) {
+ var type = gluTextureUtil.mapGLChannelType(dataType, true);
+ var dataArrType = tcuTexture.getTypedArray(type);
+ dataArr = new dataArrType(data);
+ } else {
+ dataArr = /** @type {?ArrayBufferView} */ (data);
+ }
+
+ context.readPixels(x, y, width, height, format, dataType, dataArr);
+ };
+ wrap['readPixels'] = readPixels;
+
+ /**
+ * @param {number} target
+ * @param {number} level
+ * @param {number} internalFormat
+ * @param {number} width
+ * @param {number} height
+ */
+ var texImage2DDelegate = function(target, level, internalFormat, width, height) {
+ var format;
+ var dataType;
+
+ switch(internalFormat)
+ {
+ case gl.ALPHA:
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ case gl.RGB:
+ case gl.RGBA:
+ format = internalFormat;
+ dataType = gl.UNSIGNED_BYTE;
+ break;
+ default:
+ {
+ var transferFmt = gluTextureUtil.getTransferFormat(gluTextureUtil.mapGLInternalFormat(internalFormat));
+ format = transferFmt.format;
+ dataType = transferFmt.dataType;
+ break;
+ }
+ }
+ context.texImage2D(target, level, internalFormat, width, height, 0, format, dataType, null);
+ };
+ wrap['texImage2DDelegate'] = texImage2DDelegate;
+
+ return wrap;
+ };
+
+ /**
+ * createProgram - This had to be added here as dummy to remove a warning when the only context used is GLContext (no reference context)
+ * @override
+ * @param {sglrShaderProgram.ShaderProgram=} shader
+ * @return {!WebGLProgram}
+ */
+ sglrGLContext.GLContext.prototype.createProgram = function(shader) {return this.createProgram();};
+
+ /**
+ * @param ctx GL-like context
+ * @param {string} name
+ * @return {boolean}
+ */
+ sglrGLContext.isExtensionSupported = function(ctx, name) {
+ var extns = ctx.getSupportedExtensions();
+ var found = false;
+ if (extns) {
+ var index = extns.indexOf(name);
+ if (index != -1)
+ found = true;
+ }
+ return found;
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContext.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContext.js
new file mode 100644
index 0000000000..523dbe607f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContext.js
@@ -0,0 +1,4986 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('framework.opengl.simplereference.sglrReferenceContext');
+goog.require('framework.common.tcuMatrix');
+goog.require('framework.common.tcuMatrixUtil');
+goog.require('framework.common.tcuPixelFormat');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.common.tcuTextureUtil');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.opengl.gluShaderUtil');
+goog.require('framework.opengl.gluTextureUtil');
+goog.require('framework.opengl.simplereference.sglrReferenceUtils');
+goog.require('framework.opengl.simplereference.sglrShaderProgram');
+goog.require('framework.referencerenderer.rrDefs');
+goog.require('framework.referencerenderer.rrGenericVector');
+goog.require('framework.referencerenderer.rrMultisamplePixelBufferAccess');
+goog.require('framework.referencerenderer.rrRenderState');
+goog.require('framework.referencerenderer.rrRenderer');
+goog.require('framework.referencerenderer.rrVertexAttrib');
+
+goog.scope(function() {
+
+ var sglrReferenceContext = framework.opengl.simplereference.sglrReferenceContext;
+ var rrMultisamplePixelBufferAccess = framework.referencerenderer.rrMultisamplePixelBufferAccess;
+ var tcuTexture = framework.common.tcuTexture;
+ var deMath = framework.delibs.debase.deMath;
+ var gluTextureUtil = framework.opengl.gluTextureUtil;
+ var tcuTextureUtil = framework.common.tcuTextureUtil;
+ var tcuPixelFormat = framework.common.tcuPixelFormat;
+ var gluShaderUtil = framework.opengl.gluShaderUtil;
+ var rrRenderer = framework.referencerenderer.rrRenderer;
+ var rrDefs = framework.referencerenderer.rrDefs;
+ var rrGenericVector = framework.referencerenderer.rrGenericVector;
+ var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib;
+ var rrRenderState = framework.referencerenderer.rrRenderState;
+ var sglrReferenceUtils = framework.opengl.simplereference.sglrReferenceUtils;
+ var sglrShaderProgram = framework.opengl.simplereference.sglrShaderProgram;
+ var tcuMatrix = framework.common.tcuMatrix;
+ var tcuMatrixUtil = framework.common.tcuMatrixUtil;
+
+ sglrReferenceContext.rrMPBA = rrMultisamplePixelBufferAccess;
+
+ //TODO: Implement automatic error checking in sglrReferenceContext, optional on creation.
+
+ /** @typedef {WebGLRenderbuffer|WebGLTexture|sglrReferenceContext.Renderbuffer|sglrReferenceContext.TextureContainer} */ sglrReferenceContext.AnyRenderbuffer;
+
+ /** @typedef {WebGLFramebuffer|sglrReferenceContext.Framebuffer} */ sglrReferenceContext.AnyFramebuffer;
+
+ /**
+ * @param {number} error
+ * @param {number} message
+ * @throws {Error}
+ */
+ sglrReferenceContext.GLU_EXPECT_NO_ERROR = function(error, message) {
+ if (error !== gl.NONE) {
+ bufferedLogToConsole('Assertion failed message:' + message);
+ }
+ };
+
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+ // /* TODO: remove */
+ // /** @type {WebGL2RenderingContext} */ var gl;
+
+ sglrReferenceContext.MAX_TEXTURE_SIZE_LOG2 = 14;
+ sglrReferenceContext.MAX_TEXTURE_SIZE = 1 << sglrReferenceContext.MAX_TEXTURE_SIZE_LOG2;
+
+ /**
+ * @param {number} width
+ * @param {number} height
+ * @return {number}
+ */
+ sglrReferenceContext.getNumMipLevels2D = function(width, height) {
+ return Math.floor(Math.log2(Math.max(width, height)) + 1);
+ };
+
+ /**
+ * @param {number} width
+ * @param {number} height
+ * @param {number} depth
+ * @return {number}
+ */
+ sglrReferenceContext.getNumMipLevels3D = function(width, height, depth) {
+ return Math.floor(Math.log2(Math.max(width, height, depth)) + 1);
+ };
+
+ /**
+ * @param {number} baseLevelSize
+ * @param {number} levelNdx
+ * @return {number}
+ */
+ sglrReferenceContext.getMipLevelSize = function(baseLevelSize, levelNdx) {
+ return Math.max(baseLevelSize >> levelNdx, 1);
+ };
+
+ sglrReferenceContext.mapGLCubeFace = function(face) {
+ switch (face) {
+ case gl.TEXTURE_CUBE_MAP_NEGATIVE_X: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X;
+ case gl.TEXTURE_CUBE_MAP_POSITIVE_X: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_X;
+ case gl.TEXTURE_CUBE_MAP_NEGATIVE_Y: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y;
+ case gl.TEXTURE_CUBE_MAP_POSITIVE_Y: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y;
+ case gl.TEXTURE_CUBE_MAP_NEGATIVE_Z: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z;
+ case gl.TEXTURE_CUBE_MAP_POSITIVE_Z: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z;
+ default: throw new Error('Invalid cube face: ' + face);
+ }
+ };
+
+ /**
+ * @param {tcuTexture.FilterMode} mode
+ * @return {boolean}
+ */
+ sglrReferenceContext.isMipmapFilter = function(/*const tcu::Sampler::FilterMode*/ mode) {
+ return mode != tcuTexture.FilterMode.NEAREST && mode != tcuTexture.FilterMode.LINEAR;
+ };
+
+ sglrReferenceContext.getNumMipLevels1D = function(size) {
+ return Math.floor(Math.log2(size)) + 1;
+ };
+
+ /**
+ * @param {?sglrReferenceContext.TextureType} type
+ * @return {sglrReferenceContext.TexTarget}
+ */
+ sglrReferenceContext.texLayeredTypeToTarget = function(type) {
+ switch (type) {
+ case sglrReferenceContext.TextureType.TYPE_2D_ARRAY: return sglrReferenceContext.TexTarget.TEXTARGET_2D_ARRAY;
+ case sglrReferenceContext.TextureType.TYPE_3D: return sglrReferenceContext.TexTarget.TEXTARGET_3D;
+ case sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_ARRAY;
+ default: throw new Error('Invalid texture type: ' + type);
+ }
+ };
+
+ /**
+ * @param {rrDefs.IndexType} indexType
+ * @return {number}
+ * @throws {Error}
+ */
+ sglrReferenceContext.getFixedRestartIndex = function(indexType) {
+ switch (indexType) {
+ case rrDefs.IndexType.INDEXTYPE_UINT8: return 0xFF;
+ case rrDefs.IndexType.INDEXTYPE_UINT16: return 0xFFFF;
+ case rrDefs.IndexType.INDEXTYPE_UINT32: return 0xFFFFFFFF;
+ default:
+ throw new Error('Unrecognized index type: ' + indexType);
+ }
+ };
+
+ /**
+ * @constructor
+ * @param {sglrShaderProgram.ShaderProgram} program
+ */
+ sglrReferenceContext.ShaderProgramObjectContainer = function(program) {
+ this.m_program = program;
+ /** @type {boolean} */ this.m_deleteFlag = false;
+ };
+
+ /**
+ * @param {WebGL2RenderingContext} gl
+ * @constructor
+ */
+ sglrReferenceContext.ReferenceContextLimits = function(gl) {
+ /** @type {number} */ this.maxTextureImageUnits = 16;
+ /** @type {number} */ this.maxTexture2DSize = 2048;
+ /** @type {number} */ this.maxTextureCubeSize = 2048;
+ /** @type {number} */ this.maxTexture2DArrayLayers = 256;
+ /** @type {number} */ this.maxTexture3DSize = 256;
+ /** @type {number} */ this.maxRenderbufferSize = 2048;
+ /** @type {number} */ this.maxVertexAttribs = 16;
+
+ if (gl) {
+ this.maxTextureImageUnits = /** @type {number} */ (gl.getParameter(gl.MAX_TEXTURE_IMAGE_UNITS));
+ this.maxTexture2DSize = /** @type {number} */ (gl.getParameter(gl.MAX_TEXTURE_SIZE));
+ this.maxTextureCubeSize = /** @type {number} */ (gl.getParameter(gl.MAX_CUBE_MAP_TEXTURE_SIZE));
+ this.maxRenderbufferSize = /** @type {number} */ (gl.getParameter(gl.MAX_RENDERBUFFER_SIZE));
+ this.maxVertexAttribs = /** @type {number} */ (gl.getParameter(gl.MAX_VERTEX_ATTRIBS));
+ this.maxTexture2DArrayLayers = /** @type {number} */ (gl.getParameter(gl.MAX_ARRAY_TEXTURE_LAYERS));
+ this.maxTexture3DSize = /** @type {number} */ (gl.getParameter(gl.MAX_3D_TEXTURE_SIZE));
+
+ // Limit texture sizes to supported values
+ this.maxTexture2DSize = Math.min(this.maxTexture2DSize, sglrReferenceContext.MAX_TEXTURE_SIZE);
+ this.maxTextureCubeSize = Math.min(this.maxTextureCubeSize, sglrReferenceContext.MAX_TEXTURE_SIZE);
+ this.maxTexture3DSize = Math.min(this.maxTexture3DSize, sglrReferenceContext.MAX_TEXTURE_SIZE);
+
+ sglrReferenceContext.GLU_EXPECT_NO_ERROR(gl.getError(), gl.NO_ERROR);
+ }
+
+ /* TODO: Port
+ // \todo [pyry] Figure out following things:
+ // + supported fbo configurations
+ // ...
+
+ // \todo [2013-08-01 pyry] Do we want to make these conditional based on renderCtx?
+ addExtension("gl.EXT_color_buffer_half_float");
+ addExtension("gl.WEBGL_color_buffer_float");
+ */
+ };
+
+ /**
+ * @enum
+ */
+ sglrReferenceContext.TextureType = {
+ TYPE_2D: 0,
+ TYPE_CUBE_MAP: 1,
+ TYPE_2D_ARRAY: 2,
+ TYPE_3D: 3,
+ TYPE_CUBE_MAP_ARRAY: 4
+ };
+
+ /**
+ * @constructor
+ * @implements {rrDefs.Sampler}
+ * @param {sglrReferenceContext.TextureType} type
+ */
+ sglrReferenceContext.Texture = function(type) {
+ // NamedObject.call(this, name);
+ /** @type {sglrReferenceContext.TextureType} */ this.m_type = type;
+ /** @type {boolean} */ this.m_immutable = false;
+ /** @type {number} */ this.m_baseLevel = 0;
+ /** @type {number} */ this.m_maxLevel = 1000;
+ /** @type {tcuTexture.Sampler} */ this.m_sampler = new tcuTexture.Sampler(
+ tcuTexture.WrapMode.REPEAT_GL,
+ tcuTexture.WrapMode.REPEAT_GL,
+ tcuTexture.WrapMode.REPEAT_GL,
+ tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR,
+ tcuTexture.FilterMode.LINEAR,
+ 0,
+ true,
+ tcuTexture.CompareMode.COMPAREMODE_NONE,
+ 0,
+ [0, 0, 0, 0],
+ true);
+ };
+
+ /**
+ * @param {Array<number>} pos
+ * @param {number=} lod
+ * @throws {Error}
+ */
+ sglrReferenceContext.Texture.prototype.sample = function(pos, lod) {throw new Error('Intentionally empty. Call method from child class instead'); };
+
+ /**
+ * @param {Array<Array<number>>} packetTexcoords
+ * @param {number} lodBias
+ * @throws {Error}
+ */
+ sglrReferenceContext.Texture.prototype.sample4 = function(packetTexcoords, lodBias) {throw new Error('Intentionally empty. Call method from child class instead'); };
+
+ // sglrReferenceContext.Texture.prototype = Object.create(NamedObject.prototype);
+ // sglrReferenceContext.Texture.prototype.constructor = sglrReferenceContext.Texture;
+
+ /**
+ * @return {number}
+ */
+ sglrReferenceContext.Texture.prototype.getType = function() { return this.m_type; };
+
+ /**
+ * @return {number}
+ */
+ sglrReferenceContext.Texture.prototype.getBaseLevel = function() { return this.m_baseLevel; };
+
+ /**
+ * @return {number}
+ */
+ sglrReferenceContext.Texture.prototype.getMaxLevel = function() { return this.m_maxLevel; };
+
+ /**
+ * @return {boolean}
+ */
+ sglrReferenceContext.Texture.prototype.isImmutable = function() { return this.m_immutable; };
+
+ /**
+ * @param {number} baseLevel
+ */
+ sglrReferenceContext.Texture.prototype.setBaseLevel = function(baseLevel) { this.m_baseLevel = baseLevel; };
+
+ /**
+ * @param {number} maxLevel
+ */
+ sglrReferenceContext.Texture.prototype.setMaxLevel = function(maxLevel) { this.m_maxLevel = maxLevel; };
+
+ /**
+ */
+ sglrReferenceContext.Texture.prototype.setImmutable = function() { this.m_immutable = true; };
+
+ /**
+ * @return {tcuTexture.Sampler}
+ */
+ sglrReferenceContext.Texture.prototype.getSampler = function() { return this.m_sampler; };
+
+ /**
+ * @constructor
+ */
+ sglrReferenceContext.TextureLevelArray = function() {
+ /** @type {Array<ArrayBuffer>} */ this.m_data = [];
+ /** @type {Array<tcuTexture.PixelBufferAccess>} */ this.m_access = [];
+ };
+
+ /**
+ * @param {number} level
+ * @return {boolean}
+ */
+ sglrReferenceContext.TextureLevelArray.prototype.hasLevel = function(level) { return this.m_data[level] != null; };
+
+ /**
+ * @param {number} level
+ * @return {tcuTexture.PixelBufferAccess}
+ * @throws {Error}
+ */
+ sglrReferenceContext.TextureLevelArray.prototype.getLevel = function(level) {
+ if (!this.hasLevel(level))
+ throw new Error('Level: ' + level + ' is not defined.');
+
+ return this.m_access[level];
+ };
+
+ /**
+ * @return {Array<tcuTexture.PixelBufferAccess>}
+ */
+ sglrReferenceContext.TextureLevelArray.prototype.getLevels = function() { return this.m_access; };
+
+ /**
+ * @param {number} level
+ * @param {tcuTexture.TextureFormat} format
+ * @param {number} width
+ * @param {number} height
+ * @param {number} depth
+ */
+ sglrReferenceContext.TextureLevelArray.prototype.allocLevel = function(level, format, width, height, depth) {
+ /** @type {number} */ var dataSize = format.getPixelSize() * width * height * depth;
+ if (this.hasLevel(level))
+ this.clearLevel(level);
+
+ this.m_data[level] = new ArrayBuffer(dataSize);
+ this.m_access[level] = new tcuTexture.PixelBufferAccess({
+ format: format,
+ width: width,
+ height: height,
+ depth: depth,
+ data: this.m_data[level]});
+ };
+
+ /**
+ * @param {number} level
+ */
+ sglrReferenceContext.TextureLevelArray.prototype.clearLevel = function(level) {
+ delete this.m_data[level];
+ delete this.m_access[level];
+ };
+
+ /**
+ */
+ sglrReferenceContext.TextureLevelArray.prototype.clear = function() {
+ for (var key in this.m_data)
+ delete this.m_data[key];
+
+ for (var key in this.m_access)
+ delete this.m_access[key];
+ };
+
+ /**
+ * @constructor
+ * @extends {sglrReferenceContext.Texture}
+ */
+ sglrReferenceContext.Texture2D = function() {
+ sglrReferenceContext.Texture.call(this, sglrReferenceContext.TextureType.TYPE_2D);
+ /** @type {tcuTexture.Texture2DView} */ this.m_view = new tcuTexture.Texture2DView(0, null);
+ /** @type {sglrReferenceContext.TextureLevelArray} */ this.m_levels = new sglrReferenceContext.TextureLevelArray();
+ };
+
+ /**
+ */
+ sglrReferenceContext.Texture2D.prototype = Object.create(sglrReferenceContext.Texture.prototype);
+ sglrReferenceContext.Texture2D.prototype.constructor = sglrReferenceContext.Texture2D;
+
+ sglrReferenceContext.Texture2D.prototype.clearLevels = function() { this.m_levels.clear(); };
+
+ /**
+ * @param {number} level
+ * @return {boolean}
+ */
+ sglrReferenceContext.Texture2D.prototype.hasLevel = function(level) { return this.m_levels.hasLevel(level); };
+
+ /**
+ * @param {number} level
+ * @return {tcuTexture.PixelBufferAccess}
+ */
+ sglrReferenceContext.Texture2D.prototype.getLevel = function(level) { return this.m_levels.getLevel(level); };
+
+ /**
+ * @param {number} level
+ * @param {?tcuTexture.TextureFormat} format
+ * @param {number} width
+ * @param {number} height
+ */
+ sglrReferenceContext.Texture2D.prototype.allocLevel = function(level, format, width, height) { this.m_levels.allocLevel(level, format, width, height, 1); };
+
+ /**
+ * @return {boolean}
+ */
+ sglrReferenceContext.Texture2D.prototype.isComplete = function() {
+ /** @type {number} */ var baseLevel = this.getBaseLevel();
+
+ if (this.hasLevel(baseLevel)) {
+ /** @type {tcuTexture.PixelBufferAccess} */ var level0 = this.getLevel(baseLevel);
+ /** @type {boolean} */ var mipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
+
+ if (mipmap) {
+ /** @type {tcuTexture.TextureFormat} */ var format = level0.getFormat();
+ /** @type {number} */ var w = level0.getWidth();
+ /** @type {number} */ var h = level0.getHeight();
+ /** @type {number} */ var numLevels = Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(w, h));
+
+ for (var levelNdx = 1; levelNdx < numLevels; levelNdx++) {
+ if (this.hasLevel(baseLevel + levelNdx)) {
+ /** @type {tcuTexture.PixelBufferAccess} */ var level = this.getLevel(baseLevel + levelNdx);
+ /** @type {number} */ var expectedW = sglrReferenceContext.getMipLevelSize(w, levelNdx);
+ /** @type {number} */ var expectedH = sglrReferenceContext.getMipLevelSize(h, levelNdx);
+
+ if (level.getWidth() != expectedW ||
+ level.getHeight() != expectedH ||
+ !level.getFormat().isEqual(format))
+ return false;
+ } else
+ return false;
+ }
+ }
+
+ return true;
+ } else
+ return false;
+ };
+
+ /**
+ */
+ sglrReferenceContext.Texture2D.prototype.updateView = function() {
+ /** @type {number} */ var baseLevel = this.getBaseLevel();
+
+ if (this.hasLevel(baseLevel) && !this.getLevel(baseLevel).isEmpty()) {
+ // Update number of levels in mipmap pyramid.
+ /** @type {number} */ var width = this.getLevel(baseLevel).getWidth();
+ /** @type {number} */ var height = this.getLevel(baseLevel).getHeight();
+ /** @type {boolean} */ var isMipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
+ /** @type {number} */ var numLevels = isMipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(width, height)) : 1;
+
+ this.m_view = new tcuTexture.Texture2DView(numLevels, this.m_levels.getLevels().slice(baseLevel));
+ } else
+ this.m_view = new tcuTexture.Texture2DView(0, null);
+ };
+
+ /**
+ * @param {Array<number>} pos
+ * @param {number=} lod
+ * @return {Array<number>}
+ */
+ sglrReferenceContext.Texture2D.prototype.sample = function(pos, lod) {
+ return this.m_view.sample(this.getSampler(), pos, lod);
+ };
+
+ /**
+ * @param {Array<Array<number>>} packetTexcoords 4 vec2 coordinates
+ * @param {number} lodBias_
+ * @return {Array<Array<number>>} 4 vec4 samples
+ */
+ sglrReferenceContext.Texture2D.prototype.sample4 = function(packetTexcoords, lodBias_) {
+ /** @type {number} */ var lodBias = lodBias_ || 0;
+ /** @type {number} */ var texWidth = this.m_view.getWidth();
+ /** @type {number} */ var texHeight = this.m_view.getHeight();
+ /** @type {Array<Array<number>>}*/ var output = [];
+
+ /** @type {Array<number>}*/ var dFdx0 = deMath.subtract(packetTexcoords[1], packetTexcoords[0]);
+ /** @type {Array<number>}*/ var dFdx1 = deMath.subtract(packetTexcoords[3], packetTexcoords[2]);
+ /** @type {Array<number>}*/ var dFdy0 = deMath.subtract(packetTexcoords[2], packetTexcoords[0]);
+ /** @type {Array<number>}*/ var dFdy1 = deMath.subtract(packetTexcoords[3], packetTexcoords[1]);
+
+ for (var fragNdx = 0; fragNdx < 4; ++fragNdx) {
+ /** @type {Array<number>}*/var dFdx = (fragNdx & 2) ? dFdx1 : dFdx0;
+ /** @type {Array<number>}*/var dFdy = (fragNdx & 1) ? dFdy1 : dFdy0;
+
+ /** @type {number} */ var mu = Math.max(Math.abs(dFdx[0]), Math.abs(dFdy[0]));
+ /** @type {number} */ var mv = Math.max(Math.abs(dFdx[1]), Math.abs(dFdy[1]));
+ /** @type {number} */ var p = Math.max(mu * texWidth, mv * texHeight);
+
+ /** @type {number} */ var lod = Math.log2(p) + lodBias;
+
+ output.push(this.sample([packetTexcoords[fragNdx][0], packetTexcoords[fragNdx][1]], lod));
+ }
+
+ return output;
+ };
+
+ /**
+ * @constructor
+ * @extends {sglrReferenceContext.Texture}
+ */
+ sglrReferenceContext.TextureCube = function() {
+ sglrReferenceContext.Texture.call(this, sglrReferenceContext.TextureType.TYPE_CUBE_MAP);
+ /** @type {tcuTexture.TextureCubeView} */ this.m_view = new tcuTexture.TextureCubeView(0, null);
+ /** @type {Array<sglrReferenceContext.TextureLevelArray>} */ this.m_levels = [];
+ for (var face in tcuTexture.CubeFace)
+ this.m_levels[tcuTexture.CubeFace[face]] = new sglrReferenceContext.TextureLevelArray();
+ };
+
+ /**
+ */
+ sglrReferenceContext.TextureCube.prototype = Object.create(sglrReferenceContext.Texture.prototype);
+ sglrReferenceContext.TextureCube.prototype.constructor = sglrReferenceContext.Texture2D;
+
+ sglrReferenceContext.TextureCube.prototype.clearLevels = function() {
+ for (var face in tcuTexture.CubeFace)
+ this.m_levels[tcuTexture.CubeFace[face]].clear();
+ };
+
+ /**
+ * @param {number} level
+ * @param {tcuTexture.CubeFace} face
+ * @return {boolean}
+ */
+ sglrReferenceContext.TextureCube.prototype.hasFace = function(level, face) { return this.m_levels[face].hasLevel(level); };
+
+ /**
+ * @param {number} level
+ * @param {tcuTexture.CubeFace} face
+ * @return {tcuTexture.PixelBufferAccess}
+ */
+ sglrReferenceContext.TextureCube.prototype.getFace = function(level, face) { return this.m_levels[face].getLevel(level); };
+
+ /**
+ * @param {number} level
+ * @param {tcuTexture.CubeFace} face
+ * @param {?tcuTexture.TextureFormat} format
+ * @param {number} width
+ * @param {number} height
+ */
+ sglrReferenceContext.TextureCube.prototype.allocLevel = function(level, face, format, width, height) {
+ this.m_levels[face].allocLevel(level, format, width, height, 1);
+ };
+
+ sglrReferenceContext.TextureCube.prototype.isComplete = function() {
+ var baseLevel = this.getBaseLevel();
+
+ if (this.hasFace(baseLevel, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X)) {
+ var level = this.getFace(baseLevel, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X);
+ var width = level.getWidth();
+ var height = level.getHeight();
+ var format = level.getFormat();
+ var mipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
+ var numLevels = mipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(width, height)) : 1;
+
+ if (width != height)
+ return false; // Non-square is not supported.
+
+ // \note Level 0 is always checked for consistency
+ for (var levelNdx = 0; levelNdx < numLevels; levelNdx++) {
+ var levelW = sglrReferenceContext.getMipLevelSize(width, levelNdx);
+ var levelH = sglrReferenceContext.getMipLevelSize(height, levelNdx);
+
+ for (var face in tcuTexture.CubeFace) {
+ if (this.hasFace(baseLevel + levelNdx, tcuTexture.CubeFace[face])) {
+ level = this.getFace(baseLevel + levelNdx, tcuTexture.CubeFace[face]);
+
+ if (level.getWidth() != levelW ||
+ level.getHeight() != levelH ||
+ !level.getFormat().isEqual(format))
+ return false;
+ } else
+ return false;
+ }
+ }
+
+ return true;
+ } else
+ return false;
+ };
+
+ sglrReferenceContext.TextureCube.prototype.updateView = function() {
+
+ var baseLevel = this.getBaseLevel();
+ var faces = [];
+
+ if (this.isComplete()) {
+ var size = this.getFace(baseLevel, tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X).getWidth();
+ var isMipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
+ var numLevels = isMipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels1D(size)) : 1;
+
+ for (var face in tcuTexture.CubeFace)
+ faces[tcuTexture.CubeFace[face]] = this.m_levels[tcuTexture.CubeFace[face]].getLevels().slice(baseLevel);
+
+ this.m_view = new tcuTexture.TextureCubeView(numLevels, faces);
+ } else
+ this.m_view = new tcuTexture.TextureCubeView(0, null);
+ };
+
+ /**
+ * @param {Array<number>} pos
+ * @param {number=} lod
+ * @return {Array<number>}
+ */
+ sglrReferenceContext.TextureCube.prototype.sample = function(pos, lod) { return this.m_view.sample(this.getSampler(), pos, lod) };
+
+ /**
+ * @constructor
+ * @extends {sglrReferenceContext.Texture}
+ */
+ sglrReferenceContext.Texture2DArray = function() {
+ sglrReferenceContext.Texture.call(this, sglrReferenceContext.TextureType.TYPE_2D_ARRAY);
+ /** @type {tcuTexture.Texture2DArrayView} */ this.m_view = new tcuTexture.Texture2DArrayView(0, null);
+ /** @type {sglrReferenceContext.TextureLevelArray} */ this.m_levels = new sglrReferenceContext.TextureLevelArray();
+ };
+
+ /**
+ */
+ sglrReferenceContext.Texture2DArray.prototype = Object.create(sglrReferenceContext.Texture.prototype);
+ sglrReferenceContext.Texture2DArray.prototype.constructor = sglrReferenceContext.Texture2DArray;
+
+ sglrReferenceContext.Texture2DArray.prototype.clearLevels = function() { this.m_levels.clear(); };
+
+ /**
+ * @param {number} level
+ * @return {boolean}
+ */
+ sglrReferenceContext.Texture2DArray.prototype.hasLevel = function(level) { return this.m_levels.hasLevel(level); };
+
+ /**
+ * @param {number} level
+ * @return {tcuTexture.PixelBufferAccess}
+ */
+ sglrReferenceContext.Texture2DArray.prototype.getLevel = function(level) { return this.m_levels.getLevel(level); };
+
+ /**
+ * @param {number} level
+ * @param {?tcuTexture.TextureFormat} format
+ * @param {number} width
+ * @param {number} height
+ * @param {number} numLayers
+ */
+ sglrReferenceContext.Texture2DArray.prototype.allocLevel = function(level, format, width, height, numLayers) {
+ this.m_levels.allocLevel(level, format, width, height, numLayers);
+ };
+
+ /**
+ * @return {boolean}
+ */
+ sglrReferenceContext.Texture2DArray.prototype.isComplete = function() {
+ /** @type {number} */ var baseLevel = this.getBaseLevel();
+
+ if (this.hasLevel(baseLevel)) {
+ /** @type {tcuTexture.PixelBufferAccess} */ var level0 = this.getLevel(baseLevel);
+ /** @type {boolean} */ var mipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
+
+ if (mipmap) {
+ /** @type {tcuTexture.TextureFormat} */ var format = level0.getFormat();
+ /** @type {number} */ var w = level0.getWidth();
+ /** @type {number} */ var h = level0.getHeight();
+ /** @type {number} */ var numLayers = level0.getDepth();
+ /** @type {number} */ var numLevels = Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(w, h));
+
+ for (var levelNdx = 1; levelNdx < numLevels; levelNdx++) {
+ if (this.hasLevel(baseLevel + levelNdx)) {
+ /** @type {tcuTexture.PixelBufferAccess} */ var level = this.getLevel(baseLevel + levelNdx);
+ /** @type {number} */ var expectedW = sglrReferenceContext.getMipLevelSize(w, levelNdx);
+ /** @type {number} */ var expectedH = sglrReferenceContext.getMipLevelSize(h, levelNdx);
+
+ if (level.getWidth() != expectedW ||
+ level.getHeight() != expectedH ||
+ level.getDepth() != numLayers ||
+ !level.getFormat().isEqual(format))
+ return false;
+ } else
+ return false;
+ }
+ }
+
+ return true;
+ } else
+ return false;
+ };
+
+ /**
+ */
+ sglrReferenceContext.Texture2DArray.prototype.updateView = function() {
+ /** @type {number} */ var baseLevel = this.getBaseLevel();
+
+ if (this.hasLevel(baseLevel) && !this.getLevel(baseLevel).isEmpty()) {
+ // Update number of levels in mipmap pyramid.
+ /** @type {number} */ var width = this.getLevel(baseLevel).getWidth();
+ /** @type {number} */ var height = this.getLevel(baseLevel).getHeight();
+ /** @type {boolean} */ var isMipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
+ /** @type {number} */ var numLevels = isMipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(width, height)) : 1;
+
+ this.m_view = new tcuTexture.Texture2DArrayView(numLevels, this.m_levels.getLevels().slice(baseLevel));
+ } else
+ this.m_view = new tcuTexture.Texture2DArrayView(0, null);
+ };
+
+ /**
+ * @param {Array<number>} pos
+ * @param {number=} lod
+ * @return {Array<number>}
+ */
+ sglrReferenceContext.Texture2DArray.prototype.sample = function(pos, lod) {
+ return this.m_view.sample(this.getSampler(), pos, lod);
+ };
+
+ /**
+ * @constructor
+ * @extends {sglrReferenceContext.Texture}
+ */
+ sglrReferenceContext.Texture3D = function() {
+ sglrReferenceContext.Texture.call(this, sglrReferenceContext.TextureType.TYPE_2D_ARRAY);
+ /** @type {tcuTexture.Texture3DView} */ this.m_view = new tcuTexture.Texture3DView(0, null);
+ /** @type {sglrReferenceContext.TextureLevelArray} */ this.m_levels = new sglrReferenceContext.TextureLevelArray();
+ };
+
+ /**
+ */
+ sglrReferenceContext.Texture3D.prototype = Object.create(sglrReferenceContext.Texture.prototype);
+ sglrReferenceContext.Texture3D.prototype.constructor = sglrReferenceContext.Texture3D;
+
+ sglrReferenceContext.Texture3D.prototype.clearLevels = function() { this.m_levels.clear(); };
+
+ /**
+ * @param {number} level
+ * @return {boolean}
+ */
+ sglrReferenceContext.Texture3D.prototype.hasLevel = function(level) { return this.m_levels.hasLevel(level); };
+
+ /**
+ * @param {number} level
+ * @return {tcuTexture.PixelBufferAccess}
+ */
+ sglrReferenceContext.Texture3D.prototype.getLevel = function(level) { return this.m_levels.getLevel(level); };
+
+ /**
+ * @param {number} level
+ * @param {?tcuTexture.TextureFormat} format
+ * @param {number} width
+ * @param {number} height
+ * @param {number} depth
+ */
+ sglrReferenceContext.Texture3D.prototype.allocLevel = function(level, format, width, height, depth) {
+ this.m_levels.allocLevel(level, format, width, height, depth);
+ };
+
+ /**
+ * @return {boolean}
+ */
+ sglrReferenceContext.Texture3D.prototype.isComplete = function() {
+ /** @type {number} */ var baseLevel = this.getBaseLevel();
+
+ if (this.hasLevel(baseLevel)) {
+ /** @type {tcuTexture.PixelBufferAccess} */ var level0 = this.getLevel(baseLevel);
+ /** @type {boolean} */ var mipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
+
+ if (mipmap) {
+ /** @type {tcuTexture.TextureFormat} */ var format = level0.getFormat();
+ /** @type {number} */ var w = level0.getWidth();
+ /** @type {number} */ var h = level0.getHeight();
+ /** @type {number} */ var d = level0.getDepth();
+ /** @type {number} */ var numLevels = Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels3D(w, h, d));
+
+ for (var levelNdx = 1; levelNdx < numLevels; levelNdx++) {
+ if (this.hasLevel(baseLevel + levelNdx)) {
+ /** @type {tcuTexture.PixelBufferAccess} */ var level = this.getLevel(baseLevel + levelNdx);
+ /** @type {number} */ var expectedW = sglrReferenceContext.getMipLevelSize(w, levelNdx);
+ /** @type {number} */ var expectedH = sglrReferenceContext.getMipLevelSize(h, levelNdx);
+ /** @type {number} */ var expectedD = sglrReferenceContext.getMipLevelSize(d, levelNdx);
+
+ if (level.getWidth() != expectedW ||
+ level.getHeight() != expectedH ||
+ level.getDepth() != expectedD ||
+ !level.getFormat().isEqual(format))
+ return false;
+ } else
+ return false;
+ }
+ }
+
+ return true;
+ } else
+ return false;
+ };
+
+ /**
+ */
+ sglrReferenceContext.Texture3D.prototype.updateView = function() {
+ /** @type {number} */ var baseLevel = this.getBaseLevel();
+
+ if (this.hasLevel(baseLevel) && !this.getLevel(baseLevel).isEmpty()) {
+ // Update number of levels in mipmap pyramid.
+ /** @type {number} */ var width = this.getLevel(baseLevel).getWidth();
+ /** @type {number} */ var height = this.getLevel(baseLevel).getHeight();
+ /** @type {boolean} */ var isMipmap = sglrReferenceContext.isMipmapFilter(this.getSampler().minFilter);
+ /** @type {number} */ var numLevels = isMipmap ? Math.min(this.getMaxLevel() - baseLevel + 1, sglrReferenceContext.getNumMipLevels2D(width, height)) : 1;
+
+ this.m_view = new tcuTexture.Texture3DView(numLevels, this.m_levels.getLevels().slice(baseLevel));
+ } else
+ this.m_view = new tcuTexture.Texture3DView(0, null);
+ };
+
+ /**
+ * @param {Array<number>} pos
+ * @param {number=} lod
+ * @return {Array<number>}
+ */
+ sglrReferenceContext.Texture3D.prototype.sample = function(pos, lod) { return this.m_view.sample(this.getSampler(), pos, lod) };
+
+ /**
+ * A container object for storing one of texture types;
+ * @constructor
+ */
+ sglrReferenceContext.TextureContainer = function() {
+ /** @type {sglrReferenceContext.Texture2D | sglrReferenceContext.TextureCube|sglrReferenceContext.Texture2DArray|sglrReferenceContext.Texture3D} */
+ this.texture = null;
+ /** @type {?sglrReferenceContext.TextureType} */ this.textureType = null;
+ };
+
+ /**
+ * @return {?sglrReferenceContext.TextureType}
+ */
+ sglrReferenceContext.TextureContainer.prototype.getType = function() { return this.textureType; };
+
+ /**
+ * @param {number} target
+ * @throws {Error}
+ */
+ sglrReferenceContext.TextureContainer.prototype.init = function(target) {
+ switch (target) {
+ case gl.TEXTURE_2D:
+ this.texture = new sglrReferenceContext.Texture2D();
+ this.textureType = sglrReferenceContext.TextureType.TYPE_2D;
+ break;
+ case gl.TEXTURE_CUBE_MAP:
+ this.texture = new sglrReferenceContext.TextureCube();
+ this.textureType = sglrReferenceContext.TextureType.TYPE_CUBE_MAP;
+ break;
+ case gl.TEXTURE_2D_ARRAY:
+ this.texture = new sglrReferenceContext.Texture2DArray();
+ this.textureType = sglrReferenceContext.TextureType.TYPE_2D_ARRAY;
+ break;
+ case gl.TEXTURE_3D:
+ this.texture = new sglrReferenceContext.Texture3D();
+ this.textureType = sglrReferenceContext.TextureType.TYPE_3D;
+ break;
+ /* TODO: Implement other types */
+ // case gl.TEXTURE_CUBE_MAP_ARRAY:
+ // this.textureType = sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY;
+ // break;
+ default: throw new Error('Unrecognized target: ' + target);
+ }
+ };
+
+ /**
+ * @enum
+ */
+ sglrReferenceContext.AttachmentPoint = {
+ ATTACHMENTPOINT_COLOR0: 0,
+ ATTACHMENTPOINT_DEPTH: 1,
+ ATTACHMENTPOINT_STENCIL: 2
+ };
+
+ /**
+ * @param {number} attachment
+ * @return {sglrReferenceContext.AttachmentPoint}
+ * @throws {Error}
+ */
+ sglrReferenceContext.mapGLAttachmentPoint = function(attachment) {
+ switch (attachment) {
+ case gl.COLOR_ATTACHMENT0: return sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_COLOR0;
+ case gl.DEPTH_ATTACHMENT: return sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH;
+ case gl.STENCIL_ATTACHMENT: return sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL;
+ default: throw new Error('Wrong attachment point:' + attachment);
+ }
+ };
+
+ /**
+ * @enum
+ */
+ sglrReferenceContext.AttachmentType = {
+ ATTACHMENTTYPE_RENDERBUFFER: 0,
+ ATTACHMENTTYPE_TEXTURE: 1
+ };
+
+ /**
+ * @enum
+ */
+ sglrReferenceContext.TexTarget = {
+ TEXTARGET_2D: 0,
+ TEXTARGET_CUBE_MAP_POSITIVE_X: 1,
+ TEXTARGET_CUBE_MAP_POSITIVE_Y: 2,
+ TEXTARGET_CUBE_MAP_POSITIVE_Z: 3,
+ TEXTARGET_CUBE_MAP_NEGATIVE_X: 4,
+ TEXTARGET_CUBE_MAP_NEGATIVE_Y: 5,
+ TEXTARGET_CUBE_MAP_NEGATIVE_Z: 6,
+ TEXTARGET_2D_ARRAY: 7,
+ TEXTARGET_3D: 8,
+ TEXTARGET_CUBE_MAP_ARRAY: 9
+ };
+
+ /**
+ * @param {?sglrReferenceContext.TexTarget} target
+ * @return {tcuTexture.CubeFace}
+ */
+ sglrReferenceContext.texTargetToFace = function(target) {
+ switch (target) {
+ case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_X: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_X;
+ case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_X: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_X;
+ case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Y: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Y;
+ case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_Y: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_Y;
+ case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Z: return tcuTexture.CubeFace.CUBEFACE_NEGATIVE_Z;
+ case sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_Z: return tcuTexture.CubeFace.CUBEFACE_POSITIVE_Z;
+ default: throw new Error('Invalid target ' + target);
+ }
+ };
+
+ /**
+ * @param {sglrReferenceContext.TexTarget} target
+ * @return {sglrReferenceContext.TexTarget}
+ * @throws {Error}
+ */
+ sglrReferenceContext.mapGLFboTexTarget = function(target) {
+ switch (target) {
+ case gl.TEXTURE_2D: return sglrReferenceContext.TexTarget.TEXTARGET_2D;
+ case gl.TEXTURE_CUBE_MAP_POSITIVE_X: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_X;
+ case gl.TEXTURE_CUBE_MAP_POSITIVE_Y: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_Y;
+ case gl.TEXTURE_CUBE_MAP_POSITIVE_Z: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_Z;
+ case gl.TEXTURE_CUBE_MAP_NEGATIVE_X: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_X;
+ case gl.TEXTURE_CUBE_MAP_NEGATIVE_Y: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Y;
+ case gl.TEXTURE_CUBE_MAP_NEGATIVE_Z: return sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Z;
+ default: throw new Error('Wrong texture target:' + target);
+ }
+ };
+
+ /**
+ * @constructor
+ */
+ sglrReferenceContext.Attachment = function() {
+ /** @type {?sglrReferenceContext.AttachmentType} */ this.type = null;
+ /** @type {sglrReferenceContext.TextureContainer|sglrReferenceContext.Renderbuffer} */ this.object = null; // TODO: fix reserved word
+ /** @type {?sglrReferenceContext.TexTarget} */ this.texTarget = null;
+ /** @type {number} */ this.level = 0;
+ /** @type {number} */ this.layer = 0;
+ };
+
+ /**
+ * @constructor
+ */
+ sglrReferenceContext.Framebuffer = function() {
+ /** @type {Array<sglrReferenceContext.Attachment>} */ this.m_attachments = [];
+ for (var key in sglrReferenceContext.AttachmentPoint)
+ this.m_attachments[sglrReferenceContext.AttachmentPoint[key]] = new sglrReferenceContext.Attachment();
+ };
+
+ /**
+ * @param {sglrReferenceContext.AttachmentPoint} point
+ * @return {sglrReferenceContext.Attachment}
+ */
+ sglrReferenceContext.Framebuffer.prototype.getAttachment = function(point) { return this.m_attachments[point]; };
+
+ /**
+ * @param {sglrReferenceContext.AttachmentPoint} point
+ * @param {sglrReferenceContext.Attachment} attachment
+ */
+ sglrReferenceContext.Framebuffer.prototype.setAttachment = function(point, attachment) { this.m_attachments[point] = attachment; };
+
+ // /**
+ // * @enum
+ // */
+ // var Format = {
+ // FORMAT_DEPTH_COMPONENT16: 0,
+ // FORMAT_RGBA4: 1,
+ // FORMAT_RGB5_A1: 2,
+ // FORMAT_RGB565: 3,
+ // FORMAT_STENCIL_INDEX8: 4
+ // };
+
+ /**
+ * @constructor
+ */
+ sglrReferenceContext.Renderbuffer = function() {
+ /** @type {tcuTexture.TextureLevel} */ this.m_data;
+ };
+
+ /**
+ * @param {tcuTexture.TextureFormat} format
+ * @param {number} width
+ * @param {number} height
+ */
+ sglrReferenceContext.Renderbuffer.prototype.setStorage = function(format, width, height) {
+ this.m_data = new tcuTexture.TextureLevel(format, width, height);
+ };
+
+ /**
+ * @return {number}
+ */
+ sglrReferenceContext.Renderbuffer.prototype.getWidth = function() { return this.m_data.getWidth(); };
+
+ /**
+ * @return {number}
+ */
+ sglrReferenceContext.Renderbuffer.prototype.getHeight = function() { return this.m_data.getHeight(); };
+
+ /**
+ * @return {?tcuTexture.TextureFormat}
+ */
+ sglrReferenceContext.Renderbuffer.prototype.getFormat = function() { return this.m_data.getFormat(); };
+
+ /**
+ * @return {tcuTexture.PixelBufferAccess}
+ */
+ sglrReferenceContext.Renderbuffer.prototype.getAccess = function() { return this.m_data.getAccess(); };
+
+ /**
+ * @constructor
+ * @param {number} maxVertexAttribs
+ */
+ sglrReferenceContext.VertexArray = function(maxVertexAttribs) {
+ /** @type {sglrReferenceContext.DataBuffer} */ this.m_elementArrayBufferBinding = null;
+
+ /** @type {Array<sglrReferenceContext.VertexArray.VertexAttribArray>} */this.m_arrays = [];
+ for (var i = 0; i < maxVertexAttribs; i++)
+ this.m_arrays.push(new sglrReferenceContext.VertexArray.VertexAttribArray());
+ };
+
+ /** @constructor */
+ sglrReferenceContext.VertexArray.VertexAttribArray = function() {
+ this.enabled = false;
+ this.size = 4;
+ this.stride = 0;
+ this.type = gl.FLOAT;
+
+ this.normalized = false;
+ this.integer = false;
+ this.divisor = 0;
+ this.offset = 0;
+ this.bufferBinding = null;
+ };
+
+ /**
+ * @constructor
+ */
+ sglrReferenceContext.DataBuffer = function() {
+ /** @type {?ArrayBuffer} */ this.m_data = null;
+ };
+
+ /**
+ * @param {number} size
+ */
+ sglrReferenceContext.DataBuffer.prototype.setStorage = function(size) {this.m_data = new ArrayBuffer(size); };
+
+ /**
+ * @return {number}
+ */
+ sglrReferenceContext.DataBuffer.prototype.getSize = function() {
+ /** @type {number} */ var size = 0;
+ if (this.m_data)
+ size = this.m_data.byteLength;
+ return size;
+ };
+
+ /**
+ * @return {?ArrayBuffer}
+ */
+ sglrReferenceContext.DataBuffer.prototype.getData = function() { return this.m_data; };
+
+ /**
+ * @param {ArrayBuffer|goog.NumberArray} data
+ */
+ sglrReferenceContext.DataBuffer.prototype.setData = function(data) {
+ /** @type {ArrayBuffer} */ var buffer;
+ /** @type {number} */ var offset = 0;
+ /** @type {number} */ var byteLength = data.byteLength;
+ if (data instanceof ArrayBuffer)
+ buffer = data;
+ else {
+ buffer = data.buffer;
+ offset = data.byteOffset;
+ }
+
+ if (!buffer)
+ throw new Error('Invalid buffer');
+
+ this.m_data = buffer.slice(offset, offset + byteLength);
+ };
+
+ /**
+ * @param {number} offset
+ * @param {goog.NumberArray} data
+ */
+ sglrReferenceContext.DataBuffer.prototype.setSubData = function(offset, data) {
+ /** @type {ArrayBuffer} */ var buffer;
+ /** @type {number} */ var srcOffset = 0;
+ /** @type {number} */ var byteLength = data.byteLength;
+ if (data instanceof ArrayBuffer)
+ buffer = data;
+ else {
+ buffer = data.buffer;
+ srcOffset = data.byteOffset;
+ }
+
+ if (!buffer)
+ throw new Error('Invalid buffer');
+
+ /** @type {goog.NumberArray} */ var src = new Uint8Array(buffer, srcOffset, byteLength);
+ /** @type {goog.NumberArray} */ var dst = new Uint8Array(this.m_data, offset, byteLength);
+ dst.set(src);
+ };
+
+ // /**
+ // * @constructor
+ // */
+ // var ObjectManager = function() {
+ // this.m_objects = {};
+ // };
+
+ // ObjectManager.prototype.insert = function(obj) {
+ // var name = obj.getName();
+ // if (!name)
+ // throw new Error("Cannot insert unnamed object");
+ // this.m_objects[name] = obj;
+ // };
+
+ // ObjectManager.prototype.find = function(name) { return this.m_objects[name]; };
+
+ // ObjectManager.prototype.acquireReference = function(obj) {
+ // if (this.find(obj.getName()) !== obj)
+ // throw new Error("Object is not in the object manager");
+ // obj.incRefCount();
+ // };
+
+ // ObjectManager.prototype.releaseReference = function(obj) {
+ // if (this.find(obj.getName()) !== obj)
+ // throw new Error("Object is not in the object manager");
+
+ // obj.decRefCount();
+
+ // if (obj.getRefCount() == 0)
+ // delete this.m_objects[obj.getName()];
+ // };
+
+ // ObjectManager.prototype.getAll = function() { return this.m_objects; };
+
+ /**
+ * @constructor
+ */
+ sglrReferenceContext.TextureUnit = function() {
+ /** @type {?sglrReferenceContext.TextureContainer} */ this.tex2DBinding = null;
+ /** @type {?sglrReferenceContext.TextureContainer} */ this.texCubeBinding = null;
+ /** @type {?sglrReferenceContext.TextureContainer} */ this.tex2DArrayBinding = null;
+ /** @type {?sglrReferenceContext.TextureContainer} */ this.tex3DBinding = null;
+ /** @type {?sglrReferenceContext.TextureContainer} */ this.texCubeArrayBinding = null;
+ };
+
+ /**
+ * @constructor
+ */
+ sglrReferenceContext.StencilState = function() {
+ /** @type {number} */ this.func = gl.ALWAYS;
+ /** @type {number} */ this.ref = 0;
+ /** @type {number} */ this.opMask = ~0;
+ /** @type {number} */ this.opStencilFail = gl.KEEP;
+ /** @type {number} */ this.opDepthFail = gl.KEEP;
+ /** @type {number} */ this.opDepthPass = gl.KEEP;
+ /** @type {number} */ this.writeMask = ~0;
+ };
+
+ /**
+ * @param {tcuPixelFormat.PixelFormat} pixelFmt
+ * @return {tcuTexture.TextureFormat}
+ * @throws {Error}
+ */
+ sglrReferenceContext.toTextureFormat = function(pixelFmt) {
+ if (pixelFmt.equals(8, 8, 8, 8))
+ return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8);
+ else if (pixelFmt.equals(8, 8, 8, 0))
+ return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8);
+ else if (pixelFmt.equals(4, 4, 4, 4))
+ return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_4444);
+ else if (pixelFmt.equals(5, 5, 5, 1))
+ return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_SHORT_5551);
+ else if (pixelFmt.equals(5, 6, 5, 0))
+ return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_SHORT_565);
+
+ throw new Error('Could not map pixel format:' + pixelFmt);
+ };
+
+ /**
+ * @param {number} depthBits
+ * @return {tcuTexture.TextureFormat}
+ * @throws {Error}
+ */
+ sglrReferenceContext.getDepthFormat = function(depthBits) {
+ switch (depthBits) {
+ case 8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNORM_INT8);
+ case 16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNORM_INT16);
+ case 24: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.UNSIGNED_INT_24_8);
+ case 32: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.D, tcuTexture.ChannelType.FLOAT);
+ default:
+ throw new Error("Can't map depth buffer format, bits: " + depthBits);
+ }
+ };
+
+ /**
+ * @param {number} stencilBits
+ * @return {tcuTexture.TextureFormat}
+ * @throws {Error}
+ */
+ sglrReferenceContext.getStencilFormat = function(stencilBits) {
+ switch (stencilBits) {
+ case 8: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT8);
+ case 16: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT16);
+ case 24: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT_24_8);
+ case 32: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.S, tcuTexture.ChannelType.UNSIGNED_INT32);
+ default:
+ throw new Error("Can't map stencil buffer format, bits: " + stencilBits);
+ }
+ };
+
+ /**
+ * @constructor
+ * @param {tcuPixelFormat.PixelFormat} colorBits
+ * @param {number} depthBits
+ * @param {number} stencilBits
+ * @param {number} width
+ * @param {number} height
+ * @param {number=} samples_
+ */
+ sglrReferenceContext.ReferenceContextBuffers = function(colorBits, depthBits, stencilBits, width, height, samples_) {
+ if (samples_ === undefined)
+ samples_ = 1;
+
+ /** @type {number} */ var samples = samples_;
+ /** @type {tcuTexture.TextureLevel} */ this.m_colorbuffer = new tcuTexture.TextureLevel(sglrReferenceContext.toTextureFormat(colorBits), samples, width, height);
+
+ if (depthBits > 0)
+ /** @type {tcuTexture.TextureLevel} */ this.m_depthbuffer = new tcuTexture.TextureLevel(sglrReferenceContext.getDepthFormat(depthBits), samples, width, height);
+
+ if (stencilBits > 0)
+ /** @type {tcuTexture.TextureLevel} */ this.m_stencilbuffer = new tcuTexture.TextureLevel(sglrReferenceContext.getStencilFormat(stencilBits), samples, width, height);
+ };
+
+ /**
+ * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
+ */
+ sglrReferenceContext.ReferenceContextBuffers.prototype.getColorbuffer = function() { return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromMultisampleAccess(this.m_colorbuffer.getAccess()); };
+
+ /**
+ * @return {?rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
+ */
+ sglrReferenceContext.ReferenceContextBuffers.prototype.getDepthbuffer = function() { return this.m_depthbuffer !== undefined ? rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromMultisampleAccess(this.m_depthbuffer.getAccess()) : null; };
+
+ /**
+ * @return {?rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
+ */
+ sglrReferenceContext.ReferenceContextBuffers.prototype.getStencilbuffer = function() { return this.m_stencilbuffer !== undefined ? rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromMultisampleAccess(this.m_stencilbuffer.getAccess()) : null; };
+
+ /**
+ * @param {sglrReferenceContext.ReferenceContextLimits} limits
+ * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} colorbuffer
+ * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} depthbuffer
+ * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} stencilbuffer
+ * @constructor
+ */
+ sglrReferenceContext.ReferenceContext = function(limits, colorbuffer, depthbuffer, stencilbuffer) {
+ /** @type {sglrReferenceContext.ReferenceContextLimits} */ this.m_limits = limits;
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ this.m_defaultColorbuffer = colorbuffer;
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ this.m_defaultDepthbuffer = depthbuffer;
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ this.m_defaultStencilbuffer = stencilbuffer;
+ /** @type {Array<number>} */ this.m_viewport = [0, 0, colorbuffer.raw().getHeight(), colorbuffer.raw().getDepth()];
+ /** @type {Array<sglrReferenceContext.TextureUnit>} */ this.m_textureUnits = [];
+ for (var i = 0; i < this.m_limits.maxTextureImageUnits; i++)
+ this.m_textureUnits.push(new sglrReferenceContext.TextureUnit());
+ /** @type {number} */ this.m_activeTexture = 0;
+ /** @type {number} */ this.m_lastError = gl.NO_ERROR;
+ // this.m_textures = new ObjectManager();
+ /** @type {number} */ this.m_pixelUnpackRowLength = 0;
+ /** @type {number} */ this.m_pixelUnpackSkipRows = 0;
+ /** @type {number} */ this.m_pixelUnpackSkipPixels = 0;
+ /** @type {number} */ this.m_pixelUnpackImageHeight = 0;
+ /** @type {number} */ this.m_pixelUnpackSkipImages = 0;
+ /** @type {number} */ this.m_pixelUnpackAlignment = 4;
+ /** @type {number} */ this.m_pixelPackAlignment = 4;
+ /** @type {Array<number>} */ this.m_clearColor = [0, 0, 0, 0];
+ /** @type {number} */ this.m_clearDepth = 1;
+ /** @type {number} */ this.m_clearStencil = 0;
+ /** @type {Array<number>} */ this.m_scissorBox = this.m_viewport;
+ /** @type {boolean} */ this.m_blendEnabled = false;
+ /** @type {boolean} */ this.m_scissorEnabled = false;
+ /** @type {boolean} */ this.m_depthTestEnabled = false;
+ /** @type {boolean} */ this.m_stencilTestEnabled = false;
+ /** @type {boolean} */ this.m_polygonOffsetFillEnabled = false;
+ /** @type {boolean} */ this.m_primitiveRestartFixedIndex = true; //always on
+ /** @type {boolean} */ this.m_primitiveRestartSettableIndex = true; //always on
+ /** @type {Array<sglrReferenceContext.StencilState>} */ this.m_stencil = [];
+ for (var type in rrDefs.FaceType)
+ this.m_stencil[rrDefs.FaceType[type]] = new sglrReferenceContext.StencilState();
+ /** @type {number} */ this.m_depthFunc = gl.LESS;
+ /** @type {number} */ this.m_depthRangeNear = 0;
+ /** @type {number} */ this.m_depthRangeFar = 1;
+ /** @type {number} */ this.m_polygonOffsetFactor = 0;
+ /** @type {number} */ this.m_polygonOffsetUnits = 0;
+ /** @type {number} */ this.m_blendModeRGB = gl.FUNC_ADD;
+ /** @type {number} */ this.m_blendModeAlpha = gl.FUNC_ADD;
+ /** @type {number} */ this.m_blendFactorSrcRGB = gl.ONE;
+ /** @type {number} */ this.m_blendFactorDstRGB = gl.ZERO;
+ /** @type {number} */ this.m_blendFactorSrcAlpha = gl.ONE;
+ /** @type {number} */ this.m_blendFactorDstAlpha = gl.ZERO;
+ /** @type {Array<number>} */ this.m_blendColor = [0, 0, 0, 0];
+ /** @type {boolean} */ this.m_sRGBUpdateEnabled = true;
+ /** @type {Array<boolean>} */ this.m_colorMask = [true, true, true, true];
+ /** @type {boolean} */ this.m_depthMask = true;
+ /** @type {sglrReferenceContext.VertexArray} */ this.m_defaultVAO = new sglrReferenceContext.VertexArray(this.m_limits.maxVertexAttribs);
+ /** @type {sglrReferenceContext.VertexArray} */ this.m_vertexArrayBinding = this.m_defaultVAO;
+ /** @type {sglrReferenceContext.DataBuffer} */ this.m_arrayBufferBinding = null;
+ /** @type {sglrReferenceContext.DataBuffer} */ this.m_copyReadBufferBinding = null;
+ /** @type {sglrReferenceContext.DataBuffer} */ this.m_copyWriteBufferBinding = null;
+ /** @type {sglrReferenceContext.DataBuffer} */ this.m_drawIndirectBufferBinding = null;
+ /** @type {sglrReferenceContext.DataBuffer} */ this.m_pixelPackBufferBinding = null;
+ /** @type {sglrReferenceContext.DataBuffer} */ this.m_pixelUnpackBufferBinding = null;
+ /** @type {sglrReferenceContext.DataBuffer} */ this.m_transformFeedbackBufferBinding = null;
+ /** @type {sglrReferenceContext.DataBuffer} */ this.m_uniformBufferBinding = null;
+ /** @type {sglrReferenceContext.Framebuffer} */ this.m_readFramebufferBinding = null;
+ /** @type {sglrReferenceContext.Framebuffer} */ this.m_drawFramebufferBinding = null;
+ /** @type {sglrReferenceContext.Renderbuffer} */ this.m_renderbufferBinding = null;
+ /** @type {sglrShaderProgram.ShaderProgram} */ this.m_currentProgram = null;
+ /** @type {Array<rrGenericVector.GenericVec4>} */ this.m_currentAttribs = [];
+ for (var i = 0; i < this.m_limits.maxVertexAttribs; i++)
+ this.m_currentAttribs.push(new rrGenericVector.GenericVec4());
+ /** @type {number} */ this.m_lineWidth = 1;
+
+ /** @type {sglrReferenceContext.TextureContainer} */ this.m_emptyTex2D = new sglrReferenceContext.TextureContainer();
+ this.m_emptyTex2D.init(gl.TEXTURE_2D);
+ this.m_emptyTex2D.texture.getSampler().wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ this.m_emptyTex2D.texture.getSampler().wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ this.m_emptyTex2D.texture.getSampler().minFilter = tcuTexture.FilterMode.NEAREST;
+ this.m_emptyTex2D.texture.getSampler().magFilter = tcuTexture.FilterMode.NEAREST;
+ this.m_emptyTex2D.texture.allocLevel(0, new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), 1, 1);
+ this.m_emptyTex2D.texture.getLevel(0).setPixel([0, 0, 0, 1], 0, 0);
+ this.m_emptyTex2D.texture.updateView();
+
+ /** @type {sglrReferenceContext.TextureContainer} */ this.m_emptyTexCube = new sglrReferenceContext.TextureContainer();
+ this.m_emptyTexCube.init(gl.TEXTURE_CUBE_MAP);
+ this.m_emptyTexCube.texture.getSampler().wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ this.m_emptyTexCube.texture.getSampler().wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ this.m_emptyTexCube.texture.getSampler().minFilter = tcuTexture.FilterMode.NEAREST;
+ this.m_emptyTexCube.texture.getSampler().magFilter = tcuTexture.FilterMode.NEAREST;
+
+ for (var face in tcuTexture.CubeFace) {
+ this.m_emptyTexCube.texture.allocLevel(0, tcuTexture.CubeFace[face],
+ new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), 1, 1);
+ this.m_emptyTexCube.texture.getFace(0, tcuTexture.CubeFace[face]).setPixel([0, 0, 0, 1], 0, 0);
+ }
+ this.m_emptyTexCube.texture.updateView();
+
+ /** @type {sglrReferenceContext.TextureContainer} */ this.m_emptyTex2DArray = new sglrReferenceContext.TextureContainer();
+ this.m_emptyTex2DArray.init(gl.TEXTURE_2D_ARRAY);
+ this.m_emptyTex2DArray.texture.getSampler().wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ this.m_emptyTex2DArray.texture.getSampler().wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ this.m_emptyTex2DArray.texture.getSampler().wrapR = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ this.m_emptyTex2DArray.texture.getSampler().minFilter = tcuTexture.FilterMode.NEAREST;
+ this.m_emptyTex2DArray.texture.getSampler().magFilter = tcuTexture.FilterMode.NEAREST;
+ this.m_emptyTex2DArray.texture.allocLevel(0, new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), 1, 1);
+ this.m_emptyTex2DArray.texture.getLevel(0).setPixel([0, 0, 0, 1], 0, 0);
+ this.m_emptyTex2DArray.texture.updateView();
+
+ /** @type {sglrReferenceContext.TextureContainer} */ this.m_emptyTex3D = new sglrReferenceContext.TextureContainer();
+ this.m_emptyTex3D.init(gl.TEXTURE_3D);
+ this.m_emptyTex3D.texture.getSampler().wrapS = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ this.m_emptyTex3D.texture.getSampler().wrapT = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ this.m_emptyTex3D.texture.getSampler().wrapR = tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ this.m_emptyTex3D.texture.getSampler().minFilter = tcuTexture.FilterMode.NEAREST;
+ this.m_emptyTex3D.texture.getSampler().magFilter = tcuTexture.FilterMode.NEAREST;
+ this.m_emptyTex3D.texture.allocLevel(0, new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8), 1, 1);
+ this.m_emptyTex3D.texture.getLevel(0).setPixel([0, 0, 0, 1], 0, 0);
+ this.m_emptyTex3D.texture.updateView();
+
+ /** @type {sglrReferenceContext.TextureType} */ this.m_type;
+
+ /** @type {boolean} */ this.m_immutable;
+
+ /** @type {tcuTexture.Sampler} */ this.m_sampler;
+ /** @type {number} */ this.m_baseLevel;
+ /** @type {number} */ this.m_maxLevel;
+ };
+
+ /**
+ * @return {number}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getWidth = function() { return this.m_defaultColorbuffer.raw().getHeight(); };
+
+ /**
+ * @return {number}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getHeight = function() { return this.m_defaultColorbuffer.raw().getDepth(); };
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width
+ * @param {number} height
+ */
+ sglrReferenceContext.ReferenceContext.prototype.viewport = function(x, y, width, height) { this.m_viewport = [x, y, width, height]; };
+
+ /**
+ * @param {number} texture
+ */
+ sglrReferenceContext.ReferenceContext.prototype.activeTexture = function(texture) {
+ if (deMath.deInBounds32(texture, gl.TEXTURE0, gl.TEXTURE0 + this.m_textureUnits.length))
+ this.m_activeTexture = texture - gl.TEXTURE0;
+ else
+ this.setError(gl.INVALID_ENUM);
+ };
+
+ /**
+ * @param {number} error
+ */
+ sglrReferenceContext.ReferenceContext.prototype.setError = function(error) {
+ if (this.m_lastError == gl.NO_ERROR)
+ this.m_lastError = error;
+ };
+
+ /**
+ * @return {number} error
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getError = function() {
+ /** @type {number} */ var err = this.m_lastError;
+ this.m_lastError = gl.NO_ERROR;
+ return err;
+ };
+
+ /**
+ * @param {boolean} condition
+ * @param {number} error
+ */
+ sglrReferenceContext.ReferenceContext.prototype.conditionalSetError = function(condition, error) {
+ if (condition)
+ this.setError(error);
+ return condition;
+ };
+
+ /**
+ * @param {number} target
+ * @param {sglrReferenceContext.TextureContainer} texture
+ * @throws {Error}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.bindTexture = function(target, texture) {
+ /** @type {number} */ var unitNdx = this.m_activeTexture;
+
+ if (this.conditionalSetError((target != gl.TEXTURE_2D &&
+ target != gl.TEXTURE_CUBE_MAP &&
+ target != gl.TEXTURE_2D_ARRAY &&
+ target != gl.TEXTURE_3D), // &&
+ // target != gl.TEXTURE_CUBE_MAP_ARRAY),
+ gl.INVALID_ENUM))
+ return;
+
+ if (!texture) {
+ // Clear binding.
+ switch (target) {
+ case gl.TEXTURE_2D: this.setTex2DBinding(unitNdx, null); break;
+ case gl.TEXTURE_CUBE_MAP: this.setTexCubeBinding(unitNdx, null); break;
+ case gl.TEXTURE_2D_ARRAY: this.setTex2DArrayBinding(unitNdx, null); break;
+ case gl.TEXTURE_3D: this.setTex3DBinding(unitNdx, null); break;
+ default:
+ throw new Error('Unrecognized target: ' + target);
+ }
+ } else {
+ if (texture.textureType == null) {
+ texture.init(target);
+ } else {
+ // Validate type.
+ /** @type {sglrReferenceContext.TextureType} */ var expectedType;
+ switch (target) {
+ case gl.TEXTURE_2D: expectedType = sglrReferenceContext.TextureType.TYPE_2D; break;
+ case gl.TEXTURE_CUBE_MAP: expectedType = sglrReferenceContext.TextureType.TYPE_CUBE_MAP; break;
+ case gl.TEXTURE_2D_ARRAY: expectedType = sglrReferenceContext.TextureType.TYPE_2D_ARRAY; break;
+ case gl.TEXTURE_3D: expectedType = sglrReferenceContext.TextureType.TYPE_3D; break;
+ default: throw new Error('Unrecognized target: ' + target);
+ }
+ if (this.conditionalSetError((texture.textureType != expectedType), gl.INVALID_OPERATION))
+ return;
+ }
+ switch (target) {
+ case gl.TEXTURE_2D: this.setTex2DBinding(unitNdx, texture); break;
+ case gl.TEXTURE_CUBE_MAP: this.setTexCubeBinding(unitNdx, texture); break;
+ case gl.TEXTURE_2D_ARRAY: this.setTex2DArrayBinding(unitNdx, texture); break;
+ case gl.TEXTURE_3D: this.setTex3DBinding(unitNdx, texture); break;
+ default:
+ throw new Error('Unrecognized target: ' + target);
+ }
+ }
+ };
+
+ /**
+ * @param {number} unitNdx
+ * @param {?sglrReferenceContext.TextureContainer} texture
+ */
+ sglrReferenceContext.ReferenceContext.prototype.setTexCubeBinding = function(unitNdx, texture) {
+ if (this.m_textureUnits[unitNdx].texCubeBinding) {
+ this.m_textureUnits[unitNdx].texCubeBinding = null;
+ }
+
+ if (texture) {
+ this.m_textureUnits[unitNdx].texCubeBinding = texture;
+ }
+ };
+
+ /**
+ * @param {number} unitNdx
+ * @param {?sglrReferenceContext.TextureContainer} texture
+ */
+ sglrReferenceContext.ReferenceContext.prototype.setTex2DBinding = function(unitNdx, texture) {
+ if (this.m_textureUnits[unitNdx].tex2DBinding) {
+ // this.m_textures.releaseReference(this.m_textureUnits[unitNdx].tex2DBinding);
+ this.m_textureUnits[unitNdx].tex2DBinding = null;
+ }
+
+ if (texture) {
+ // this.m_textures.acquireReference(texture);
+ this.m_textureUnits[unitNdx].tex2DBinding = texture;
+ }
+ };
+
+ /**
+ * @param {number} unitNdx
+ * @param {?sglrReferenceContext.TextureContainer} texture
+ */
+ sglrReferenceContext.ReferenceContext.prototype.setTex2DArrayBinding = function(unitNdx, texture) {
+ if (this.m_textureUnits[unitNdx].tex2DArrayBinding) {
+ // this.m_textures.releaseReference(this.m_textureUnits[unitNdx].tex2DArrayBinding);
+ this.m_textureUnits[unitNdx].tex2DArrayBinding = null;
+ }
+
+ if (texture) {
+ // this.m_textures.acquireReference(texture);
+ this.m_textureUnits[unitNdx].tex2DArrayBinding = texture;
+ }
+ };
+
+ /**
+ * @param {number} unitNdx
+ * @param {?sglrReferenceContext.TextureContainer} texture
+ */
+ sglrReferenceContext.ReferenceContext.prototype.setTex3DBinding = function(unitNdx, texture) {
+ if (this.m_textureUnits[unitNdx].tex3DBinding) {
+ // this.m_textures.releaseReference(this.m_textureUnits[unitNdx].tex3DBinding);
+ this.m_textureUnits[unitNdx].tex3DBinding = null;
+ }
+
+ if (texture) {
+ // this.m_textures.acquireReference(texture);
+ this.m_textureUnits[unitNdx].tex3DBinding = texture;
+ }
+ };
+
+ /**
+ * @return {sglrReferenceContext.TextureContainer}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.createTexture = function() { return new sglrReferenceContext.TextureContainer(); };
+
+ /**
+ * @param {sglrReferenceContext.Texture} texture
+ */
+ sglrReferenceContext.ReferenceContext.prototype.deleteTexture = function(texture) { /*empty*/ };
+
+ /**
+ * @param {number} target
+ * @param {framework.opengl.simplereference.sglrReferenceContext.Framebuffer} fbo
+ */
+ sglrReferenceContext.ReferenceContext.prototype.bindFramebuffer = function(target, fbo) {
+ if (this.conditionalSetError((target != gl.FRAMEBUFFER &&
+ target != gl.DRAW_FRAMEBUFFER &&
+ target != gl.READ_FRAMEBUFFER), gl.INVALID_ENUM))
+ return;
+ for (var ndx = 0; ndx < 2; ndx++) {
+ /** @type {number} */ var bindingTarget = ndx ? gl.DRAW_FRAMEBUFFER : gl.READ_FRAMEBUFFER;
+
+ if (target != gl.FRAMEBUFFER && target != bindingTarget)
+ continue; // Doesn't match this target.
+
+ if (ndx)
+ this.m_drawFramebufferBinding = fbo;
+ else
+ this.m_readFramebufferBinding = fbo;
+ }
+ };
+
+ /**
+ * @return {sglrReferenceContext.Framebuffer}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.createFramebuffer = function() { return new sglrReferenceContext.Framebuffer(); };
+
+ /**
+ * @param {sglrReferenceContext.Framebuffer} fbo
+ */
+ sglrReferenceContext.ReferenceContext.prototype.deleteFramebuffer = function(fbo) { /*empty*/ };
+
+ /**
+ * @param {number} target
+ * @param {sglrReferenceContext.Renderbuffer} rbo
+ */
+ sglrReferenceContext.ReferenceContext.prototype.bindRenderbuffer = function(target, rbo) {
+ if (this.conditionalSetError(target != gl.RENDERBUFFER, gl.INVALID_ENUM))
+ return;
+
+ this.m_renderbufferBinding = rbo;
+ };
+
+ /**
+ * @return {sglrReferenceContext.Renderbuffer}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.createRenderbuffer = function() { return new sglrReferenceContext.Renderbuffer(); };
+
+ /**
+ * @param {sglrReferenceContext.Renderbuffer} rbo
+ */
+ sglrReferenceContext.ReferenceContext.prototype.deleteRenderbuffer = function(rbo) { /*empty*/ };
+
+ /**
+ * @param {number} pname
+ * @param {number} param
+ */
+ sglrReferenceContext.ReferenceContext.prototype.pixelStorei = function(pname, param) {
+ switch (pname) {
+ case gl.UNPACK_ALIGNMENT:
+ if (this.conditionalSetError((param != 1 && param != 2 && param != 4 && param != 8), gl.INVALID_VALUE)) return;
+ this.m_pixelUnpackAlignment = param;
+ break;
+
+ case gl.PACK_ALIGNMENT:
+ if (this.conditionalSetError((param != 1 && param != 2 && param != 4 && param != 8), gl.INVALID_VALUE)) return;
+ this.m_pixelPackAlignment = param;
+ break;
+
+ case gl.UNPACK_ROW_LENGTH:
+ if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return;
+ this.m_pixelUnpackRowLength = param;
+ break;
+
+ case gl.UNPACK_SKIP_ROWS:
+ if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return;
+ this.m_pixelUnpackSkipRows = param;
+ break;
+
+ case gl.UNPACK_SKIP_PIXELS:
+ if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return;
+ this.m_pixelUnpackSkipPixels = param;
+ break;
+
+ case gl.UNPACK_IMAGE_HEIGHT:
+ if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return;
+ this.m_pixelUnpackImageHeight = param;
+ break;
+
+ case gl.UNPACK_SKIP_IMAGES:
+ if (this.conditionalSetError(param < 0, gl.INVALID_VALUE)) return;
+ this.m_pixelUnpackSkipImages = param;
+ break;
+
+ default:
+ this.setError(gl.INVALID_ENUM);
+ }
+ };
+
+ /**
+ * @param {number} red
+ * @param {number} green
+ * @param {number} blue
+ * @param {number} alpha
+ */
+ sglrReferenceContext.ReferenceContext.prototype.clearColor = function(red, green, blue, alpha) {
+ this.m_clearColor = [deMath.clamp(red, 0, 1),
+ deMath.clamp(green, 0, 1),
+ deMath.clamp(blue, 0, 1),
+ deMath.clamp(alpha, 0, 1)];
+ };
+
+ /**
+ * @param {number} depth
+ */
+ sglrReferenceContext.ReferenceContext.prototype.clearDepthf = function(depth) {
+ this.m_clearDepth = deMath.clamp(depth, 0, 1);
+ };
+
+ /**
+ * @param {number} stencil
+ */
+ sglrReferenceContext.ReferenceContext.prototype.clearStencil = function(stencil) {
+ this.m_clearStencil = stencil;
+ };
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width
+ * @param {number} height
+ */
+ sglrReferenceContext.ReferenceContext.prototype.scissor = function(x, y, width, height) {
+ if (this.conditionalSetError(width < 0 || height < 0, gl.INVALID_VALUE))
+ return;
+ this.m_scissorBox = [x, y, width, height];
+ };
+
+ /**
+ * @param {number} cap
+ */
+ sglrReferenceContext.ReferenceContext.prototype.enable = function(cap) {
+ switch (cap) {
+ case gl.BLEND: this.m_blendEnabled = true; break;
+ case gl.SCISSOR_TEST: this.m_scissorEnabled = true; break;
+ case gl.DEPTH_TEST: this.m_depthTestEnabled = true; break;
+ case gl.STENCIL_TEST: this.m_stencilTestEnabled = true; break;
+ case gl.POLYGON_OFFSET_FILL: this.m_polygonOffsetFillEnabled = true; break;
+
+ case gl.DITHER:
+ // Not implemented - just ignored.
+ break;
+
+ default:
+ this.setError(gl.INVALID_ENUM);
+ break;
+ }
+ };
+
+ /**
+ * @param {number} cap
+ */
+ sglrReferenceContext.ReferenceContext.prototype.disable = function(cap) {
+ switch (cap) {
+ case gl.BLEND: this.m_blendEnabled = false; break;
+ case gl.SCISSOR_TEST: this.m_scissorEnabled = false; break;
+ case gl.DEPTH_TEST: this.m_depthTestEnabled = false; break;
+ case gl.STENCIL_TEST: this.m_stencilTestEnabled = false; break;
+ case gl.POLYGON_OFFSET_FILL: this.m_polygonOffsetFillEnabled = false; break;
+
+ case gl.DITHER:
+ // Not implemented - just ignored.
+ break;
+
+ default:
+ this.setError(gl.INVALID_ENUM);
+ break;
+ }
+ };
+
+ /**
+ * @param {number} func
+ * @param {number} ref
+ * @param {number} mask
+ */
+ sglrReferenceContext.ReferenceContext.prototype.stencilFunc = function(func, ref, mask) {
+ this.stencilFuncSeparate(gl.FRONT_AND_BACK, func, ref, mask);
+ };
+
+ /**
+ * @param {number} face
+ * @param {number} func
+ * @param {number} ref
+ * @param {number} mask
+ */
+ sglrReferenceContext.ReferenceContext.prototype.stencilFuncSeparate = function(face, func, ref, mask) {
+ /** @type {boolean} */ var setFront = face == gl.FRONT || face == gl.FRONT_AND_BACK;
+ /** @type {boolean} */ var setBack = face == gl.BACK || face == gl.FRONT_AND_BACK;
+
+ if (this.conditionalSetError(!sglrReferenceContext.isValidCompareFunc(func), gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(!setFront && !setBack, gl.INVALID_ENUM))
+ return;
+
+ for (var key in rrDefs.FaceType) {
+ /** @type {number} */ var type = rrDefs.FaceType[key];
+ if ((type == rrDefs.FaceType.FACETYPE_FRONT && setFront) ||
+ (type == rrDefs.FaceType.FACETYPE_BACK && setBack)) {
+ this.m_stencil[type].func = func;
+ this.m_stencil[type].ref = ref;
+ this.m_stencil[type].opMask = mask;
+ }
+ }
+ };
+
+ /**
+ * @param {number} func
+ * @return {boolean}
+ */
+ sglrReferenceContext.isValidCompareFunc = function(func) {
+ switch (func) {
+ case gl.NEVER:
+ case gl.LESS:
+ case gl.LEQUAL:
+ case gl.GREATER:
+ case gl.GEQUAL:
+ case gl.EQUAL:
+ case gl.NOTEQUAL:
+ case gl.ALWAYS:
+ return true;
+
+ default:
+ return false;
+ }
+ };
+
+ /**
+ * @param {number} op
+ * @return {boolean}
+ */
+ sglrReferenceContext.isValidStencilOp = function(op) {
+ switch (op) {
+ case gl.KEEP:
+ case gl.ZERO:
+ case gl.REPLACE:
+ case gl.INCR:
+ case gl.INCR_WRAP:
+ case gl.DECR:
+ case gl.DECR_WRAP:
+ case gl.INVERT:
+ return true;
+
+ default:
+ return false;
+ }
+ };
+
+ /**
+ * @param {number} sfail
+ * @param {number} dpfail
+ * @param {number} dppass
+ */
+ sglrReferenceContext.ReferenceContext.prototype.stencilOp = function(sfail, dpfail, dppass) {
+ this.stencilOpSeparate(gl.FRONT_AND_BACK, sfail, dpfail, dppass);
+ };
+
+ /**
+ * @param {number} face
+ * @param {number} sfail
+ * @param {number} dpfail
+ * @param {number} dppass
+ */
+ sglrReferenceContext.ReferenceContext.prototype.stencilOpSeparate = function(face, sfail, dpfail, dppass) {
+ /** @type {boolean} */ var setFront = face == gl.FRONT || face == gl.FRONT_AND_BACK;
+ /** @type {boolean} */ var setBack = face == gl.BACK || face == gl.FRONT_AND_BACK;
+
+ if (this.conditionalSetError((!sglrReferenceContext.isValidStencilOp(sfail) ||
+ !sglrReferenceContext.isValidStencilOp(dpfail) ||
+ !sglrReferenceContext.isValidStencilOp(dppass)),
+ gl.INVALID_ENUM))
+ return;
+
+ if (this.conditionalSetError(!setFront && !setBack, gl.INVALID_ENUM))
+ return;
+
+ for (var key in rrDefs.FaceType) {
+ /** @type {number} */ var type = rrDefs.FaceType[key];
+ if ((type == rrDefs.FaceType.FACETYPE_FRONT && setFront) ||
+ (type == rrDefs.FaceType.FACETYPE_BACK && setBack)) {
+ this.m_stencil[type].opStencilFail = sfail;
+ this.m_stencil[type].opDepthFail = dpfail;
+ this.m_stencil[type].opDepthPass = dppass;
+ }
+ }
+ };
+
+ /**
+ * @param {number} func
+ */
+ sglrReferenceContext.ReferenceContext.prototype.depthFunc = function(func) {
+ if (this.conditionalSetError(!sglrReferenceContext.isValidCompareFunc(func), gl.INVALID_ENUM))
+ return;
+ this.m_depthFunc = func;
+ };
+
+ /**
+ * @param {number} n
+ * @param {number} f
+ */
+ sglrReferenceContext.ReferenceContext.prototype.depthRange = function(n, f) {
+ this.m_depthRangeNear = deMath.clamp(n, 0, 1);
+ this.m_depthRangeFar = deMath.clamp(f, 0, 1);
+ };
+
+ /**
+ * @param {number} factor
+ * @param {number} units
+ */
+ sglrReferenceContext.ReferenceContext.prototype.polygonOffset = function(factor, units) {
+ this.m_polygonOffsetFactor = factor;
+ this.m_polygonOffsetUnits = units;
+ };
+
+ /**
+ * @param {number} mode
+ * @return {boolean}
+ */
+ sglrReferenceContext.isValidBlendEquation = function(mode) {
+ return mode == gl.FUNC_ADD ||
+ mode == gl.FUNC_SUBTRACT ||
+ mode == gl.FUNC_REVERSE_SUBTRACT ||
+ mode == gl.MIN ||
+ mode == gl.MAX;
+ };
+
+ /**
+ * @param {number} factor
+ * @return {boolean}
+ */
+ sglrReferenceContext.isValidBlendFactor = function(factor) {
+ switch (factor) {
+ case gl.ZERO:
+ case gl.ONE:
+ case gl.SRC_COLOR:
+ case gl.ONE_MINUS_SRC_COLOR:
+ case gl.DST_COLOR:
+ case gl.ONE_MINUS_DST_COLOR:
+ case gl.SRC_ALPHA:
+ case gl.ONE_MINUS_SRC_ALPHA:
+ case gl.DST_ALPHA:
+ case gl.ONE_MINUS_DST_ALPHA:
+ case gl.CONSTANT_COLOR:
+ case gl.ONE_MINUS_CONSTANT_COLOR:
+ case gl.CONSTANT_ALPHA:
+ case gl.ONE_MINUS_CONSTANT_ALPHA:
+ case gl.SRC_ALPHA_SATURATE:
+ return true;
+
+ default:
+ return false;
+ }
+ };
+
+ /**
+ * @param {number} mode
+ */
+ sglrReferenceContext.ReferenceContext.prototype.blendEquation = function(mode) {
+ if (this.conditionalSetError(!sglrReferenceContext.isValidBlendEquation(mode), gl.INVALID_ENUM))
+ return;
+ this.m_blendModeRGB = mode;
+ this.m_blendModeAlpha = mode;
+ };
+
+ /**
+ * @param {number} modeRGB
+ * @param {number} modeAlpha
+ */
+ sglrReferenceContext.ReferenceContext.prototype.blendEquationSeparate = function(modeRGB, modeAlpha) {
+ if (this.conditionalSetError(!sglrReferenceContext.isValidBlendEquation(modeRGB) ||
+ !sglrReferenceContext.isValidBlendEquation(modeAlpha),
+ gl.INVALID_ENUM))
+ return;
+
+ this.m_blendModeRGB = modeRGB;
+ this.m_blendModeAlpha = modeAlpha;
+ };
+
+ /**
+ * @param {number} src
+ * @param {number} dst
+ */
+ sglrReferenceContext.ReferenceContext.prototype.blendFunc = function(src, dst) {
+ if (this.conditionalSetError(!sglrReferenceContext.isValidBlendFactor(src) ||
+ !sglrReferenceContext.isValidBlendFactor(dst),
+ gl.INVALID_ENUM))
+ return;
+
+ this.m_blendFactorSrcRGB = src;
+ this.m_blendFactorSrcAlpha = src;
+ this.m_blendFactorDstRGB = dst;
+ this.m_blendFactorDstAlpha = dst;
+ };
+
+ /**
+ * @param {number} srcRGB
+ * @param {number} dstRGB
+ * @param {number} srcAlpha
+ * @param {number} dstAlpha
+ */
+ sglrReferenceContext.ReferenceContext.prototype.blendFuncSeparate = function(srcRGB, dstRGB, srcAlpha, dstAlpha) {
+ if (this.conditionalSetError(!sglrReferenceContext.isValidBlendFactor(srcRGB) ||
+ !sglrReferenceContext.isValidBlendFactor(dstRGB) ||
+ !sglrReferenceContext.isValidBlendFactor(srcAlpha) ||
+ !sglrReferenceContext.isValidBlendFactor(dstAlpha),
+ gl.INVALID_ENUM))
+ return;
+
+ this.m_blendFactorSrcRGB = srcRGB;
+ this.m_blendFactorSrcAlpha = srcAlpha;
+ this.m_blendFactorDstRGB = dstRGB;
+ this.m_blendFactorDstAlpha = dstAlpha;
+ };
+
+ /**
+ * @param {number} red
+ * @param {number} green
+ * @param {number} blue
+ * @param {number} alpha
+ */
+ sglrReferenceContext.ReferenceContext.prototype.blendColor = function(red, green, blue, alpha) {
+ this.m_blendColor = [deMath.clamp(red, 0, 1),
+ deMath.clamp(green, 0, 1),
+ deMath.clamp(blue, 0, 1),
+ deMath.clamp(alpha, 0, 1)];
+ };
+
+ /**
+ * @param {boolean} r
+ * @param {boolean} g
+ * @param {boolean} b
+ * @param {boolean} a
+ */
+ sglrReferenceContext.ReferenceContext.prototype.colorMask = function(r, g, b, a) {
+ this.m_colorMask = [r, g, b, a];
+ };
+
+ /**
+ * @param {boolean} mask
+ */
+ sglrReferenceContext.ReferenceContext.prototype.depthMask = function(mask) {
+ this.m_depthMask = mask;
+ };
+
+ /**
+ * @param {number} mask
+ */
+ sglrReferenceContext.ReferenceContext.prototype.stencilMask = function(mask) {
+ this.stencilMaskSeparate(gl.FRONT_AND_BACK, mask);
+ };
+
+ /**
+ * @param {number} face
+ * @param {number} mask
+ */
+ sglrReferenceContext.ReferenceContext.prototype.stencilMaskSeparate = function(face, mask) {
+ /** @type {boolean} */ var setFront = face == gl.FRONT || face == gl.FRONT_AND_BACK;
+ /** @type {boolean} */ var setBack = face == gl.BACK || face == gl.FRONT_AND_BACK;
+
+ if (this.conditionalSetError(!setFront && !setBack, gl.INVALID_ENUM))
+ return;
+
+ if (setFront) this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask = mask;
+ if (setBack) this.m_stencil[rrDefs.FaceType.FACETYPE_BACK].writeMask = mask;
+ };
+
+ /**
+ * @param {sglrReferenceContext.VertexArray} array
+ */
+ sglrReferenceContext.ReferenceContext.prototype.bindVertexArray = function(array) {
+ if (array)
+ this.m_vertexArrayBinding = array;
+ else
+ this.m_vertexArrayBinding = this.m_defaultVAO;
+ };
+
+ /**
+ * @return {sglrReferenceContext.VertexArray}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.createVertexArray = function() { return new sglrReferenceContext.VertexArray(this.m_limits.maxVertexAttribs); };
+
+ /**
+ * @param {number} array
+ */
+ sglrReferenceContext.ReferenceContext.prototype.deleteVertexArray = function(array) {};
+
+ /**
+ * @param {number} index
+ * @param {number} rawSize
+ * @param {number} type
+ * @param {boolean} normalized
+ * @param {number} stride
+ * @param {number} offset
+ */
+ sglrReferenceContext.ReferenceContext.prototype.vertexAttribPointer = function(index, rawSize, type, normalized, stride, offset) {
+ /** @type {boolean} */ var allowBGRA = false;
+ /** @type {number} */ var effectiveSize = rawSize;
+
+ if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(effectiveSize <= 0 || effectiveSize > 4, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(type != gl.BYTE && type != gl.UNSIGNED_BYTE &&
+ type != gl.SHORT && type != gl.UNSIGNED_SHORT &&
+ type != gl.INT && type != gl.UNSIGNED_INT &&
+ type != gl.FLOAT && type != gl.HALF_FLOAT &&
+ type != gl.INT_2_10_10_10_REV && type != gl.UNSIGNED_INT_2_10_10_10_REV, gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(normalized != true && normalized != false, gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(stride < 0, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError((type == gl.INT_2_10_10_10_REV || type == gl.UNSIGNED_INT_2_10_10_10_REV) && effectiveSize != 4, gl.INVALID_OPERATION))
+ return;
+ if (this.conditionalSetError(this.m_vertexArrayBinding != null && this.m_arrayBufferBinding == null && offset != 0, gl.INVALID_OPERATION))
+ return;
+
+ /** @type {?(sglrReferenceContext.VertexArray.VertexAttribArray)} */ var array_ = this.m_vertexArrayBinding.m_arrays[index]; // TODO: fix type
+
+ array_.size = rawSize;
+ array_.stride = stride;
+ array_.type = type;
+ array_.normalized = normalized;
+ array_.integer = false;
+ array_.offset = offset;
+
+ array_.bufferBinding = this.m_arrayBufferBinding;
+ };
+
+ /**
+ * @param {number} index
+ * @param {number} size
+ * @param {number} type
+ * @param {number} stride
+ * @param {number} offset
+ */
+ sglrReferenceContext.ReferenceContext.prototype.vertexAttribIPointer = function(index, size, type, stride, offset) {
+ if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(size <= 0 || size > 4, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(type != gl.BYTE && type != gl.UNSIGNED_BYTE &&
+ type != gl.SHORT && type != gl.UNSIGNED_SHORT &&
+ type != gl.INT && type != gl.UNSIGNED_INT, gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(stride < 0, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(this.m_vertexArrayBinding != null && this.m_arrayBufferBinding == null && offset != 0, gl.INVALID_OPERATION))
+ return;
+
+ /** @type {?(sglrReferenceContext.VertexArray.VertexAttribArray)} */ var array_ = this.m_vertexArrayBinding.m_arrays[index]; // TODO: fix type
+
+ array_.size = size;
+ array_.stride = stride;
+ array_.type = type;
+ array_.normalized = false;
+ array_.integer = true;
+ array_.offset = offset;
+
+ array_.bufferBinding = this.m_arrayBufferBinding;
+ };
+
+ /**
+ * @param {number} index
+ */
+ sglrReferenceContext.ReferenceContext.prototype.enableVertexAttribArray = function(index) {
+ if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
+ return;
+
+ this.m_vertexArrayBinding.m_arrays[index].enabled = true;
+ };
+
+ /**
+ * @param {number} index
+ */
+ sglrReferenceContext.ReferenceContext.prototype.disableVertexAttribArray = function(index) {
+ if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
+ return;
+
+ this.m_vertexArrayBinding.m_arrays[index].enabled = false;
+ };
+
+ /**
+ * @param {number} index
+ * @param {number} divisor
+ */
+ sglrReferenceContext.ReferenceContext.prototype.vertexAttribDivisor = function(index, divisor) {
+ if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
+ return;
+
+ this.m_vertexArrayBinding.m_arrays[index].divisor = divisor;
+ };
+
+ /**
+ * @param {number} index
+ * @param {number} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.vertexAttrib1f = function(index, x) {
+ if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
+ return;
+
+ this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, 0, 0, 1);
+ };
+
+ /**
+ * @param {number} index
+ * @param {number} x
+ * @param {number} y
+ */
+ sglrReferenceContext.ReferenceContext.prototype.vertexAttrib2f = function(index, x, y) {
+ if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
+ return;
+
+ this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, 0, 1);
+ };
+
+ /**
+ * @param {number} index
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ */
+ sglrReferenceContext.ReferenceContext.prototype.vertexAttrib3f = function(index, x, y, z) {
+ if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
+ return;
+
+ this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, z, 1);
+ };
+
+ /**
+ * @param {number} index
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @param {number} w
+ */
+ sglrReferenceContext.ReferenceContext.prototype.vertexAttrib4f = function(index, x, y, z, w) {
+ if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
+ return;
+
+ this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, z, w);
+ };
+
+ /**
+ * @param {number} index
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @param {number} w
+ */
+ sglrReferenceContext.ReferenceContext.prototype.vertexAttribI4i = function(index, x, y, z, w) {
+ if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
+ return;
+
+ this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, z, w);
+ };
+
+ /**
+ * @param {number} index
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @param {number} w
+ */
+ sglrReferenceContext.ReferenceContext.prototype.vertexAttribI4ui = function(index, x, y, z, w) {
+ if (this.conditionalSetError(index >= this.m_limits.maxVertexAttribs, gl.INVALID_VALUE))
+ return;
+
+ this.m_currentAttribs[index] = new rrGenericVector.GenericVec4(x, y, z, w);
+ };
+
+ /**
+ * @param {sglrShaderProgram.ShaderProgram} program
+ * @param {string} name
+ * @return {number}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getAttribLocation = function(program, name) {
+ if (this.conditionalSetError(!(program), gl.INVALID_OPERATION))
+ return -1;
+
+ for (var i = 0; i < program.m_attributeNames.length; i++)
+ if (program.m_attributeNames[i] === name)
+ return i;
+
+ return -1;
+ };
+
+ /**
+ * @param {number} pname
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getParameter = function(pname) {
+ switch (pname) {
+ case (gl.VIEWPORT): return new Int32Array(this.m_viewport);
+ case (gl.SCISSOR_BOX): return new Int32Array(this.m_scissorBox);
+ default:
+ throw new Error('Unimplemented');
+ }
+ };
+
+ /**
+ * @param {number} location
+ * @param {gluShaderUtil.DataType} type
+ * @param {Array<number>} value
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniformValue = function(location, type, value) {
+ if (this.conditionalSetError(!this.m_currentProgram, gl.INVALID_OPERATION))
+ return;
+
+ if (location === null)
+ return;
+
+ /** @type {sglrShaderProgram.Uniform} */ var uniform = this.m_currentProgram.m_uniforms[location];
+
+ if (this.conditionalSetError(!uniform, gl.INVALID_OPERATION))
+ return;
+
+ if (gluShaderUtil.isDataTypeSampler(uniform.type)) {
+ if (this.conditionalSetError(type != gluShaderUtil.DataType.INT, gl.INVALID_OPERATION))
+ return;
+ } else if (this.conditionalSetError(uniform.type != type, gl.INVALID_OPERATION))
+ return;
+ /* TODO: Do we need to copy objects? */
+ uniform.value = value;
+ };
+
+ /**
+ * @param {number} location
+ * @param {number} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform1f = function(location, x) {
+ return this.uniformValue(location, gluShaderUtil.DataType.FLOAT, [x]);
+ };
+
+ /**
+ * @param {number} location
+ * @param {Array<number>} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform1fv = function(location, x) {
+ return this.uniformValue(location, gluShaderUtil.DataType.FLOAT, x);
+ };
+
+ /**
+ * @param {number} location
+ * @param {number} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform1i = function(location, x) {
+ return this.uniformValue(location, gluShaderUtil.DataType.INT, [x]);
+ };
+
+ /**
+ * @param {number} location
+ * @param {Array<number>} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform1iv = function(location, x) {
+ return this.uniformValue(location, gluShaderUtil.DataType.INT, x);
+ };
+
+ /**
+ * @param {number} location
+ * @param {number} x
+ * @param {number} y
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform2f = function(location, x, y) {
+ return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC2, [x, y]);
+ };
+
+ /**
+ * @param {number} location
+ * @param {Array<number>} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform2fv = function(location, x) {
+ return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC2, x);
+ };
+
+ /**
+ * @param {number} location
+ * @param {number} x
+ * @param {number} y
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform2i = function(location, x, y) {
+ return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC2, [x, y]);
+ };
+
+ /**
+ * @param {number} location
+ * @param {Array<number>} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform2iv = function(location, x) {
+ return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC2, x);
+ };
+
+ /**
+ * @param {number} location
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform3f = function(location, x, y, z) {
+ return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC3, [x, y, z]);
+ };
+
+ /**
+ * @param {number} location
+ * @param {Array<number>} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform3fv = function(location, x) {
+ return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC3, x);
+ };
+
+ /**
+ * @param {number} location
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform3i = function(location, x, y, z) {
+ return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC3, [x, y, z]);
+ };
+
+ /**
+ * @param {number} location
+ * @param {Array<number>} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform3iv = function(location, x) {
+ return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC3, x);
+ };
+
+ /**
+ * @param {number} location
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @param {number} w
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform4f = function(location, x, y, z, w) {
+ return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC4, [x, y, z, w]);
+ };
+
+ /**
+ * @param {number} location
+ * @param {Array<number>} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform4fv = function(location, x) {
+ return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_VEC4, x);
+ };
+
+ /**
+ * @param {number} location
+ * @param {number} x
+ * @param {number} y
+ * @param {number} z
+ * @param {number} w
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform4i = function(location, x, y, z, w) {
+ return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC4, [x, y, z, w]);
+ };
+
+ /**
+ * @param {number} location
+ * @param {Array<number>} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniform4iv = function(location, x) {
+ return this.uniformValue(location, gluShaderUtil.DataType.INT_VEC4, x);
+ };
+
+ /**
+ * @return {Array<string>}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getSupportedExtensions = function() {
+ var extensions = gl.getSupportedExtensions(); //TODO: Let's just return gl's supported extensions for now
+ return extensions;
+ };
+
+ /**
+ * @param {string} name
+ * @return {*}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getExtension = function(name) {
+ return gl.getExtension(name); //TODO: Let's just return gl's supported extensions for now
+ };
+
+ /** transpose matrix 'x' of 'size' columns and rows
+ * @param {number} size
+ * @param {Array<number>} x
+ * @return {Array<number>}
+ */
+ sglrReferenceContext.trans = function(size, x) {
+ /** @type {Array<number>} */ var result = [];
+ for (var row = 0; row < size; ++row)
+ for (var col = 0; col < size; ++col)
+ result[row * size + col] = x[col * size + row];
+
+ return result;
+ };
+
+ /**
+ * @param {number} location
+ * @param {Array<number>} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniformMatrix2fv = function(location, transpose, x) {
+ /* change from column-major to internal row-major if transpose if FALSE */
+ return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_MAT2, !transpose ? sglrReferenceContext.trans(2, x) : x);
+ };
+
+ /**
+ * @param {number} location
+ * @param {Array<number>} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniformMatrix3fv = function(location, transpose, x) {
+ /* change from column-major to internal row-major if transpose if FALSE */
+ return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_MAT3, !transpose ? sglrReferenceContext.trans(3, x) : x);
+ };
+
+ /**
+ * @param {number} location
+ * @param {Array<number>} x
+ */
+ sglrReferenceContext.ReferenceContext.prototype.uniformMatrix4fv = function(location, transpose, x) {
+ /* change from column-major to internal row-major if transpose if FALSE */
+ return this.uniformValue(location, gluShaderUtil.DataType.FLOAT_MAT4, !transpose ? sglrReferenceContext.trans(4, x) : x);
+ };
+
+ /**
+ * @param {sglrShaderProgram.ShaderProgram} program
+ * @param {string} name
+ * @return {number}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getUniformLocation = function(program, name) {
+ if (this.conditionalSetError(!program, gl.INVALID_OPERATION))
+ return -1;
+
+ for (var i = 0; i < program.m_uniforms.length; i++)
+ if (program.m_uniforms[i].name === name)
+ return i;
+
+ return -1;
+ };
+
+ /**
+ * @param {number} w
+ */
+ sglrReferenceContext.ReferenceContext.prototype.lineWidth = function(w) {
+ if (this.conditionalSetError(w < 0, gl.INVALID_VALUE))
+ return;
+ this.m_lineWidth = w;
+ };
+
+ /**
+ * @param {number} target
+ * @return {boolean}
+ */
+ sglrReferenceContext.isValidBufferTarget = function(target) {
+ switch (target) {
+ case gl.ARRAY_BUFFER:
+ case gl.COPY_READ_BUFFER:
+ case gl.COPY_WRITE_BUFFER:
+ case gl.ELEMENT_ARRAY_BUFFER:
+ case gl.PIXEL_PACK_BUFFER:
+ case gl.PIXEL_UNPACK_BUFFER:
+ case gl.TRANSFORM_FEEDBACK_BUFFER:
+ case gl.UNIFORM_BUFFER:
+ return true;
+
+ default:
+ return false;
+ }
+ };
+
+ /**
+ * @param {number} target
+ * @param {sglrReferenceContext.DataBuffer} buffer
+ * @throws {Error}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.setBufferBinding = function(target, buffer) {
+ switch (target) {
+ case gl.ARRAY_BUFFER: this.m_arrayBufferBinding = buffer; break;
+ case gl.COPY_READ_BUFFER: this.m_copyReadBufferBinding = buffer; break;
+ case gl.COPY_WRITE_BUFFER: this.m_copyWriteBufferBinding = buffer; break;
+ case gl.ELEMENT_ARRAY_BUFFER: this.m_vertexArrayBinding.m_elementArrayBufferBinding = buffer; break;
+ case gl.PIXEL_PACK_BUFFER: this.m_pixelPackBufferBinding = buffer; break;
+ case gl.PIXEL_UNPACK_BUFFER: this.m_pixelUnpackBufferBinding = buffer; break;
+ case gl.TRANSFORM_FEEDBACK_BUFFER: this.m_transformFeedbackBufferBinding = buffer; break;
+ case gl.UNIFORM_BUFFER: this.m_uniformBufferBinding = buffer; break;
+ default:
+ throw new Error('Unrecognized target: ' + target);
+ }
+ };
+
+ /**
+ * @param {number} target
+ * @return {sglrReferenceContext.DataBuffer}
+ * @throws {Error}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getBufferBinding = function(target) {
+ switch (target) {
+ case gl.ARRAY_BUFFER: return this.m_arrayBufferBinding;
+ case gl.COPY_READ_BUFFER: return this.m_copyReadBufferBinding;
+ case gl.COPY_WRITE_BUFFER: return this.m_copyWriteBufferBinding;
+ case gl.ELEMENT_ARRAY_BUFFER: return this.m_vertexArrayBinding.m_elementArrayBufferBinding;
+ case gl.PIXEL_PACK_BUFFER: return this.m_pixelPackBufferBinding;
+ case gl.PIXEL_UNPACK_BUFFER: return this.m_pixelUnpackBufferBinding;
+ case gl.TRANSFORM_FEEDBACK_BUFFER: return this.m_transformFeedbackBufferBinding;
+ case gl.UNIFORM_BUFFER: return this.m_uniformBufferBinding;
+ default:
+ throw new Error('Unrecognized target: ' + target);
+ }
+ };
+
+ /**
+ * @param {number} target
+ * @param {sglrReferenceContext.DataBuffer} buffer
+ */
+ sglrReferenceContext.ReferenceContext.prototype.bindBuffer = function(target, buffer) {
+ if (this.conditionalSetError(!sglrReferenceContext.isValidBufferTarget(target), gl.INVALID_ENUM))
+ return;
+
+ this.setBufferBinding(target, buffer);
+ };
+
+ /**
+ * @return {sglrReferenceContext.DataBuffer}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.createBuffer = function() { return new sglrReferenceContext.DataBuffer(); };
+
+ /**
+ * @param {number} buffer
+ */
+ sglrReferenceContext.ReferenceContext.prototype.deleteBuffer = function(buffer) {};
+
+ /**
+ * @param {number} target
+ * @param {number|goog.NumberArray} input
+ * @param {number} usage
+ */
+ sglrReferenceContext.ReferenceContext.prototype.bufferData = function(target, input, usage) {
+ if (this.conditionalSetError(!sglrReferenceContext.isValidBufferTarget(target), gl.INVALID_ENUM))
+ return;
+ /** @type {sglrReferenceContext.DataBuffer} */ var buffer = this.getBufferBinding(target);
+ if (this.conditionalSetError(!buffer, gl.INVALID_OPERATION))
+ return;
+
+ if (typeof input == 'number') {
+ if (this.conditionalSetError(input < 0, gl.INVALID_VALUE))
+ return;
+ buffer.setStorage(input);
+ } else {
+ buffer.setData(input);
+ }
+ };
+
+ /**
+ * @param {number} target
+ * @param {number} offset
+ * @param {goog.NumberArray} data
+ */
+ sglrReferenceContext.ReferenceContext.prototype.bufferSubData = function(target, offset, data) {
+ if (this.conditionalSetError(!sglrReferenceContext.isValidBufferTarget(target), gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(offset < 0, gl.INVALID_VALUE))
+ return;
+ /** @type {sglrReferenceContext.DataBuffer} */ var buffer = this.getBufferBinding(target);
+ if (this.conditionalSetError(!buffer, gl.INVALID_OPERATION))
+ return;
+
+ if (this.conditionalSetError(offset + data.byteLength > buffer.getSize(), gl.INVALID_VALUE))
+ return;
+ buffer.setSubData(offset, data);
+ };
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width
+ * @param {number} height
+ * @param {number} format
+ * @param {number} type
+ * @param {goog.NumberArray} pixels
+ */
+ sglrReferenceContext.ReferenceContext.prototype.readPixels = function(x, y, width, height, format, type, pixels) {
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var src = this.getReadColorbuffer();
+
+ // Map transfer format.
+ /** @type {tcuTexture.TextureFormat} */ var transferFmt = gluTextureUtil.mapGLTransferFormat(format, type);
+
+ // Clamp input values
+ /** @type {number} */ var copyX = deMath.clamp(x, 0, src.raw().getHeight());
+ /** @type {number} */ var copyY = deMath.clamp(y, 0, src.raw().getDepth());
+ /** @type {number} */ var copyWidth = deMath.clamp(width, 0, src.raw().getHeight() - x);
+ /** @type {number} */ var copyHeight = deMath.clamp(height, 0, src.raw().getDepth() - y);
+
+ /** @type {?ArrayBuffer} */ var data;
+ /** @type {number} */ var offset;
+ if (this.m_pixelPackBufferBinding) {
+ if (this.conditionalSetError(typeof pixels !== 'number', gl.INVALID_VALUE))
+ return;
+ data = this.m_pixelPackBufferBinding.getData();
+ offset = pixels.byteOffset;
+ } else {
+ if (pixels instanceof ArrayBuffer) {
+ data = pixels;
+ offset = 0;
+ } else {
+ data = pixels.buffer;
+ offset = pixels.byteOffset;
+ }
+ }
+
+ /** @type {tcuTexture.PixelBufferAccess} */
+ var dst = new tcuTexture.PixelBufferAccess({
+ format: transferFmt,
+ width: width,
+ height: height,
+ depth: 1,
+ rowPitch: deMath.deAlign32(width * transferFmt.getPixelSize(), this.m_pixelPackAlignment),
+ slicePitch: 0,
+ data: data,
+ offset: offset});
+
+ src = src.getSubregion([copyX, copyY, copyWidth, copyHeight]);
+ src.resolveMultisampleColorBuffer(tcuTextureUtil.getSubregion(dst, 0, 0, 0, copyWidth, copyHeight, 1));
+ };
+
+ /**
+ * @return {number}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getType = function() {
+ return this.m_type;
+ };
+
+ /**
+ * @return {tcuTexture.PixelBufferAccess}
+ */
+ sglrReferenceContext.nullAccess = function() {
+ return new tcuTexture.PixelBufferAccess({
+ width: 0,
+ height: 0});
+ };
+
+ /**
+ * @param {sglrReferenceContext.Framebuffer} framebuffer
+ * @param {sglrReferenceContext.AttachmentPoint} point
+ * @return {tcuTexture.PixelBufferAccess}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getFboAttachment = function(framebuffer, point) {
+ /** @type {sglrReferenceContext.Attachment} */ var attachment = framebuffer.getAttachment(point);
+
+ switch (attachment.type) {
+ case sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_TEXTURE: {
+ var container = /** @type {sglrReferenceContext.TextureContainer} */ (attachment.object);
+ /** @type {?sglrReferenceContext.TextureType} */ var type = container.getType();
+ var texture = container.texture;
+
+ if (type == sglrReferenceContext.TextureType.TYPE_2D)
+ return texture.getLevel(attachment.level);
+ else if (type == sglrReferenceContext.TextureType.TYPE_CUBE_MAP)
+ return texture.getFace(attachment.level, sglrReferenceContext.texTargetToFace(attachment.texTarget));
+ else if (type == sglrReferenceContext.TextureType.TYPE_2D_ARRAY ||
+ type == sglrReferenceContext.TextureType.TYPE_3D ||
+ type == sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY) {
+ /** @type {tcuTexture.PixelBufferAccess} */ var level = texture.getLevel(attachment.level);
+
+ return new tcuTexture.PixelBufferAccess({
+ format: level.getFormat(),
+ width: level.getWidth(),
+ height: level.getHeight(),
+ depth: 1,
+ rowPitch: level.getRowPitch(),
+ slicePitch: 0,
+ data: level.getBuffer(),
+ offset: level.getSlicePitch() * attachment.layer});
+ } else
+ return sglrReferenceContext.nullAccess();
+ }
+
+ case sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_RENDERBUFFER: {
+ var rbo = /** @type {sglrReferenceContext.Renderbuffer} */ (attachment.object);
+ return rbo.getAccess();
+ }
+
+ default:
+ return sglrReferenceContext.nullAccess();
+ }
+ };
+
+ /**
+ * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getReadColorbuffer = function() {
+ if (this.m_readFramebufferBinding)
+ return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_readFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_COLOR0));
+ else
+ return this.m_defaultColorbuffer;
+ };
+
+ // sglrReferenceContext.ReferenceContext.prototype.drawArrays = function(mode, first, count) {
+ // this.drawArraysInstanced(mode, first, count, 1);
+ // };
+
+ /**
+ * @param {number} target
+ * @return {number}
+ * @throws {Error}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.checkFramebufferStatus = function(target) {
+ if (this.conditionalSetError(target != gl.FRAMEBUFFER &&
+ target != gl.DRAW_FRAMEBUFFER &&
+ target != gl.READ_FRAMEBUFFER, gl.INVALID_ENUM))
+ return 0;
+
+ // Select binding point.
+ /** @type {sglrReferenceContext.Framebuffer} */ var framebufferBinding = (target == gl.FRAMEBUFFER || target == gl.DRAW_FRAMEBUFFER) ? this.m_drawFramebufferBinding : this.m_readFramebufferBinding;
+
+ // Default framebuffer is always complete.
+ if (!framebufferBinding)
+ return gl.FRAMEBUFFER_COMPLETE;
+
+ /** @type {number} */ var width = -1;
+ /** @type {number} */ var height = -1;
+ /** @type {boolean} */ var hasAttachment = false;
+ /** @type {boolean} */ var attachmentComplete = true;
+ /** @type {boolean} */ var dimensionsOk = true;
+
+ for (var key in sglrReferenceContext.AttachmentPoint) {
+ /** @type {sglrReferenceContext.AttachmentPoint} */ var point = sglrReferenceContext.AttachmentPoint[key];
+ /** @type {sglrReferenceContext.Attachment} */ var attachment = framebufferBinding.getAttachment(point);
+ /** @type {number} */ var attachmentWidth = 0;
+ /** @type {number} */ var attachmentHeight = 0;
+ /** @type {tcuTexture.TextureFormat} */ var attachmentFormat;
+
+ if (attachment.type == sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_TEXTURE) {
+ var container = /** @type {sglrReferenceContext.TextureContainer} */ (attachment.object);
+ /** @type {tcuTexture.ConstPixelBufferAccess} */ var level;
+
+ if (attachment.texTarget == sglrReferenceContext.TexTarget.TEXTARGET_2D) {
+ DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_2D);
+ /** @type {sglrReferenceContext.Texture2D} */ var tex2D = /** @type {sglrReferenceContext.Texture2D} */ (container.texture);
+
+ if (tex2D.hasLevel(attachment.level))
+ level = tex2D.getLevel(attachment.level);
+ // TODO: implement CUBE_MAP, 2D_ARRAY, 3D, CUBE_MAP_ARRAY
+ } else if (deMath.deInRange32(attachment.texTarget, sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_X,
+ sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Z)) {
+ DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_CUBE_MAP);
+
+ var texCube = /** @type {sglrReferenceContext.TextureCube} */ (container.texture);
+ var face = sglrReferenceContext.texTargetToFace(attachment.texTarget);
+
+ if (texCube.hasFace(attachment.level, face))
+ level = texCube.getFace(attachment.level, face);
+ } else if (attachment.texTarget == sglrReferenceContext.TexTarget.TEXTARGET_2D_ARRAY) {
+ DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_2D_ARRAY);
+ var tex2DArr = /** @type {sglrReferenceContext.Texture2DArray} */ (container.texture);
+
+ if (tex2DArr.hasLevel(attachment.level))
+ level = tex2DArr.getLevel(attachment.level); // \note Slice doesn't matter here.
+ } else if (attachment.texTarget == sglrReferenceContext.TexTarget.TEXTARGET_3D) {
+ DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_3D);
+ var tex3D = /** @type {sglrReferenceContext.Texture3D} */ (container.texture);
+
+ if (tex3D.hasLevel(attachment.level))
+ level = tex3D.getLevel(attachment.level); // \note Slice doesn't matter here.
+ // } else if (attachment.texTarget == sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_ARRAY) {
+ // DE_ASSERT(container.textureType == sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY);
+ // var texCubeArr = container.texture;
+ //
+ // if (texCubeArr.hasLevel(attachment.level))
+ // level = texCubeArr.getLevel(attachment.level); // \note Slice doesn't matter here.
+ } else
+ throw new Error('sglrReferenceContext.Framebuffer attached to a texture but no valid target specified.');
+
+ attachmentWidth = level.getWidth();
+ attachmentHeight = level.getHeight();
+ attachmentFormat = level.getFormat();
+ } else if (attachment.type == sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_RENDERBUFFER) {
+ var renderbuffer = attachment.object;
+
+ attachmentWidth = renderbuffer.getWidth();
+ attachmentHeight = renderbuffer.getHeight();
+ attachmentFormat = renderbuffer.getFormat();
+ } else
+ continue; // Skip rest of checks.
+
+ if (!hasAttachment && attachmentWidth > 0 && attachmentHeight > 0) {
+ width = attachmentWidth;
+ height = attachmentHeight;
+ hasAttachment = true;
+ } else if (attachmentWidth != width || attachmentHeight != height)
+ dimensionsOk = false;
+
+ // Validate attachment point compatibility.
+ switch (attachmentFormat.order) {
+ case tcuTexture.ChannelOrder.R:
+ case tcuTexture.ChannelOrder.RG:
+ case tcuTexture.ChannelOrder.RGB:
+ case tcuTexture.ChannelOrder.RGBA:
+ case tcuTexture.ChannelOrder.sRGB:
+ case tcuTexture.ChannelOrder.sRGBA:
+ if (point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_COLOR0)
+ attachmentComplete = false;
+ break;
+
+ case tcuTexture.ChannelOrder.D:
+ if (point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH)
+ attachmentComplete = false;
+ break;
+
+ case tcuTexture.ChannelOrder.S:
+ if (point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL)
+ attachmentComplete = false;
+ break;
+
+ case tcuTexture.ChannelOrder.DS:
+ if (point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH &&
+ point != sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL)
+ attachmentComplete = false;
+ break;
+
+ default:
+ throw new Error('Unsupported attachment channel order:' + attachmentFormat.order);
+ }
+ }
+
+ if (!attachmentComplete)
+ return gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT;
+ else if (!hasAttachment)
+ return gl.FRAMEBUFFER_INCOMPLETE_MISSING_ATTACHMENT;
+ else if (!dimensionsOk)
+ return gl.FRAMEBUFFER_INCOMPLETE_DIMENSIONS;
+ else
+ return gl.FRAMEBUFFER_COMPLETE;
+ };
+
+ /**
+ * @param {number} mode
+ * @return {boolean}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.predrawErrorChecks = function(mode) {
+ if (this.conditionalSetError(mode != gl.POINTS &&
+ mode != gl.LINE_STRIP && mode != gl.LINE_LOOP && mode != gl.LINES &&
+ mode != gl.TRIANGLE_STRIP && mode != gl.TRIANGLE_FAN && mode != gl.TRIANGLES,
+ gl.INVALID_ENUM))
+ return false;
+
+ // \todo [jarkko] Uncomment following code when the buffer mapping support is added
+ //for (size_t ndx = 0; ndx < vao.m_arrays.length; ++ndx)
+ // if (vao.m_arrays[ndx].enabled && vao.m_arrays[ndx].bufferBinding && vao.m_arrays[ndx].bufferBinding->isMapped)
+ // RC_ERROR_RET(gl.INVALID_OPERATION, RC_RET_VOID);
+
+ if (this.conditionalSetError(this.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE, gl.INVALID_FRAMEBUFFER_OPERATION))
+ return false;
+
+ return true;
+ };
+
+ /**
+ * Draws quads from vertex arrays
+ * @param {number} mode GL primitive type to draw with.
+ * @param {number} first First vertex to begin drawing with
+ * @param {number} count How many vertices to draw (not counting vertices before first)
+ * @param {number} instanceCount
+ */
+ sglrReferenceContext.ReferenceContext.prototype.drawArraysInstanced = function(mode, first, count, instanceCount) {
+ if (this.conditionalSetError(first < 0 || count < 0 || instanceCount < 0, gl.INVALID_VALUE))
+ return;
+
+ if (!this.predrawErrorChecks(mode))
+ return;
+
+ // All is ok
+ this.drawQuads(mode, first, count, instanceCount);
+ };
+
+ /**
+ * @param {number} mode GL primitive type to draw with.
+ * @param {number} start
+ * @param {number} end
+ * @param {number} count How many vertices to draw (not counting vertices before first)
+ * @param {number} type Data type
+ * @param {number} offset
+ */
+ sglrReferenceContext.ReferenceContext.prototype.drawRangeElements = function(mode, start, end, count, type, offset) {
+ if (this.conditionalSetError(end < start, gl.INVALID_VALUE))
+ return;
+
+ this.drawElements(mode, count, type, offset);
+ };
+
+ /**
+ * @param {number} mode GL primitive type to draw with.
+ * @param {number} count How many vertices to draw (not counting vertices before first)
+ * @param {number} type Data type
+ * @param {number} offset
+ */
+ sglrReferenceContext.ReferenceContext.prototype.drawElements = function(mode, count, type, offset) {
+ this.drawElementsInstanced(mode, count, type, offset, 1);
+ };
+
+ /**
+ * @param {number} mode GL primitive type to draw with.
+ * @param {number} count How many vertices to draw (not counting vertices before first)
+ * @param {number} type Data type
+ * @param {number} offset
+ * @param {number} instanceCount
+ */
+ sglrReferenceContext.ReferenceContext.prototype.drawElementsInstanced = function(mode, count, type, offset, instanceCount) {
+ this.drawElementsInstancedBaseVertex(mode, count, type, offset, instanceCount, 0);
+ };
+
+ /**
+ * @param {number} mode GL primitive type to draw with.
+ * @param {number} count How many vertices to draw (not counting vertices before first)
+ * @param {number} type Data type
+ * @param {number} offset
+ * @param {number} instanceCount
+ * @param {number} baseVertex
+ */
+ sglrReferenceContext.ReferenceContext.prototype.drawElementsInstancedBaseVertex = function(mode, count, type, offset, instanceCount, baseVertex) {
+ var vao = this.m_vertexArrayBinding;
+
+ if (this.conditionalSetError(type != gl.UNSIGNED_BYTE &&
+ type != gl.UNSIGNED_SHORT &&
+ type != gl.UNSIGNED_INT, gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(count < 0 || instanceCount < 0, gl.INVALID_VALUE))
+ return;
+
+ if (!this.predrawErrorChecks(mode))
+ return;
+
+ if (this.conditionalSetError(count > 0 && !vao.m_elementArrayBufferBinding, gl.INVALID_OPERATION))
+ return;
+ // All is ok
+ var data = vao.m_elementArrayBufferBinding.getData();
+ var indices = new rrRenderer.DrawIndices(data, sglrReferenceUtils.mapGLIndexType(type), offset, baseVertex);
+
+ this.drawQuads(mode, indices, count, instanceCount);
+ };
+
+ /**
+ * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} access
+ * @return {Array<number>}
+ */
+ sglrReferenceContext.getBufferRect = function(access) { return [0, 0, access.raw().getHeight(), access.raw().getDepth()]; };
+
+ /**
+ * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getDrawColorbuffer = function() {
+ if (this.m_drawFramebufferBinding)
+ return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_drawFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_COLOR0));
+ return this.m_defaultColorbuffer;
+ };
+
+ /**
+ * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getDrawDepthbuffer = function() {
+ if (this.m_drawFramebufferBinding)
+ return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_drawFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH));
+ return this.m_defaultDepthbuffer;
+ };
+
+ /**
+ * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getDrawStencilbuffer = function() {
+ if (this.m_drawFramebufferBinding)
+ return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_drawFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL));
+ return this.m_defaultStencilbuffer;
+ };
+
+ /**
+ * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getReadDepthbuffer = function() {
+ if (this.m_readFramebufferBinding)
+ return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_readFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_DEPTH));
+ return this.m_defaultDepthbuffer;
+ };
+
+ /**
+ * @return {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.getReadStencilbuffer = function() {
+ if (this.m_readFramebufferBinding)
+ return rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess.fromSinglesampleAccess(this.getFboAttachment(this.m_readFramebufferBinding, sglrReferenceContext.AttachmentPoint.ATTACHMENTPOINT_STENCIL));
+ return this.m_defaultStencilbuffer;
+ };
+
+ /**
+ * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} access
+ * @param {number} s
+ * @param {number} x
+ * @param {number} y
+ * @param {number} depth
+ */
+ sglrReferenceContext.writeDepthOnly = function(access, s, x, y, depth) { access.raw().setPixDepth(depth, s, x, y); };
+
+ /**
+ * @param {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} access
+ * @param {number} s
+ * @param {number} x
+ * @param {number} y
+ * @param {number} stencil
+ * @param {number} writeMask
+ */
+ sglrReferenceContext.writeStencilOnly = function(access, s, x, y, stencil, writeMask) {
+ /** @type {number} */ var oldVal = access.raw().getPixelInt(s, x, y)[3];
+ access.raw().setPixStencil((oldVal & ~writeMask) | (stencil & writeMask), s, x, y);
+ };
+
+ /**
+ * @param {number} bits
+ * @param {number} s
+ * @return {number}
+ */
+ sglrReferenceContext.maskStencil = function(bits, s) { return s & ((1 << bits) - 1); };
+
+ /**
+ * @param {number} buffers
+ */
+ sglrReferenceContext.ReferenceContext.prototype.clear = function(buffers) {
+ if (this.conditionalSetError((buffers & ~(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)) != 0, gl.INVALID_VALUE))
+ return;
+
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf0 = this.getDrawColorbuffer();
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var depthBuf = this.getDrawDepthbuffer();
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var stencilBuf = this.getDrawStencilbuffer();
+ /** @type {boolean} */ var hasColor0 = /** @type {!boolean} */ (colorBuf0 && !colorBuf0.isEmpty());
+ /** @type {boolean} */ var hasDepth = /** @type {!boolean} */ (depthBuf && !depthBuf.isEmpty());
+ /** @type {boolean} */ var hasStencil = /** @type {!boolean} */ (stencilBuf && !stencilBuf.isEmpty());
+ /** @type {Array<number>} */ var baseArea = this.m_scissorEnabled ? this.m_scissorBox : [0, 0, 0x7fffffff, 0x7fffffff];
+
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var access;
+ /** @type {boolean} */ var isSharedDepthStencil;
+
+ if (hasColor0 && (buffers & gl.COLOR_BUFFER_BIT) != 0) {
+ /** @type {Array<number>} */ var colorArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(colorBuf0));
+ access = colorBuf0.getSubregion(colorArea);
+ /** @type {boolean} */ var isSRGB = colorBuf0.raw().getFormat().isSRGB();
+ /** @type {Array<number>} */ var c = (isSRGB && this.m_sRGBUpdateEnabled) ? tcuTextureUtil.linearToSRGB(this.m_clearColor) : this.m_clearColor;
+ /** @type {boolean} */ var maskUsed = !this.m_colorMask[0] || !this.m_colorMask[1] || !this.m_colorMask[2] || !this.m_colorMask[3];
+ /** @type {boolean} */ var maskZero = !this.m_colorMask[0] && !this.m_colorMask[1] && !this.m_colorMask[2] && !this.m_colorMask[3];
+
+ if (!maskUsed)
+ access.clear(c);
+ else if (!maskZero) {
+ for (var y = 0; y < access.raw().getDepth(); y++)
+ for (var x = 0; x < access.raw().getHeight(); x++)
+ for (var s = 0; s < access.getNumSamples(); s++)
+ access.raw().setPixel(tcuTextureUtil.select(c, access.raw().getPixel(s, x, y), this.m_colorMask), s, x, y);
+ }
+ // else all channels masked out
+ }
+
+ if (hasDepth && (buffers & gl.DEPTH_BUFFER_BIT) != 0 && this.m_depthMask) {
+ /** @type {Array<number>} */ var depthArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(depthBuf));
+ access = depthBuf.getSubregion(depthArea);
+ isSharedDepthStencil = depthBuf.raw().getFormat().order != tcuTexture.ChannelOrder.D;
+
+ if (isSharedDepthStencil) {
+ // Slow path where stencil is masked out in write.
+ for (var y = 0; y < access.raw().getDepth(); y++)
+ for (var x = 0; x < access.raw().getHeight(); x++)
+ for (var s = 0; s < access.getNumSamples(); s++)
+ sglrReferenceContext.writeDepthOnly(access, s, x, y, this.m_clearDepth);
+ } else
+ access.clear([this.m_clearDepth, 0, 0, 0]);
+ }
+
+ if (hasStencil && (buffers & gl.STENCIL_BUFFER_BIT) != 0) {
+ /** @type {Array<number>} */ var stencilArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(stencilBuf));
+ access = stencilBuf.getSubregion(stencilArea);
+ /** @type {number} */ var stencilBits = stencilBuf.raw().getFormat().getNumStencilBits();
+ /** @type {number} */ var stencil = sglrReferenceContext.maskStencil(stencilBits, this.m_clearStencil);
+ isSharedDepthStencil = stencilBuf.raw().getFormat().order != tcuTexture.ChannelOrder.S;
+
+ if (isSharedDepthStencil || ((this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask & ((1 << stencilBits) - 1)) != ((1 << stencilBits) - 1))) {
+ // Slow path where depth or stencil is masked out in write.
+ for (var y = 0; y < access.raw().getDepth(); y++)
+ for (var x = 0; x < access.raw().getHeight(); x++)
+ for (var s = 0; s < access.getNumSamples(); s++)
+ sglrReferenceContext.writeStencilOnly(access, s, x, y, stencil, this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask);
+ } else
+ access.clear([0, 0, 0, stencil]);
+ }
+ };
+
+ /**
+ * @param {number} buffer
+ * @param {number} drawbuffer
+ * @param {Array<number>} value
+ * @throws {Error}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.clearBufferiv = function(buffer, drawbuffer, value) {
+ if (this.conditionalSetError(buffer != gl.COLOR && buffer != gl.STENCIL, gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(drawbuffer != 0, gl.INVALID_VALUE))
+ return;
+
+ /** @type {Array<number>} */ var baseArea = this.m_scissorEnabled ? this.m_scissorBox : [0, 0, 0x7fffffff, 0x7fffffff];
+
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var access;
+
+ if (buffer == gl.COLOR) {
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf = this.getDrawColorbuffer();
+ /** @type {boolean} */ var maskUsed = !this.m_colorMask[0] || !this.m_colorMask[1] || !this.m_colorMask[2] || !this.m_colorMask[3];
+ /** @type {boolean} */ var maskZero = !this.m_colorMask[0] && !this.m_colorMask[1] && !this.m_colorMask[2] && !this.m_colorMask[3];
+
+ if (!colorBuf.isEmpty() && !maskZero) {
+ /** @type {Array<number>} */ var colorArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(colorBuf));
+ access = colorBuf.getSubregion(colorArea);
+
+ if (!maskUsed)
+ access.clear(value);
+ else {
+ for (var y = 0; y < access.raw().getDepth(); y++)
+ for (var x = 0; x < access.raw().getHeight(); x++)
+ for (var s = 0; s < access.getNumSamples(); s++)
+ access.raw().setPixel(tcuTextureUtil.select(value, access.raw().getPixel(s, x, y), this.m_colorMask), s, x, y);
+ }
+ }
+ } else {
+ if (buffer !== gl.STENCIL)
+ throw new Error('Unexpected buffer type: ' + buffer);
+
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var stencilBuf = this.getDrawStencilbuffer();
+
+ if (!stencilBuf.isEmpty() && this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask != 0) {
+ /** @type {Array<number>} */ var area = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(stencilBuf));
+ access = stencilBuf.getSubregion(area);
+ /** @type {number} */ var stencil = value[0];
+
+ for (var y = 0; y < access.raw().getDepth(); y++)
+ for (var x = 0; x < access.raw().getHeight(); x++)
+ for (var s = 0; s < access.getNumSamples(); s++)
+ sglrReferenceContext.writeStencilOnly(access, s, x, y, stencil, this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask);
+ }
+ }
+ };
+
+ /**
+ * @param {number} buffer
+ * @param {number} drawbuffer
+ * @param {Array<number>} value
+ * @throws {Error}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.clearBufferfv = function(buffer, drawbuffer, value) {
+ if (this.conditionalSetError(buffer != gl.COLOR && buffer != gl.DEPTH, gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(drawbuffer != 0, gl.INVALID_VALUE))
+ return;
+
+ /** @type {Array<number>} */ var baseArea = this.m_scissorEnabled ? this.m_scissorBox : [0, 0, 0x7fffffff, 0x7fffffff];
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var access;
+ if (buffer == gl.COLOR) {
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf = this.getDrawColorbuffer();
+ /** @type {boolean} */ var maskUsed = !this.m_colorMask[0] || !this.m_colorMask[1] || !this.m_colorMask[2] || !this.m_colorMask[3];
+ /** @type {boolean} */ var maskZero = !this.m_colorMask[0] && !this.m_colorMask[1] && !this.m_colorMask[2] && !this.m_colorMask[3];
+
+ if (!colorBuf.isEmpty() && !maskZero) {
+ /** @type {Array<number>} */ var colorArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(colorBuf));
+ access = colorBuf.getSubregion(colorArea);
+ var color = value;
+
+ if (this.m_sRGBUpdateEnabled && access.raw().getFormat().isSRGB())
+ color = tcuTextureUtil.linearToSRGB(color);
+
+ if (!maskUsed)
+ access.clear(color);
+ else {
+ for (var y = 0; y < access.raw().getDepth(); y++)
+ for (var x = 0; x < access.raw().getHeight(); x++)
+ for (var s = 0; s < access.getNumSamples(); s++)
+ access.raw().setPixel(tcuTextureUtil.select(color, access.raw().getPixel(s, x, y), this.m_colorMask), s, x, y);
+ }
+ }
+ } else {
+ if (buffer !== gl.DEPTH)
+ throw new Error('Unexpected buffer type: ' + buffer);
+
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var depthBuf = this.getDrawDepthbuffer();
+
+ if (!depthBuf.isEmpty() && this.m_depthMask) {
+ /** @type {Array<number>} */ var area = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(depthBuf));
+ access = depthBuf.getSubregion(area);
+ /** @type {number} */ var depth = value[0];
+
+ for (var y = 0; y < access.raw().getDepth(); y++)
+ for (var x = 0; x < access.raw().getHeight(); x++)
+ for (var s = 0; s < access.getNumSamples(); s++)
+ sglrReferenceContext.writeDepthOnly(access, s, x, y, depth);
+ }
+ }
+ };
+
+ /**
+ * @param {number} buffer
+ * @param {number} drawbuffer
+ * @param {Array<number>} value
+ */
+ sglrReferenceContext.ReferenceContext.prototype.clearBufferuiv = function(buffer, drawbuffer, value) {
+ if (this.conditionalSetError(buffer != gl.COLOR, gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(drawbuffer != 0, gl.INVALID_VALUE))
+ return;
+
+ /** @type {Array<number>} */ var baseArea = this.m_scissorEnabled ? this.m_scissorBox : [0, 0, 0x7fffffff, 0x7fffffff];
+
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf = this.getDrawColorbuffer();
+ /** @type {boolean} */ var maskUsed = !this.m_colorMask[0] || !this.m_colorMask[1] || !this.m_colorMask[2] || !this.m_colorMask[3];
+ /** @type {boolean} */ var maskZero = !this.m_colorMask[0] && !this.m_colorMask[1] && !this.m_colorMask[2] && !this.m_colorMask[3];
+
+ if (!colorBuf.isEmpty() && !maskZero) {
+ /** @type {Array<number>} */ var colorArea = deMath.intersect(baseArea, sglrReferenceContext.getBufferRect(colorBuf));
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var access = colorBuf.getSubregion(colorArea);
+
+ if (!maskUsed)
+ access.clear(value);
+ else {
+ for (var y = 0; y < access.raw().getDepth(); y++)
+ for (var x = 0; x < access.raw().getHeight(); x++)
+ for (var s = 0; s < access.getNumSamples(); s++)
+ access.raw().setPixel(tcuTextureUtil.select(value, access.raw().getPixel(s, x, y), this.m_colorMask), s, x, y);
+ }
+ }
+ };
+
+ /**
+ * @param {number} buffer
+ * @param {number} drawbuffer
+ * @param {number} depth
+ * @param {number} stencil
+ */
+ sglrReferenceContext.ReferenceContext.prototype.clearBufferfi = function(buffer, drawbuffer, depth, stencil) {
+ if (this.conditionalSetError(buffer != gl.DEPTH_STENCIL, gl.INVALID_ENUM))
+ return;
+ this.clearBufferfv(gl.DEPTH, drawbuffer, [depth]);
+ this.clearBufferiv(gl.STENCIL, drawbuffer, [stencil]);
+ };
+
+ /**
+ * @param {number} target
+ * @param {number} attachment
+ * @param {sglrReferenceContext.TexTarget} textarget
+ * @param {sglrReferenceContext.TextureContainer} texture
+ * @param {number} level
+ * @throws {Error}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.framebufferTexture2D = function(target, attachment, textarget, texture, level) {
+ if (attachment == gl.DEPTH_STENCIL_ATTACHMENT) {
+ // Attach to both depth and stencil.
+ this.framebufferTexture2D(target, gl.DEPTH_ATTACHMENT, textarget, texture, level);
+ this.framebufferTexture2D(target, gl.STENCIL_ATTACHMENT, textarget, texture, level);
+ } else {
+ /** @type {sglrReferenceContext.AttachmentPoint} */ var point = sglrReferenceContext.mapGLAttachmentPoint(attachment);
+ /** @type {sglrReferenceContext.TexTarget} */ var fboTexTarget = sglrReferenceContext.mapGLFboTexTarget(textarget);
+
+ if (this.conditionalSetError(target != gl.FRAMEBUFFER &&
+ target != gl.DRAW_FRAMEBUFFER &&
+ target != gl.READ_FRAMEBUFFER, gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(point == undefined, gl.INVALID_ENUM))
+ return;
+
+ // Select binding point.
+ /** @type {sglrReferenceContext.Framebuffer} */ var framebufferBinding = (target == gl.FRAMEBUFFER || target == gl.DRAW_FRAMEBUFFER) ? this.m_drawFramebufferBinding : this.m_readFramebufferBinding;
+ if (this.conditionalSetError(!framebufferBinding, gl.INVALID_OPERATION))
+ return;
+
+ if (texture) {
+ if (this.conditionalSetError(level != 0, gl.INVALID_VALUE))
+ return;
+
+ if (texture.getType() == sglrReferenceContext.TextureType.TYPE_2D) {
+ if (this.conditionalSetError(fboTexTarget != sglrReferenceContext.TexTarget.TEXTARGET_2D, gl.INVALID_OPERATION))
+ return;
+ } else {
+ if (!texture.getType() == sglrReferenceContext.TextureType.TYPE_CUBE_MAP)
+ throw new Error('Unsupported texture type');
+ if (this.conditionalSetError(!deMath.deInRange32(fboTexTarget, sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_POSITIVE_X, sglrReferenceContext.TexTarget.TEXTARGET_CUBE_MAP_NEGATIVE_Z), gl.INVALID_OPERATION))
+ return;
+ }
+ }
+
+ /** @type {sglrReferenceContext.Attachment} */ var fboAttachment = new sglrReferenceContext.Attachment();
+
+ if (texture) {
+ fboAttachment.type = sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_TEXTURE;
+ fboAttachment.object = texture;
+ fboAttachment.texTarget = fboTexTarget;
+ fboAttachment.level = level;
+ }
+ framebufferBinding.setAttachment(point, fboAttachment);
+ }
+ };
+
+ /**
+ * @param {number} target
+ * @param {number} attachment
+ * @param {sglrReferenceContext.TextureContainer} texture
+ * @param {number} level
+ * @param {number} layer
+ * @throws {Error}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.framebufferTextureLayer = function(target, attachment, texture, level, layer) {
+ if (attachment == gl.DEPTH_STENCIL_ATTACHMENT) {
+ // Attach to both depth and stencil.
+ this.framebufferTextureLayer(target, gl.DEPTH_ATTACHMENT, texture, level, layer);
+ this.framebufferTextureLayer(target, gl.STENCIL_ATTACHMENT, texture, level, layer);
+ } else {
+ /** @type {sglrReferenceContext.AttachmentPoint} */ var point = sglrReferenceContext.mapGLAttachmentPoint(attachment);
+
+ if (this.conditionalSetError(target != gl.FRAMEBUFFER &&
+ target != gl.DRAW_FRAMEBUFFER &&
+ target != gl.READ_FRAMEBUFFER, gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(point === undefined, gl.INVALID_ENUM))
+ return;
+
+ // Select binding point.
+ /** @type {sglrReferenceContext.Framebuffer} */ var framebufferBinding = (target == gl.FRAMEBUFFER || target == gl.DRAW_FRAMEBUFFER) ? this.m_drawFramebufferBinding : this.m_readFramebufferBinding;
+ if (this.conditionalSetError(!framebufferBinding, gl.INVALID_OPERATION))
+ return;
+
+ if (texture) {
+ if (this.conditionalSetError(level != 0, gl.INVALID_VALUE))
+ return;
+
+ if (this.conditionalSetError(texture.getType() != sglrReferenceContext.TextureType.TYPE_2D_ARRAY &&
+ texture.getType() != sglrReferenceContext.TextureType.TYPE_3D &&
+ texture.getType() != sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY, gl.INVALID_OPERATION))
+ return;
+
+ if (texture.getType() == sglrReferenceContext.TextureType.TYPE_2D_ARRAY || texture.getType() == sglrReferenceContext.TextureType.TYPE_CUBE_MAP_ARRAY) {
+ if (this.conditionalSetError((layer < 0) || (layer >= gl.MAX_ARRAY_TEXTURE_LAYERS), gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError((level < 0) || (level > Math.floor(Math.log2(gl.MAX_TEXTURE_SIZE))), gl.INVALID_VALUE))
+ return;
+ } else if (texture.getType() == sglrReferenceContext.TextureType.TYPE_3D) {
+ if (this.conditionalSetError((layer < 0) || (layer >= gl.MAX_3D_TEXTURE_SIZE), gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError((level < 0) || (level > Math.floor(Math.log2(gl.MAX_3D_TEXTURE_SIZE))), gl.INVALID_VALUE))
+ return;
+ }
+ }
+
+ /** @type {sglrReferenceContext.Attachment} */ var fboAttachment = new sglrReferenceContext.Attachment();
+
+ if (texture) {
+ fboAttachment.type = sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_TEXTURE;
+ fboAttachment.object = texture;
+ fboAttachment.texTarget = sglrReferenceContext.texLayeredTypeToTarget(texture.getType());
+ fboAttachment.level = level;
+ fboAttachment.layer = layer;
+ }
+ framebufferBinding.setAttachment(point, fboAttachment);
+
+ }
+ };
+
+ /**
+ * @param {number} target
+ * @param {number} attachment
+ * @param {number} renderbuffertarget
+ * @param {sglrReferenceContext.Renderbuffer} renderbuffer
+ */
+ sglrReferenceContext.ReferenceContext.prototype.framebufferRenderbuffer = function(target, attachment, renderbuffertarget, renderbuffer) {
+ if (attachment == gl.DEPTH_STENCIL_ATTACHMENT) {
+ // Attach both to depth and stencil.
+ this.framebufferRenderbuffer(target, gl.DEPTH_ATTACHMENT, renderbuffertarget, renderbuffer);
+ this.framebufferRenderbuffer(target, gl.STENCIL_ATTACHMENT, renderbuffertarget, renderbuffer);
+ } else {
+ /** @type {sglrReferenceContext.AttachmentPoint} */ var point = sglrReferenceContext.mapGLAttachmentPoint(attachment);
+
+ if (this.conditionalSetError(target != gl.FRAMEBUFFER &&
+ target != gl.DRAW_FRAMEBUFFER &&
+ target != gl.READ_FRAMEBUFFER, gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(point == undefined, gl.INVALID_ENUM))
+ return;
+
+ // Select binding point.
+ /** @type {sglrReferenceContext.Framebuffer} */ var framebufferBinding = (target == gl.FRAMEBUFFER || target == gl.DRAW_FRAMEBUFFER) ? this.m_drawFramebufferBinding : this.m_readFramebufferBinding;
+ if (this.conditionalSetError(!framebufferBinding, gl.INVALID_OPERATION))
+ return;
+
+ if (renderbuffer) {
+ if (this.conditionalSetError(renderbuffertarget != gl.RENDERBUFFER, gl.INVALID_ENUM))
+ return;
+ }
+
+ /** @type {sglrReferenceContext.Attachment} */ var fboAttachment = new sglrReferenceContext.Attachment();
+
+ if (renderbuffer) {
+ fboAttachment.type = sglrReferenceContext.AttachmentType.ATTACHMENTTYPE_RENDERBUFFER;
+ fboAttachment.object = renderbuffer;
+ }
+ framebufferBinding.setAttachment(point, fboAttachment);
+ }
+ };
+
+ /**
+ * @param {number} target
+ * @param {number} internalformat
+ * @param {number} width
+ * @param {number} height
+ */
+ sglrReferenceContext.ReferenceContext.prototype.renderbufferStorage = function(target, internalformat, width, height) {
+ /** @type {tcuTexture.TextureFormat} */ var format = gluTextureUtil.mapGLInternalFormat(internalformat);
+
+ if (this.conditionalSetError(target != gl.RENDERBUFFER, gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError(!this.m_renderbufferBinding, gl.INVALID_OPERATION))
+ return;
+ if (this.conditionalSetError(!deMath.deInRange32(width, 0, this.m_limits.maxRenderbufferSize) ||
+ !deMath.deInRange32(height, 0, this.m_limits.maxRenderbufferSize),
+ gl.INVALID_OPERATION))
+ return;
+ if (this.conditionalSetError(!format, gl.INVALID_ENUM))
+ return;
+
+ this.m_renderbufferBinding.setStorage(format, width, height);
+ };
+
+ /**
+ * @param {number} target
+ * @param {number} samples
+ * @param {number} internalformat
+ * @param {number} width
+ * @param {number} height
+ */
+ sglrReferenceContext.ReferenceContext.prototype.renderbufferStorageMultisample = function(target, samples, internalformat, width, height) {
+ this.renderbufferStorage(target, internalformat, width, height);
+ };
+
+ /**
+ * @param {rrRenderer.PrimitiveType} derivedType
+ * @return {rrRenderer.PrimitiveType}
+ * @throws {Error}
+ */
+ sglrReferenceContext.getPrimitiveBaseType = function(derivedType) {
+ switch (derivedType) {
+ case rrRenderer.PrimitiveType.TRIANGLES:
+ case rrRenderer.PrimitiveType.TRIANGLE_STRIP:
+ case rrRenderer.PrimitiveType.TRIANGLE_FAN:
+ return rrRenderer.PrimitiveType.TRIANGLES;
+
+ case rrRenderer.PrimitiveType.LINES:
+ case rrRenderer.PrimitiveType.LINE_STRIP:
+ case rrRenderer.PrimitiveType.LINE_LOOP:
+ return rrRenderer.PrimitiveType.LINES;
+
+ case rrRenderer.PrimitiveType.POINTS:
+ return rrRenderer.PrimitiveType.POINTS;
+
+ default:
+ throw new Error('Unrecognized primitive type:' + derivedType);
+ }
+ };
+
+ /**
+ * createProgram
+ * @param {sglrShaderProgram.ShaderProgram} program
+ * @return {sglrShaderProgram.ShaderProgram}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.createProgram = function(program) {
+ return program;
+ };
+
+ /**
+ * deleteProgram
+ * @param {sglrShaderProgram.ShaderProgram} program
+ */
+ sglrReferenceContext.ReferenceContext.prototype.deleteProgram = function(program) {};
+
+ /**
+ * @param {sglrShaderProgram.ShaderProgram} program
+ */
+ sglrReferenceContext.ReferenceContext.prototype.useProgram = function(program) {
+ this.m_currentProgram = program;
+ };
+
+ /**
+ * Draws quads from vertex arrays
+ * @param {number} primitive GL primitive type to draw with.
+ * @param {number} first First vertex to begin drawing with
+ * @param {number} count How many vertices to draw (not counting vertices before first)
+ */
+ sglrReferenceContext.ReferenceContext.prototype.drawArrays = function(primitive, first, count) {
+ this.drawQuads(primitive, first, count, 1);
+ };
+
+ /**
+ * Draws quads from vertex arrays
+ * @param {number} primitive GL primitive type to draw with.
+ * @param {(number|rrRenderer.DrawIndices)} first First vertex to begin drawing with
+ * @param {number} count Number of vertices
+ * @param {number=} instances Number of instances
+ */
+ sglrReferenceContext.ReferenceContext.prototype.drawQuads = function(primitive, first, count, instances) {
+ // undefined results
+ if (!this.m_currentProgram)
+ return;
+
+ if (typeof instances === 'undefined')
+ instances = 1;
+
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var colorBuf0 = this.getDrawColorbuffer();
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var depthBuf = this.getDrawDepthbuffer();
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var stencilBuf = this.getDrawStencilbuffer();
+ /** @type {boolean} */ var hasStencil = /** @type {!boolean} */ (stencilBuf && !stencilBuf.isEmpty());
+ /** @type {number} */ var stencilBits = (hasStencil) ? stencilBuf.raw().getFormat().getNumStencilBits() : 0;
+
+ /** @type {rrRenderer.RenderTarget} */ var renderTarget = new rrRenderer.RenderTarget(colorBuf0,
+ depthBuf,
+ stencilBuf);
+ /** @type {sglrShaderProgram.ShaderProgram} */ var program = this.m_currentProgram;
+
+ /*new rrRenderer.Program(
+ * this.m_currentProgram.getVertexShader(),
+ * this.m_currentProgram.getFragmentShader());*/
+
+ /** @type {rrRenderState.ViewportState} */ var viewportState = new rrRenderState.ViewportState(colorBuf0);
+ /** @type {rrRenderState.RenderState} */ var state = new rrRenderState.RenderState(viewportState);
+
+ /** @type {Array<rrVertexAttrib.VertexAttrib>} */ var vertexAttribs = [];
+
+ // Gen state
+ /** @type {rrRenderer.PrimitiveType} */ var baseType = rrRenderer.PrimitiveType.TRIANGLES;
+ /** @type {boolean} */ var polygonOffsetEnabled =
+ (baseType == rrRenderer.PrimitiveType.TRIANGLES) ?
+ (this.m_polygonOffsetFillEnabled) :
+ (false);
+
+ //state.cullMode = m_cullMode
+
+ state.fragOps.scissorTestEnabled = this.m_scissorEnabled;
+ state.fragOps.scissorRectangle = new rrRenderState.WindowRectangle(this.m_scissorBox);
+
+ state.fragOps.numStencilBits = stencilBits;
+ state.fragOps.stencilTestEnabled = this.m_stencilTestEnabled;
+
+ for (var key in rrDefs.FaceType) {
+ /** @type {number} */ var faceType = rrDefs.FaceType[key];
+ state.fragOps.stencilStates[faceType].compMask = this.m_stencil[faceType].opMask;
+ state.fragOps.stencilStates[faceType].writeMask = this.m_stencil[faceType].writeMask;
+ state.fragOps.stencilStates[faceType].ref = this.m_stencil[faceType].ref;
+ state.fragOps.stencilStates[faceType].func = sglrReferenceUtils.mapGLTestFunc(this.m_stencil[faceType].func);
+ state.fragOps.stencilStates[faceType].sFail = sglrReferenceUtils.mapGLStencilOp(this.m_stencil[faceType].opStencilFail);
+ state.fragOps.stencilStates[faceType].dpFail = sglrReferenceUtils.mapGLStencilOp(this.m_stencil[faceType].opDepthFail);
+ state.fragOps.stencilStates[faceType].dpPass = sglrReferenceUtils.mapGLStencilOp(this.m_stencil[faceType].opDepthPass);
+ }
+
+ state.fragOps.depthTestEnabled = this.m_depthTestEnabled;
+ state.fragOps.depthFunc = sglrReferenceUtils.mapGLTestFunc(this.m_depthFunc);
+ state.fragOps.depthMask = this.m_depthMask;
+
+ state.fragOps.blendMode = this.m_blendEnabled ? rrRenderState.BlendMode.STANDARD : rrRenderState.BlendMode.NONE;
+ state.fragOps.blendRGBState.equation = sglrReferenceUtils.mapGLBlendEquation(this.m_blendModeRGB);
+ state.fragOps.blendRGBState.srcFunc = sglrReferenceUtils.mapGLBlendFunc(this.m_blendFactorSrcRGB);
+ state.fragOps.blendRGBState.dstFunc = sglrReferenceUtils.mapGLBlendFunc(this.m_blendFactorDstRGB);
+ state.fragOps.blendAState.equation = sglrReferenceUtils.mapGLBlendEquation(this.m_blendModeAlpha);
+ state.fragOps.blendAState.srcFunc = sglrReferenceUtils.mapGLBlendFunc(this.m_blendFactorSrcAlpha);
+ state.fragOps.blendAState.dstFunc = sglrReferenceUtils.mapGLBlendFunc(this.m_blendFactorDstAlpha);
+ state.fragOps.blendColor = this.m_blendColor;
+
+ state.fragOps.colorMask = this.m_colorMask;
+
+ state.viewport.rect = new rrRenderState.WindowRectangle(this.m_viewport);
+ state.viewport.zn = this.m_depthRangeNear;
+ state.viewport.zf = this.m_depthRangeFar;
+
+ //state.point.pointSize = this.m_pointSize;
+ state.line.lineWidth = this.m_lineWidth;
+
+ state.fragOps.polygonOffsetEnabled = polygonOffsetEnabled;
+ state.fragOps.polygonOffsetFactor = this.m_polygonOffsetFactor;
+ state.fragOps.polygonOffsetUnits = this.m_polygonOffsetUnits;
+
+ state.provokingVertexConvention = (this.m_provokingFirstVertexConvention) ? (rrDefs.ProvokingVertex.PROVOKINGVERTEX_FIRST) : (rrDefs.ProvokingVertex.PROVOKINGVERTEX_LAST);
+
+ // gen attributes
+ /** @type {sglrReferenceContext.VertexArray} */ var vao = this.m_vertexArrayBinding;
+ for (var ndx = 0; ndx < vao.m_arrays.length; ++ndx) {
+ vertexAttribs[ndx] = new rrVertexAttrib.VertexAttrib();
+ if (!vao.m_arrays[ndx].enabled) {
+ vertexAttribs[ndx].type = rrVertexAttrib.VertexAttribType.DONT_CARE; // reading with wrong type is allowed, but results are undefined
+ vertexAttribs[ndx].generic = this.m_currentAttribs[ndx];
+ } else {
+ vertexAttribs[ndx].type = (vao.m_arrays[ndx].integer) ?
+ (sglrReferenceUtils.mapGLPureIntegerVertexAttributeType(vao.m_arrays[ndx].type)) :
+ (sglrReferenceUtils.mapGLFloatVertexAttributeType(vao.m_arrays[ndx].type, vao.m_arrays[ndx].normalized, vao.m_arrays[ndx].size));
+ vertexAttribs[ndx].size = sglrReferenceUtils.mapGLSize(vao.m_arrays[ndx].size);
+ vertexAttribs[ndx].stride = vao.m_arrays[ndx].stride;
+ vertexAttribs[ndx].instanceDivisor = vao.m_arrays[ndx].divisor;
+ vertexAttribs[ndx].pointer = vao.m_arrays[ndx].bufferBinding.getData();
+ vertexAttribs[ndx].offset = vao.m_arrays[ndx].offset;
+ vertexAttribs[ndx].componentCount = vao.m_arrays[ndx].size;
+ }
+ }
+
+ // Set shader samplers
+ for (var uniformNdx = 0; uniformNdx < this.m_currentProgram.m_uniforms.length; ++uniformNdx) {
+ /** @type {number} */ var texNdx = this.m_currentProgram.m_uniforms[uniformNdx].value[0];
+
+ switch (this.m_currentProgram.m_uniforms[uniformNdx].type) {
+ case gluShaderUtil.DataType.SAMPLER_2D:
+ case gluShaderUtil.DataType.UINT_SAMPLER_2D:
+ case gluShaderUtil.DataType.INT_SAMPLER_2D: {
+ /** @type {sglrReferenceContext.Texture2D} */ var tex;
+
+ if (texNdx >= 0 && texNdx < this.m_textureUnits.length)
+ tex = /** @type {sglrReferenceContext.Texture2D} */ (this.m_textureUnits[texNdx].tex2DBinding.texture);
+
+ if (tex && tex.isComplete()) {
+ tex.updateView();
+ this.m_currentProgram.m_uniforms[uniformNdx].sampler = tex;
+ } else
+ this.m_currentProgram.m_uniforms[uniformNdx].sampler = this.m_emptyTex2D.texture;
+
+ break;
+ }
+ case gluShaderUtil.DataType.SAMPLER_CUBE:
+ case gluShaderUtil.DataType.UINT_SAMPLER_CUBE:
+ case gluShaderUtil.DataType.INT_SAMPLER_CUBE: {
+ /** @type {sglrReferenceContext.TextureCube} */ var texCube;
+
+ if (texNdx >= 0 && texNdx < this.m_textureUnits.length)
+ texCube = /** @type {sglrReferenceContext.TextureCube} */ (this.m_textureUnits[texNdx].texCubeBinding.texture);
+
+ if (texCube && texCube.isComplete()) {
+ texCube.updateView();
+ this.m_currentProgram.m_uniforms[uniformNdx].sampler = texCube;
+ } else
+ this.m_currentProgram.m_uniforms[uniformNdx].sampler = this.m_emptyTexCube.texture;
+
+ break;
+ }
+ case gluShaderUtil.DataType.SAMPLER_2D_ARRAY:
+ case gluShaderUtil.DataType.UINT_SAMPLER_2D_ARRAY:
+ case gluShaderUtil.DataType.INT_SAMPLER_2D_ARRAY: {
+ /** @type {sglrReferenceContext.Texture2DArray} */ var tex2DArray;
+
+ if (texNdx >= 0 && texNdx < this.m_textureUnits.length)
+ tex2DArray = /** @type {sglrReferenceContext.Texture2DArray} */ (this.m_textureUnits[texNdx].tex2DArrayBinding.texture);
+
+ if (tex2DArray && tex2DArray.isComplete()) {
+ tex2DArray.updateView();
+ this.m_currentProgram.m_uniforms[uniformNdx].sampler = tex2DArray;
+ } else
+ this.m_currentProgram.m_uniforms[uniformNdx].sampler = this.m_emptyTex2DArray.texture;
+
+ break;
+ }
+ case gluShaderUtil.DataType.SAMPLER_3D:
+ case gluShaderUtil.DataType.UINT_SAMPLER_3D:
+ case gluShaderUtil.DataType.INT_SAMPLER_3D: {
+ /** @type {sglrReferenceContext.Texture3D} */ var tex3D;
+
+ if (texNdx >= 0 && texNdx < this.m_textureUnits.length)
+ tex3D = /** @type {sglrReferenceContext.Texture3D} */ (this.m_textureUnits[texNdx].tex3DBinding.texture);
+
+ if (tex3D && tex3D.isComplete()) {
+ tex3D.updateView();
+ this.m_currentProgram.m_uniforms[uniformNdx].sampler = tex3D;
+ } else
+ this.m_currentProgram.m_uniforms[uniformNdx].sampler = this.m_emptyTex3D.texture;
+
+ break;
+ }
+ /* TODO: Port
+ case gluShaderUtil.DataType.SAMPLER_CUBE_ARRAY:
+ case gluShaderUtil.DataType.UINT_SAMPLER_CUBE_ARRAY:
+ case gluShaderUtil.DataType.INT_SAMPLER_CUBE_ARRAY:{
+ rc::TextureCubeArray* tex = DE_NULL;
+
+ if (texNdx >= 0 && (size_t)texNdx < m_textureUnits.length)
+ tex = (this.m_textureUnits[texNdx].texCubeArrayBinding) ? (this.m_textureUnits[texNdx].texCubeArrayBinding) : (&this.m_textureUnits[texNdx].defaultCubeArrayTex);
+
+ if (tex && tex.isComplete()) {
+ tex.updateView();
+ this.m_currentProgram.m_uniforms[uniformNdx].sampler.texCubeArray = tex;
+ } else
+ this.m_currentProgram.m_uniforms[uniformNdx].sampler.texCubeArray = &this.m_emptyTexCubeArray;
+
+ break;
+ }
+ */
+ default:
+ // nothing
+ break;
+ }
+ }
+
+ var primitiveType = sglrReferenceUtils.mapGLPrimitiveType(primitive);
+
+ var renderFunction = rrRenderer.drawTriangles;
+ if (primitiveType == rrRenderer.PrimitiveType.LINES ||
+ primitiveType == rrRenderer.PrimitiveType.LINE_STRIP ||
+ primitiveType == rrRenderer.PrimitiveType.LINE_LOOP)
+ renderFunction = rrRenderer.drawLines;
+ else if (primitiveType == rrRenderer.PrimitiveType.POINTS)
+ renderFunction = rrRenderer.drawPoints;
+
+ for (var instanceID = 0; instanceID < instances; instanceID++)
+ renderFunction(state, renderTarget, program, vertexAttribs, primitiveType, first, count, instanceID);
+ };
+
+ /**
+ * @param {Array<number>} rect
+ * @return {boolean}
+ */
+ sglrReferenceContext.isEmpty = function(rect) { return rect[2] == 0 || rect[3] == 0; };
+
+ /**
+ * @param {number} mask
+ * @param {Array<number>} srcRect
+ * @param {Array<number>} dstRect
+ * @param {boolean} flipX
+ * @param {boolean} flipY
+ * @throws {Error}
+ */
+ sglrReferenceContext.ReferenceContext.prototype.blitResolveMultisampleFramebuffer = function(mask, srcRect, dstRect, flipX, flipY) {
+ throw new Error('Unimplemented');
+ };
+
+ /**
+ * @param {number} srcX0
+ * @param {number} srcY0
+ * @param {number} srcX1
+ * @param {number} srcY1
+ * @param {number} dstX0
+ * @param {number} dstY0
+ * @param {number} dstX1
+ * @param {number} dstY1
+ * @param {number} mask
+ * @param {number} filter
+ */
+ sglrReferenceContext.ReferenceContext.prototype.blitFramebuffer = function(srcX0, srcY0, srcX1, srcY1, dstX0, dstY0, dstX1, dstY1, mask, filter) {
+ // p0 in inclusive, p1 exclusive.
+ // Negative width/height means swap.
+ /** @type {boolean} */ var swapSrcX = srcX1 < srcX0;
+ /** @type {boolean} */ var swapSrcY = srcY1 < srcY0;
+ /** @type {boolean} */ var swapDstX = dstX1 < dstX0;
+ /** @type {boolean} */ var swapDstY = dstY1 < dstY0;
+ /** @type {number} */ var srcW = Math.abs(srcX1 - srcX0);
+ /** @type {number} */ var srcH = Math.abs(srcY1 - srcY0);
+ /** @type {number} */ var dstW = Math.abs(dstX1 - dstX0);
+ /** @type {number} */ var dstH = Math.abs(dstY1 - dstY0);
+ /** @type {boolean} */ var scale = srcW != dstW || srcH != dstH;
+ /** @type {number} */ var srcOriginX = swapSrcX ? srcX1 : srcX0;
+ /** @type {number} */ var srcOriginY = swapSrcY ? srcY1 : srcY0;
+ /** @type {number} */ var dstOriginX = swapDstX ? dstX1 : dstX0;
+ /** @type {number} */ var dstOriginY = swapDstY ? dstY1 : dstY0;
+ /** @type {Array<number>} */ var srcRect = [srcOriginX, srcOriginY, srcW, srcH];
+ /** @type {Array<number>} */ var dstRect = [dstOriginX, dstOriginY, dstW, dstH];
+
+ if (this.conditionalSetError(filter != gl.NEAREST && filter != gl.LINEAR, gl.INVALID_ENUM))
+ return;
+ if (this.conditionalSetError((mask & (gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT)) != 0 && filter != gl.NEAREST, gl.INVALID_OPERATION))
+ return;
+
+ // Validate that both targets are complete.
+ if (this.conditionalSetError(this.checkFramebufferStatus(gl.DRAW_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE ||
+ this.checkFramebufferStatus(gl.READ_FRAMEBUFFER) != gl.FRAMEBUFFER_COMPLETE, gl.INVALID_OPERATION))
+ return;
+
+ // Check samples count is valid
+ if (this.conditionalSetError(this.getDrawColorbuffer().getNumSamples() != 1, gl.INVALID_OPERATION))
+ return;
+
+ // Check size restrictions of multisampled case
+ if (this.getReadColorbuffer().getNumSamples() != 1) {
+ // Src and Dst rect dimensions must be the same
+ if (this.conditionalSetError(srcW != dstW || srcH != dstH, gl.INVALID_OPERATION))
+ return;
+
+ // sglrReferenceContext.Framebuffer formats must match
+ if (mask & gl.COLOR_BUFFER_BIT)
+ if (this.conditionalSetError(this.getReadColorbuffer().raw().getFormat() != this.getDrawColorbuffer().raw().getFormat(), gl.INVALID_OPERATION))
+ return;
+ if (mask & gl.DEPTH_BUFFER_BIT)
+ if (this.conditionalSetError(this.getReadDepthbuffer().raw().getFormat() != this.getDrawDepthbuffer().raw().getFormat(), gl.INVALID_OPERATION))
+ return;
+ if (mask & gl.STENCIL_BUFFER_BIT)
+ if (this.conditionalSetError(this.getReadStencilbuffer().raw().getFormat() != this.getDrawStencilbuffer().raw().getFormat(), gl.INVALID_OPERATION))
+ return;
+ }
+
+ // Compute actual source rect.
+ srcRect = (mask & gl.COLOR_BUFFER_BIT) ? deMath.intersect(srcRect, sglrReferenceContext.getBufferRect(this.getReadColorbuffer())) : srcRect;
+ srcRect = (mask & gl.DEPTH_BUFFER_BIT) ? deMath.intersect(srcRect, sglrReferenceContext.getBufferRect(this.getReadDepthbuffer())) : srcRect;
+ srcRect = (mask & gl.STENCIL_BUFFER_BIT) ? deMath.intersect(srcRect, sglrReferenceContext.getBufferRect(this.getReadStencilbuffer())) : srcRect;
+
+ // Compute destination rect.
+ dstRect = (mask & gl.COLOR_BUFFER_BIT) ? deMath.intersect(dstRect, sglrReferenceContext.getBufferRect(this.getDrawColorbuffer())) : dstRect;
+ dstRect = (mask & gl.DEPTH_BUFFER_BIT) ? deMath.intersect(dstRect, sglrReferenceContext.getBufferRect(this.getDrawDepthbuffer())) : dstRect;
+ dstRect = (mask & gl.STENCIL_BUFFER_BIT) ? deMath.intersect(dstRect, sglrReferenceContext.getBufferRect(this.getDrawStencilbuffer())) : dstRect;
+ dstRect = this.m_scissorEnabled ? deMath.intersect(dstRect, this.m_scissorBox) : dstRect;
+
+ if (sglrReferenceContext.isEmpty(srcRect) || sglrReferenceContext.isEmpty(dstRect))
+ return; // Don't attempt copy.
+
+ // Multisampled read buffer is a special case
+ if (this.getReadColorbuffer().getNumSamples() != 1) {
+ /** @type {boolean} */ var swapX = swapSrcX ^ swapDstX ? true : false;
+ /** @type {boolean} */ var swapY = swapSrcY ^ swapDstY ? true : false;
+ var error = this.blitResolveMultisampleFramebuffer(mask, srcRect, dstRect, swapX, swapY);
+
+ if (error != gl.NO_ERROR)
+ this.setError(error);
+
+ return;
+ }
+
+ // \note Multisample pixel buffers can now be accessed like non-multisampled because multisample read buffer case is already handled. => sample count must be 1
+
+ // Coordinate transformation:
+ // Dst offset space -> dst rectangle space -> src rectangle space -> src offset space.
+ /** @type {tcuMatrix.Matrix} */ var matrix = tcuMatrixUtil.translationMatrix([srcX0 - srcRect[0], srcY0 - srcRect[1]]);
+ matrix = tcuMatrix.multiply(matrix, tcuMatrix.matrixFromVector(3, 3, [(srcX1 - srcX0) / (dstX1 - dstX0), (srcY1 - srcY0) / (dstY1 - dstY0), 1]));
+ matrix = tcuMatrix.multiply(matrix, tcuMatrixUtil.translationMatrix([dstRect[0] - dstX0, dstRect[1] - dstY0]));
+
+ /**
+ * @param {number} x
+ * @param {number} y
+ * @return {number}
+ */
+ var transform = function(x, y) { return matrix.get(x, y); };
+
+ /** @type {number} */ var dX;
+ /** @type {number} */ var dY;
+ /** @type {number} */ var sX;
+ /** @type {number} */ var sY;
+ /** @type {tcuTexture.PixelBufferAccess|rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var src;
+ /** @type {tcuTexture.PixelBufferAccess|rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var dst;
+
+ if (mask & gl.COLOR_BUFFER_BIT) {
+ src = tcuTextureUtil.getSubregion(this.getReadColorbuffer().toSinglesampleAccess(), srcRect[0], srcRect[1], 0, srcRect[2], srcRect[3], 1);
+ dst = tcuTextureUtil.getSubregion(this.getDrawColorbuffer().toSinglesampleAccess(), dstRect[0], dstRect[1], 0, dstRect[2], dstRect[3], 1);
+ /** @type {tcuTexture.TextureChannelClass} */ var dstClass = tcuTexture.getTextureChannelClass(dst.getFormat().type);
+ /** @type {boolean} */ var dstIsFloat = dstClass == tcuTexture.TextureChannelClass.FLOATING_POINT ||
+ dstClass == tcuTexture.TextureChannelClass.UNSIGNED_FIXED_POINT ||
+ dstClass == tcuTexture.TextureChannelClass.SIGNED_FIXED_POINT;
+ /** @type {tcuTexture.FilterMode} */ var sFilter = (scale && filter == gl.LINEAR) ? tcuTexture.FilterMode.LINEAR : tcuTexture.FilterMode.NEAREST;
+ /** @type {tcuTexture.Sampler} */ var sampler = new tcuTexture.Sampler(tcuTexture.WrapMode.CLAMP_TO_EDGE, tcuTexture.WrapMode.CLAMP_TO_EDGE, tcuTexture.WrapMode.CLAMP_TO_EDGE,
+ sFilter, sFilter, 0.0 /* lod threshold */, false /* non-normalized coords */);
+ /** @type {boolean} */ var srcIsSRGB = src.getFormat().order == tcuTexture.ChannelOrder.sRGB || src.getFormat().order == tcuTexture.ChannelOrder.sRGBA;
+ /** @type {boolean} */ var dstIsSRGB = dst.getFormat().order == tcuTexture.ChannelOrder.sRGB || dst.getFormat().order == tcuTexture.ChannelOrder.sRGBA;
+ /** @type {boolean} */ var convertSRGB = this.m_sRGBUpdateEnabled;
+
+ // \note We don't check for unsupported conversions, unlike spec requires.
+
+ for (var yo = 0; yo < dstRect[3]; yo++) {
+ for (var xo = 0; xo < dstRect[2]; xo++) {
+ dX = xo + 0.5;
+ dY = yo + 0.5;
+
+ // \note Only affine part is used.
+ sX = transform(0, 0) * dX + transform(0, 1) * dY + transform(0, 2);
+ sY = transform(1, 0) * dX + transform(1, 1) * dY + transform(1, 2);
+
+ // do not copy pixels outside the modified source region (modified by buffer intersection)
+ if (sX < 0.0 || sX >= srcRect[2] ||
+ sY < 0.0 || sY >= srcRect[3])
+ continue;
+
+ if (dstIsFloat || srcIsSRGB || filter == tcuTexture.FilterMode.LINEAR) {
+ /** @type {Array<number>} */ var p = src.sample2D(sampler, sampler.minFilter, sX, sY, 0);
+ dst.setPixel((dstIsSRGB && convertSRGB) ? tcuTextureUtil.linearToSRGB(p) : p, xo, yo);
+ } else
+ dst.setPixelInt(src.getPixelInt(Math.floor(sX), Math.floor(sY)), xo, yo);
+ }
+ }
+ }
+
+ if ((mask & gl.DEPTH_BUFFER_BIT) && this.m_depthMask) {
+ src = this.getReadDepthbuffer().getSubregion(srcRect);
+ dst = this.getDrawDepthbuffer().getSubregion(dstRect);
+
+ for (var yo = 0; yo < dstRect[3]; yo++) {
+ for (var xo = 0; xo < dstRect[2]; xo++) {
+ var sampleNdx = 0; // multisample read buffer case is already handled
+
+ dX = xo + 0.5;
+ dY = yo + 0.5;
+ sX = transform(0, 0) * dX + transform(0, 1) * dY + transform(0, 2);
+ sY = transform(1, 0) * dX + transform(1, 1) * dY + transform(1, 2);
+
+ sglrReferenceContext.writeDepthOnly(dst, sampleNdx, xo, yo, src.raw().getPixel(sampleNdx, Math.floor(sX), Math.floor(sY))[0]);
+ }
+ }
+ }
+
+ if (mask & gl.STENCIL_BUFFER_BIT) {
+ src = this.getReadStencilbuffer().getSubregion(srcRect);
+ dst = this.getDrawStencilbuffer().getSubregion(dstRect);
+
+ for (var yo = 0; yo < dstRect[3]; yo++) {
+ for (var xo = 0; xo < dstRect[2]; xo++) {
+ var sampleNdx = 0; // multisample read buffer case is already handled
+
+ dX = xo + 0.5;
+ dY = yo + 0.5;
+ sX = transform(0, 0) * dX + transform(0, 1) * dY + transform(0, 2);
+ sY = transform(1, 0) * dX + transform(1, 1) * dY + transform(1, 2);
+
+ sglrReferenceContext.writeStencilOnly(dst, sampleNdx, xo, yo, src.raw().getPixelInt(sampleNdx, Math.floor(sX), Math.floor(sY))[3], this.m_stencil[rrDefs.FaceType.FACETYPE_FRONT].writeMask);
+ }
+ }
+ }
+ };
+
+ /**
+ * @param {number} internalFormat
+ * @return {tcuTexture.TextureFormat}
+ */
+ sglrReferenceContext.mapInternalFormat = function(internalFormat) {
+ switch (internalFormat) {
+ case gl.ALPHA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.A, tcuTexture.ChannelType.UNORM_INT8);
+ case gl.LUMINANCE: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.L, tcuTexture.ChannelType.UNORM_INT8);
+ case gl.LUMINANCE_ALPHA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.LA, tcuTexture.ChannelType.UNORM_INT8);
+ case gl.RGB: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGB, tcuTexture.ChannelType.UNORM_INT8);
+ case gl.RGBA: return new tcuTexture.TextureFormat(tcuTexture.ChannelOrder.RGBA, tcuTexture.ChannelType.UNORM_INT8);
+
+ default:
+ return gluTextureUtil.mapGLInternalFormat(internalFormat);
+ }
+ };
+
+ /**
+ * @param {tcuTexture.PixelBufferAccess} dst
+ * @param {tcuTexture.ConstPixelBufferAccess} src
+ */
+ sglrReferenceContext.depthValueFloatClampCopy = function(dst, src) {
+ /** @type {number} */ var width = dst.getWidth();
+ /** @type {number} */ var height = dst.getHeight();
+ /** @type {number} */ var depth = dst.getDepth();
+
+ DE_ASSERT(src.getWidth() == width && src.getHeight() == height && src.getDepth() == depth);
+
+ // clamping copy
+ for (var z = 0; z < depth; z++)
+ for (var y = 0; y < height; y++)
+ for (var x = 0; x < width; x++) {
+ /** @type {Array<number>} */ var data = src.getPixel(x, y, z);
+ dst.setPixel([deMath.clamp(data[0], 0.0, 1.0), data[1], data[2], data[3]], x, y, z);
+ }
+ };
+
+ /**
+ * @param {number} target
+ * @param {number} level
+ * @param {number} internalFormat
+ * @param {number} width
+ * @param {number} height
+ */
+ sglrReferenceContext.ReferenceContext.prototype.texImage2DDelegate = function (target, level, internalFormat, width, height) {
+ var format;
+ var dataType;
+
+ switch (internalFormat)
+ {
+ case gl.ALPHA:
+ case gl.LUMINANCE:
+ case gl.LUMINANCE_ALPHA:
+ case gl.RGB:
+ case gl.RGBA:
+ format = internalFormat;
+ dataType = GL.UNSIGNED_BYTE;
+ break;
+ default:
+ {
+ var transferFmt = gluTextureUtil.getTransferFormat(gluTextureUtil.mapGLInternalFormat(internalFormat));
+ format = transferFmt.format;
+ dataType = transferFmt.dataType;
+ break;
+ }
+ }
+ this.texImage2D(target, level, internalFormat, width, height, 0, format, dataType, null);
+ };
+
+ /**
+ * @param {number} target
+ * @param {number} level
+ * @param {number} internalFormat
+ * @param {number} width
+ * @param {number} height
+ * @param {number} border
+ * @param {number} format
+ * @param {number} type
+ * @param {number} pixels
+ */
+ sglrReferenceContext.ReferenceContext.prototype.texImage2D = function(target, level, internalFormat, width, height, border, format, type, pixels) {
+ this.texImage3D(target, level, internalFormat, width, height, 1, border, format, type, pixels);
+ };
+
+ sglrReferenceContext.ReferenceContext.prototype.texImage3D = function(target, level, internalFormat, width, height, depth, border, format, type, pixels) {
+ /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture];
+ /** @type {ArrayBuffer} */ var data = null;
+ /** @type {number} */ var offset = 0;
+ /** @type {tcuTexture.PixelBufferAccess} */ var dst;
+ /** @type {tcuTexture.ConstPixelBufferAccess} */ var src;
+ if (this.m_pixelUnpackBufferBinding) {
+ if (this.conditionalSetError(typeof pixels !== 'number', gl.INVALID_VALUE))
+ return;
+ data = this.m_pixelUnpackBufferBinding.getData();
+ offset = pixels;
+ } else if (pixels) {
+ if (pixels instanceof ArrayBuffer) {
+ data = pixels;
+ offset = 0;
+ } else {
+ data = pixels.buffer;
+ offset = pixels.byteOffset;
+ }
+ }
+ /** @type {boolean} */ var isDstFloatDepthFormat = (internalFormat == gl.DEPTH_COMPONENT32F || internalFormat == gl.DEPTH32F_STENCIL8); // depth components are limited to [0,1] range
+
+ if (this.conditionalSetError(border != 0, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(width < 0 || height < 0 || depth < 0 || level < 0, gl.INVALID_VALUE))
+ return;
+
+ // Map storage format.
+ /** @type {tcuTexture.TextureFormat} */ var storageFmt = sglrReferenceContext.mapInternalFormat(internalFormat);
+ if (this.conditionalSetError(!storageFmt, gl.INVALID_ENUM))
+ return;
+
+ // Map transfer format.
+ /** @type {tcuTexture.TextureFormat} */ var transferFmt = gluTextureUtil.mapGLTransferFormat(format, type);
+ if (this.conditionalSetError(!transferFmt, gl.INVALID_ENUM))
+ return;
+
+ if (target == gl.TEXTURE_2D) {
+ // Validate size and level.
+ if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || height > this.m_limits.maxTexture2DSize || depth != 1, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(level > Math.log2(this.m_limits.maxTexture2DSize), gl.INVALID_VALUE))
+ return;
+
+ /** @type {sglrReferenceContext.Texture2D} */
+ var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture);
+
+ if (texture.isImmutable()) {
+ if (this.conditionalSetError(!texture.hasLevel(level), gl.INVALID_OPERATION))
+ return;
+
+ //NOTE: replaces this: var dst = tcuTexture.PixelBufferAccess.newFromTextureLevel(texture.getLevel(level));
+ dst = texture.getLevel(level);
+
+ if (this.conditionalSetError(!storageFmt.isEqual(dst.getFormat()) ||
+ width != dst.getWidth() ||
+ height != dst.getHeight(), gl.INVALID_OPERATION))
+ return;
+ } else
+ texture.allocLevel(level, storageFmt, width, height);
+
+ if (data) {
+ var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
+ var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
+ var skip = this.m_pixelUnpackSkipRows * rowPitch + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
+ src = new tcuTexture.ConstPixelBufferAccess({
+ format: transferFmt,
+ width: width,
+ height: height,
+ rowPitch: rowPitch,
+ data: data,
+ offset: offset + skip});
+
+ //NOTE: replaces this: var dst = tcuTexture.PixelBufferAccess.newFromTextureLevel(texture.getLevel(level));
+ dst = texture.getLevel(level);
+
+ if (isDstFloatDepthFormat)
+ sglrReferenceContext.depthValueFloatClampCopy(dst, src);
+ else
+ tcuTextureUtil.copy(dst, src);
+ } else {
+ // No data supplied, clear to black.
+
+ //NOTE: replaces this: var dst = tcuTexture.PixelBufferAccess.newFromTextureLevel(texture.getLevel(level));
+ dst = texture.getLevel(level);
+ dst.clear([0.0, 0.0, 0.0, 1.0]);
+ }
+ } else if (target == gl.TEXTURE_CUBE_MAP_NEGATIVE_X ||
+ target == gl.TEXTURE_CUBE_MAP_POSITIVE_X ||
+ target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Y ||
+ target == gl.TEXTURE_CUBE_MAP_POSITIVE_Y ||
+ target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ||
+ target == gl.TEXTURE_CUBE_MAP_POSITIVE_Z) {
+ // Validate size and level.
+ if (this.conditionalSetError(width != height || width > this.m_limits.maxTextureCubeSize || depth != 1, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTextureCubeSize)), gl.INVALID_VALUE))
+ return;
+
+ var textureCube = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture);
+
+ var face = sglrReferenceContext.mapGLCubeFace(target);
+
+ if (textureCube.isImmutable()) {
+ if (this.conditionalSetError(!textureCube.hasFace(level, face), gl.INVALID_OPERATION))
+ return;
+
+ dst = textureCube.getFace(level, face);
+
+ if (this.conditionalSetError(!storageFmt.isEqual(dst.getFormat()) ||
+ width != dst.getWidth() ||
+ height != dst.getHeight(), gl.INVALID_OPERATION))
+ return;
+ } else
+ textureCube.allocLevel(level, face, storageFmt, width, height);
+
+ if (data) {
+ var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
+ var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
+ var skip = this.m_pixelUnpackSkipRows * rowPitch + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
+ src = new tcuTexture.ConstPixelBufferAccess({
+ format: transferFmt,
+ width: width,
+ height: height,
+ rowPitch: rowPitch,
+ data: data,
+ offset: offset + skip});
+
+ dst = textureCube.getFace(level, face);
+
+ if (isDstFloatDepthFormat)
+ sglrReferenceContext.depthValueFloatClampCopy(dst, src);
+ else
+ tcuTextureUtil.copy(dst, src);
+ } else {
+ // No data supplied, clear to black.
+ dst = textureCube.getFace(level, face);
+ dst.clear([0.0, 0.0, 0.0, 1.0]);
+ }
+ } else if (target == gl.TEXTURE_2D_ARRAY) {
+ // Validate size and level.
+ if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize ||
+ height > this.m_limits.maxTexture2DSize ||
+ depth > this.m_limits.maxTexture2DArrayLayers, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture2DSize)), gl.INVALID_VALUE))
+ return;
+
+ /** @type {sglrReferenceContext.Texture2DArray} */
+ var texture2DArray = /** @type {sglrReferenceContext.Texture2DArray} */ (unit.tex2DArrayBinding.texture);
+
+ if (texture2DArray.isImmutable()) {
+ if (this.conditionalSetError(!texture2DArray.hasLevel(level), gl.INVALID_OPERATION))
+ return;
+
+ dst = texture2DArray.getLevel(level);
+ if (this.conditionalSetError(!storageFmt.isEqual(dst.getFormat()) ||
+ width != dst.getWidth() ||
+ height != dst.getHeight() ||
+ depth != dst.getDepth(), gl.INVALID_OPERATION))
+ return;
+ } else
+ texture2DArray.allocLevel(level, storageFmt, width, height, depth);
+
+ if (data) {
+ var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
+ var imageHeight = this.m_pixelUnpackImageHeight > 0 ? this.m_pixelUnpackImageHeight : height;
+ var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
+ var slicePitch = imageHeight * rowPitch;
+ var skip = this.m_pixelUnpackSkipImages * slicePitch + this.m_pixelUnpackSkipRows * rowPitch +
+ this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
+ src = new tcuTexture.ConstPixelBufferAccess({
+ format: transferFmt,
+ width: width,
+ height: height,
+ depth: depth,
+ rowPitch: rowPitch,
+ slicePitch: slicePitch,
+ data: data,
+ offset: offset + skip});
+
+ dst = texture2DArray.getLevel(level);
+
+ if (isDstFloatDepthFormat)
+ sglrReferenceContext.depthValueFloatClampCopy(dst, src);
+ else
+ tcuTextureUtil.copy(dst, src);
+ } else {
+ // No data supplied, clear to black.
+ dst = texture2DArray.getLevel(level);
+ dst.clear([0.0, 0.0, 0.0, 1.0]);
+ }
+ } else if (target == gl.TEXTURE_3D) {
+ // Validate size and level.
+ if (this.conditionalSetError(width > this.m_limits.maxTexture3DSize ||
+ height > this.m_limits.maxTexture3DSize ||
+ depth > this.m_limits.maxTexture3DSize, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture3DSize)), gl.INVALID_VALUE))
+ return;
+
+ var texture3D = /** @type {sglrReferenceContext.Texture3D} */ (unit.tex3DBinding.texture);
+
+ if (texture3D.isImmutable()) {
+ if (this.conditionalSetError(!texture3D.hasLevel(level), gl.INVALID_OPERATION))
+ return;
+
+ dst = texture3D.getLevel(level);
+ if (this.conditionalSetError(!storageFmt.isEqual(dst.getFormat()) ||
+ width != dst.getWidth() ||
+ height != dst.getHeight() ||
+ depth != dst.getDepth(), gl.INVALID_OPERATION))
+ return;
+ } else
+ texture3D.allocLevel(level, storageFmt, width, height, depth);
+
+ if (data) {
+ var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
+ var imageHeight = this.m_pixelUnpackImageHeight > 0 ? this.m_pixelUnpackImageHeight : height;
+ var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
+ var slicePitch = imageHeight * rowPitch;
+ var skip = this.m_pixelUnpackSkipImages * slicePitch + this.m_pixelUnpackSkipRows * rowPitch +
+ this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
+ src = new tcuTexture.ConstPixelBufferAccess({
+ format: transferFmt,
+ width: width,
+ height: height,
+ depth: depth,
+ rowPitch: rowPitch,
+ slicePitch: slicePitch,
+ data: data,
+ offset: offset + skip});
+
+ dst = texture3D.getLevel(level);
+
+ if (isDstFloatDepthFormat)
+ sglrReferenceContext.depthValueFloatClampCopy(dst, src);
+ else
+ tcuTextureUtil.copy(dst, src);
+
+ } else {
+ // No data supplied, clear to black.
+ dst = texture3D.getLevel(level);
+ dst.clear([0.0, 0.0, 0.0, 1.0]);
+ }
+ }
+ // else if (target == gl.TEXTURE_CUBE_MAP_ARRAY)
+ // {
+ // // Validate size and level.
+ // RC_IF_ERROR(width != height ||
+ // width > m_limits.maxTexture2DSize ||
+ // depth % 6 != 0 ||
+ // depth > m_limits.maxTexture2DArrayLayers, gl.INVALID_VALUE, RC_RET_VOID);
+ // RC_IF_ERROR(level > deLog2Floor32(m_limits.maxTexture2DSize), gl.INVALID_VALUE, RC_RET_VOID);
+
+ // TextureCubeArray* texture = unit.texCubeArrayBinding ? unit.texCubeArrayBinding : &unit.defaultCubeArrayTex;
+
+ // if (texture->isImmutable())
+ // {
+ // RC_IF_ERROR(!texture->hasLevel(level), gl.INVALID_OPERATION, RC_RET_VOID);
+
+ // ConstPixelBufferAccess dst(texture->getLevel(level));
+ // RC_IF_ERROR(storageFmt != dst.getFormat() ||
+ // width != dst.getWidth() ||
+ // height != dst.getHeight() ||
+ // depth != dst.getDepth(), gl.INVALID_OPERATION, RC_RET_VOID);
+ // }
+ // else
+ // texture->allocLevel(level, storageFmt, width, height, depth);
+
+ // if (unpackPtr)
+ // {
+ // ConstPixelBufferAccess src = getUnpack3DAccess(transferFmt, width, height, depth, unpackPtr);
+ // PixelBufferAccess dst (texture->getLevel(level));
+
+ // if (isDstFloatDepthFormat)
+ // sglrReferenceContext.depthValueFloatClampCopy(dst, src);
+ // else
+ // tcu::copy(dst, src);
+ // }
+ // else
+ // {
+ // // No data supplied, clear to black.
+ // PixelBufferAccess dst = texture->getLevel(level);
+ // tcu::clear(dst, Vec4(0.0f, 0.0f, 0.0f, 1.0f));
+ // }
+ // } /**/
+ else
+ this.setError(gl.INVALID_ENUM);
+ };
+
+ sglrReferenceContext.ReferenceContext.prototype.texSubImage2D = function(target, level, xoffset, yoffset, width, height, format, type, pixels) {
+ this.texSubImage3D(target, level, xoffset, yoffset, 0, width, height, 1, format, type, pixels);
+ };
+
+ sglrReferenceContext.ReferenceContext.prototype.texSubImage3D = function(target, level, xoffset, yoffset, zoffset, width, height, depth, format, type, pixels) {
+ /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture];
+ /** @type {ArrayBuffer} */ var data = null;
+ /** @type {number} */ var offset = 0;
+ /** @type {tcuTexture.PixelBufferAccess} */ var dst;
+ /** @type {tcuTexture.PixelBufferAccess} */ var sub;
+ /** @type {tcuTexture.ConstPixelBufferAccess} */ var src;
+ /** @type {boolean} */ var isDstFloatDepthFormat;
+ if (this.m_pixelUnpackBufferBinding) {
+ if (this.conditionalSetError(typeof pixels !== 'number', gl.INVALID_VALUE))
+ return;
+ data = this.m_pixelUnpackBufferBinding.getData();
+ offset = pixels;
+ } else if (pixels) {
+ if (pixels instanceof ArrayBuffer) {
+ data = pixels;
+ offset = 0;
+ } else {
+ data = pixels.buffer;
+ offset = pixels.byteOffset;
+ }
+ }
+
+ if (this.conditionalSetError(xoffset < 0 || yoffset < 0 || zoffset < 0, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(width < 0 || height < 0 || depth < 0 || level < 0, gl.INVALID_VALUE))
+ return;
+
+ // Map transfer format.
+ /** @type {tcuTexture.TextureFormat} */ var transferFmt = gluTextureUtil.mapGLTransferFormat(format, type);
+ if (this.conditionalSetError(!transferFmt, gl.INVALID_ENUM))
+ return;
+
+ if (target == gl.TEXTURE_2D) {
+ // Validate size and level.
+ if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || height > this.m_limits.maxTexture2DSize || depth != 1, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(level > Math.log2(this.m_limits.maxTexture2DSize), gl.INVALID_VALUE))
+ return;
+
+ /** @type {sglrReferenceContext.Texture2D} */
+ var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture);
+
+ if (this.conditionalSetError(!texture.hasLevel(level), gl.INVALID_OPERATION))
+ return;
+
+ //NOTE: replaces this: var dst = tcuTexture.PixelBufferAccess.newFromTextureLevel(texture.getLevel(level));
+ dst = texture.getLevel(level);
+
+ if (this.conditionalSetError(xoffset + width > dst.getWidth() ||
+ yoffset + height > dst.getHeight() ||
+ zoffset + depth > dst.getDepth(),
+ gl.INVALID_VALUE))
+ return;
+
+ var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
+ var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
+ var skip = this.m_pixelUnpackSkipRows * rowPitch + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
+ src = new tcuTexture.ConstPixelBufferAccess({
+ format: transferFmt,
+ width: width,
+ height: height,
+ rowPitch: rowPitch,
+ data: data,
+ offset: offset + skip});
+
+ sub = tcuTextureUtil.getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth);
+ isDstFloatDepthFormat = (dst.getFormat().order == tcuTexture.ChannelOrder.D || dst.getFormat().order == tcuTexture.ChannelOrder.DS); // depth components are limited to [0,1] range
+
+ if (isDstFloatDepthFormat)
+ sglrReferenceContext.depthValueFloatClampCopy(sub, src);
+ else
+ tcuTextureUtil.copy(sub, src);
+ } else if (target == gl.TEXTURE_CUBE_MAP_NEGATIVE_X ||
+ target == gl.TEXTURE_CUBE_MAP_POSITIVE_X ||
+ target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Y ||
+ target == gl.TEXTURE_CUBE_MAP_POSITIVE_Y ||
+ target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ||
+ target == gl.TEXTURE_CUBE_MAP_POSITIVE_Z) {
+ var textureCube = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture);
+
+ var face = sglrReferenceContext.mapGLCubeFace(target);
+
+ if (this.conditionalSetError(!textureCube.hasFace(level, face), gl.INVALID_OPERATION))
+ return;
+
+ dst = textureCube.getFace(level, face);
+
+ if (this.conditionalSetError(xoffset + width > dst.getWidth() ||
+ yoffset + height > dst.getHeight() ||
+ zoffset + depth > dst.getDepth(),
+ gl.INVALID_VALUE))
+ return;
+
+ var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
+ var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
+ var skip = this.m_pixelUnpackSkipRows * rowPitch + this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
+ src = new tcuTexture.ConstPixelBufferAccess({
+ format: transferFmt,
+ width: width,
+ height: height,
+ rowPitch: rowPitch,
+ slicePitach: slicePitch,
+ data: data,
+ offset: offset + skip});
+
+ sub = tcuTextureUtil.getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth);
+ isDstFloatDepthFormat = (dst.getFormat().order == tcuTexture.ChannelOrder.D || dst.getFormat().order == tcuTexture.ChannelOrder.DS); // depth components are limited to [0,1] range
+
+ if (isDstFloatDepthFormat)
+ sglrReferenceContext.depthValueFloatClampCopy(sub, src);
+ else
+ tcuTextureUtil.copy(sub, src);
+ } else if (target == gl.TEXTURE_2D_ARRAY) {
+ // Validate size and level.
+ if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize ||
+ height > this.m_limits.maxTexture2DSize ||
+ depth > this.m_limits.maxTexture2DArrayLayers, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture2DSize)), gl.INVALID_VALUE))
+ return;
+
+ /** @type {sglrReferenceContext.Texture2DArray} */
+ var texture2DArray = /** @type {sglrReferenceContext.Texture2DArray} */ (unit.tex2DArrayBinding.texture);
+
+ if (this.conditionalSetError(!texture2DArray.hasLevel(level), gl.INVALID_OPERATION))
+ return;
+
+ dst = texture2DArray.getLevel(level);
+ if (this.conditionalSetError(xoffset + width > dst.getWidth() ||
+ yoffset + height > dst.getHeight() ||
+ zoffset + depth > dst.getDepth(),
+ gl.INVALID_VALUE))
+ return;
+
+ var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
+ var imageHeight = this.m_pixelUnpackImageHeight > 0 ? this.m_pixelUnpackImageHeight : height;
+ var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
+ var slicePitch = imageHeight * rowPitch;
+ var skip = this.m_pixelUnpackSkipImages * slicePitch + this.m_pixelUnpackSkipRows * rowPitch +
+ this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
+ src = new tcuTexture.ConstPixelBufferAccess({
+ format: transferFmt,
+ width: width,
+ height: height,
+ depth: depth,
+ rowPitch: rowPitch,
+ slicePitch: slicePitch,
+ data: data,
+ offset: offset + skip});
+
+ sub = tcuTextureUtil.getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth);
+ isDstFloatDepthFormat = (dst.getFormat().order == tcuTexture.ChannelOrder.D || dst.getFormat().order == tcuTexture.ChannelOrder.DS); // depth components are limited to [0,1] range
+
+ if (isDstFloatDepthFormat)
+ sglrReferenceContext.depthValueFloatClampCopy(sub, src);
+ else
+ tcuTextureUtil.copy(sub, src);
+ } else if (target == gl.TEXTURE_3D) {
+ // Validate size and level.
+ if (this.conditionalSetError(width > this.m_limits.maxTexture3DSize ||
+ height > this.m_limits.maxTexture3DSize ||
+ depth > this.m_limits.maxTexture3DSize, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture3DSize)), gl.INVALID_VALUE))
+ return;
+
+ var texture3D = /** @type {sglrReferenceContext.Texture3D} */ (unit.tex3DBinding.texture);
+
+ if (this.conditionalSetError(!texture3D.hasLevel(level), gl.INVALID_OPERATION))
+ return;
+
+ dst = texture3D.getLevel(level);
+ if (this.conditionalSetError(xoffset + width > dst.getWidth() ||
+ yoffset + height > dst.getHeight() ||
+ zoffset + depth > dst.getDepth(),
+ gl.INVALID_VALUE))
+ return;
+
+ var rowLen = this.m_pixelUnpackRowLength > 0 ? this.m_pixelUnpackRowLength : width;
+ var imageHeight = this.m_pixelUnpackImageHeight > 0 ? this.m_pixelUnpackImageHeight : height;
+ var rowPitch = deMath.deAlign32(rowLen * transferFmt.getPixelSize(), this.m_pixelUnpackAlignment);
+ var slicePitch = imageHeight * rowPitch;
+ var skip = this.m_pixelUnpackSkipImages * slicePitch + this.m_pixelUnpackSkipRows * rowPitch +
+ this.m_pixelUnpackSkipPixels * transferFmt.getPixelSize();
+ src = new tcuTexture.ConstPixelBufferAccess({
+ format: transferFmt,
+ width: width,
+ height: height,
+ depth: depth,
+ rowPitch: rowPitch,
+ slicePitch: slicePitch,
+ data: data,
+ offset: offset + skip});
+
+ sub = tcuTextureUtil.getSubregion(dst, xoffset, yoffset, zoffset, width, height, depth);
+
+ isDstFloatDepthFormat = (dst.getFormat().order == tcuTexture.ChannelOrder.D || dst.getFormat().order == tcuTexture.ChannelOrder.DS); // depth components are limited to [0,1] range
+ if (isDstFloatDepthFormat)
+ sglrReferenceContext.depthValueFloatClampCopy(sub, src);
+ else
+ tcuTextureUtil.copy(sub, src);
+ } else
+ this.setError(gl.INVALID_ENUM);
+ };
+
+ /**
+ * @param {number} target
+ * @param {number} level
+ * @param {number} internalFormat
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width
+ * @param {number} height
+ * @param {number} border
+ */
+ sglrReferenceContext.ReferenceContext.prototype.copyTexImage2D = function(target, level, internalFormat, x, y, width, height, border) {
+ /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture];
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var src = this.getReadColorbuffer();
+
+ if (this.conditionalSetError(border != 0, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(width < 0 || height < 0 || level < 0, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(src.isEmpty(), gl.INVALID_OPERATION))
+ return;
+
+ // Map storage format.
+ /** @type {tcuTexture.TextureFormat} */ var storageFmt = sglrReferenceContext.mapInternalFormat(internalFormat);
+ if (this.conditionalSetError(!storageFmt, gl.INVALID_ENUM))
+ return;
+
+ if (target == gl.TEXTURE_2D) {
+ // Validate size and level.
+ if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || height > this.m_limits.maxTexture2DSize, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTexture2DSize)), gl.INVALID_VALUE))
+ return;
+
+ /** @type {sglrReferenceContext.Texture2D} */
+ var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture);
+
+ if (texture.isImmutable()) {
+ if (this.conditionalSetError(!texture.hasLevel(level), gl.INVALID_OPERATION))
+ return;
+
+ /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getLevel(level);
+ if (this.conditionalSetError(storageFmt != dst.getFormat() || width != dst.getWidth() || height != dst.getHeight(), gl.INVALID_OPERATION))
+ return;
+ } else {
+ texture.allocLevel(level, storageFmt, width, height);
+ }
+
+ // Copy from current framebuffer.
+ /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getLevel(level);
+ for (var yo = 0; yo < height; yo++) {
+ for (var xo = 0; xo < width; xo++) {
+ if (!deMath.deInBounds32(x+xo, 0, src.raw().getHeight()) || !deMath.deInBounds32(y+yo, 0, src.raw().getDepth()))
+ continue; // Undefined pixel.
+
+ dst.setPixel(src.resolveMultisamplePixel(x+xo, y+yo), xo, yo);
+ }
+ }
+ } else if (target == gl.TEXTURE_CUBE_MAP_NEGATIVE_X ||
+ target == gl.TEXTURE_CUBE_MAP_POSITIVE_X ||
+ target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Y ||
+ target == gl.TEXTURE_CUBE_MAP_POSITIVE_Y ||
+ target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ||
+ target == gl.TEXTURE_CUBE_MAP_POSITIVE_Z) {
+ // Validate size and level.
+ if (this.conditionalSetError(width != height || width > this.m_limits.maxTextureCubeSize, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(level > Math.floor(Math.log2(this.m_limits.maxTextureCubeSize)), gl.INVALID_VALUE))
+ return;
+
+ /** @type {sglrReferenceContext.TextureCube} */
+ var texture = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture);
+ var face = sglrReferenceContext.mapGLCubeFace(target);
+
+ if (texture.isImmutable()) {
+ if (this.conditionalSetError(!texture.hasFace(level, face), gl.INVALID_OPERATION))
+ return;
+
+ /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getFace(level, face);
+ if (this.conditionalSetError(storageFmt != dst.getFormat() || width != dst.getWidth() || height != dst.getHeight(), gl.INVALID_OPERATION))
+ return;
+ } else {
+ texture.allocLevel(level, face, storageFmt, width, height);
+ }
+
+ // Copy from current framebuffer.
+ /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getFace(level, face);
+ for (var yo = 0; yo < height; yo++) {
+ for (var xo = 0; xo < width; xo++) {
+ if (!deMath.deInBounds32(x+xo, 0, src.raw().getHeight()) || !deMath.deInBounds32(y+yo, 0, src.raw().getDepth()))
+ continue; // Undefined pixel.
+
+ dst.setPixel(src.resolveMultisamplePixel(x+xo, y+yo), xo, yo);
+ }
+ }
+ } else {
+ this.setError(gl.INVALID_ENUM);
+ }
+ }
+
+ /**
+ * @param {number} target
+ * @param {number} level
+ * @param {number} xoffset
+ * @param {number} yoffset
+ * @param {number} x
+ * @param {number} y
+ * @param {number} width
+ * @param {number} height
+ */
+ sglrReferenceContext.ReferenceContext.prototype.copyTexSubImage2D = function(target, level, xoffset, yoffset, x, y, width, height) {
+ /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture];
+ /** @type {rrMultisamplePixelBufferAccess.MultisamplePixelBufferAccess} */ var src = this.getReadColorbuffer();
+
+ if (this.conditionalSetError(xoffset < 0 || yoffset < 0, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(width < 0 || height < 0 || level < 0, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(src.isEmpty(), gl.INVALID_OPERATION))
+ return;
+
+ if (target == gl.TEXTURE_2D) {
+ /** @type {sglrReferenceContext.Texture2D} */
+ var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture);
+
+ if (this.conditionalSetError(!texture.hasLevel(level), gl.INVALID_VALUE))
+ return;
+
+ /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getLevel(level);
+
+ if (this.conditionalSetError(xoffset + width > dst.getWidth() || yoffset + height > dst.getHeight(), gl.INVALID_VALUE))
+ return;
+
+ for (var yo = 0; yo < height; yo++) {
+ for (var xo = 0; xo < width; xo++) {
+ if (!deMath.deInBounds32(x+xo, 0, src.raw().getHeight()) || !deMath.deInBounds32(y+yo, 0, src.raw().getDepth()))
+ continue;
+
+ dst.setPixel(src.resolveMultisamplePixel(x+xo, y+yo), xo+xoffset, yo+yoffset);
+ }
+ }
+ } else if (target == gl.TEXTURE_CUBE_MAP_NEGATIVE_X ||
+ target == gl.TEXTURE_CUBE_MAP_POSITIVE_X ||
+ target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Y ||
+ target == gl.TEXTURE_CUBE_MAP_POSITIVE_Y ||
+ target == gl.TEXTURE_CUBE_MAP_NEGATIVE_Z ||
+ target == gl.TEXTURE_CUBE_MAP_POSITIVE_Z) {
+ /** @type {sglrReferenceContext.TextureCube} */
+ var texture = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture);
+ var face = sglrReferenceContext.mapGLCubeFace(target);
+
+ if (this.conditionalSetError(!texture.hasFace(level, face), gl.INVALID_VALUE))
+ return;
+
+ /** @type {tcuTexture.PixelBufferAccess} */ var dst = texture.getFace(level, face);
+
+ if (this.conditionalSetError(xoffset + width > dst.getWidth() || yoffset + height > dst.getHeight(), gl.INVALID_VALUE))
+ return;
+
+ for (var yo = 0; yo < height; yo++) {
+ for (var xo = 0; xo < width; xo++) {
+ if (!deMath.deInBounds32(x+xo, 0, src.raw().getHeight()) || !deMath.deInBounds32(y+yo, 0, src.raw().getDepth()))
+ continue;
+
+ dst.setPixel(src.resolveMultisamplePixel(x+xo, y+yo), xo+xoffset, yo+yoffset);
+ }
+ }
+ } else {
+ this.setError(gl.INVALID_ENUM);
+ }
+ }
+
+ sglrReferenceContext.ReferenceContext.prototype.texStorage3D = function(target, levels, internalFormat, width, height, depth) {
+ /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture];
+
+ if (this.conditionalSetError(width <= 0 || height <= 0, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(levels < 1 || levels > Math.floor(Math.log2(Math.max(width, height))) + 1, gl.INVALID_VALUE))
+ return;
+
+ // Map storage format.
+ /** @type {tcuTexture.TextureFormat} */ var storageFmt = sglrReferenceContext.mapInternalFormat(internalFormat);
+ if (this.conditionalSetError(!storageFmt, gl.INVALID_ENUM))
+ return;
+
+ if (target == gl.TEXTURE_2D_ARRAY) {
+ if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize ||
+ height > this.m_limits.maxTexture2DSize ||
+ depth >= this.m_limits.maxTexture2DArrayLayers, gl.INVALID_VALUE))
+ return;
+
+ /** @type {sglrReferenceContext.Texture2DArray} */
+ var textureArray = /** @type {sglrReferenceContext.Texture2DArray} */ (unit.tex2DArrayBinding.texture);
+ if (this.conditionalSetError(textureArray.isImmutable(), gl.INVALID_OPERATION))
+ return;
+
+ textureArray.clearLevels();
+ textureArray.setImmutable();
+
+ for (var level = 0; level < levels; level++) {
+ var levelW = Math.max(1, width >> level);
+ var levelH = Math.max(1, height >> level);
+
+ textureArray.allocLevel(level, storageFmt, levelW, levelH, depth);
+ }
+ } else if (target == gl.TEXTURE_3D) {
+ if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize ||
+ height > this.m_limits.maxTexture2DSize ||
+ depth >= this.m_limits.maxTexture3DSize, gl.INVALID_VALUE))
+ return;
+
+ /** @type {sglrReferenceContext.Texture3D} */
+ var texture3D = /** @type {sglrReferenceContext.Texture3D} */ (unit.tex3DBinding.texture);
+ if (this.conditionalSetError(texture3D.isImmutable(), gl.INVALID_OPERATION))
+ return;
+
+ texture3D.clearLevels();
+ texture3D.setImmutable();
+
+ for (var level = 0; level < levels; level++) {
+ var levelW = Math.max(1, width >> level);
+ var levelH = Math.max(1, height >> level);
+ var levelD = Math.max(1, depth >> level);
+
+ texture3D.allocLevel(level, storageFmt, levelW, levelH, levelD);
+ }
+ } else
+ this.setError(gl.INVALID_ENUM);
+ };
+
+ sglrReferenceContext.ReferenceContext.prototype.texStorage2D = function(target, levels, internalFormat, width, height) {
+ /** @type {sglrReferenceContext.TextureUnit} */var unit = this.m_textureUnits[this.m_activeTexture];
+
+ if (this.conditionalSetError(width <= 0 || height <= 0, gl.INVALID_VALUE))
+ return;
+ if (this.conditionalSetError(levels < 1 || levels > Math.floor(Math.log2(Math.max(width, height))) + 1, gl.INVALID_VALUE))
+ return;
+
+ // Map storage format.
+ /** @type {tcuTexture.TextureFormat} */ var storageFmt = sglrReferenceContext.mapInternalFormat(internalFormat);
+ if (this.conditionalSetError(!storageFmt, gl.INVALID_ENUM))
+ return;
+
+ if (target == gl.TEXTURE_2D) {
+ if (this.conditionalSetError(width > this.m_limits.maxTexture2DSize || height > this.m_limits.maxTexture2DSize, gl.INVALID_VALUE))
+ return;
+
+ /** @type {sglrReferenceContext.Texture2D} */
+ var texture = /** @type {sglrReferenceContext.Texture2D} */ (unit.tex2DBinding.texture);
+ if (this.conditionalSetError(texture.isImmutable(), gl.INVALID_OPERATION))
+ return;
+
+ texture.clearLevels();
+ texture.setImmutable();
+
+ for (var level = 0; level < levels; level++) {
+ var levelW = Math.max(1, width >> level);
+ var levelH = Math.max(1, height >> level);
+
+ texture.allocLevel(level, storageFmt, levelW, levelH);
+ }
+ } else if (target == gl.TEXTURE_CUBE_MAP) {
+ if (this.conditionalSetError(width != height || width > this.m_limits.maxTextureCubeSize, gl.INVALID_VALUE))
+ return;
+ var textureCube = /** @type {sglrReferenceContext.TextureCube} */ (unit.texCubeBinding.texture);
+ if (this.conditionalSetError(textureCube.isImmutable(), gl.INVALID_OPERATION))
+ return;
+
+ textureCube.clearLevels();
+ textureCube.setImmutable();
+
+ for (var level = 0; level < levels; level++) {
+ var levelW = Math.max(1, width >> level);
+ var levelH = Math.max(1, height >> level);
+
+ for (var face in tcuTexture.CubeFace)
+ textureCube.allocLevel(level, tcuTexture.CubeFace[face], storageFmt, levelW, levelH);
+ }
+ } else
+ this.setError(gl.INVALID_ENUM);
+ };
+
+ /**
+ * @param {number} value
+ * @return {?tcuTexture.WrapMode}
+ */
+ sglrReferenceContext.mapGLWrapMode = function(value) {
+ switch (value) {
+ case gl.CLAMP_TO_EDGE: return tcuTexture.WrapMode.CLAMP_TO_EDGE;
+ case gl.REPEAT: return tcuTexture.WrapMode.REPEAT_GL;
+ case gl.MIRRORED_REPEAT: return tcuTexture.WrapMode.MIRRORED_REPEAT_GL;
+ }
+ return null;
+ };
+
+ /**
+ * @param {number} value
+ * @return {?tcuTexture.FilterMode}
+ */
+ sglrReferenceContext.mapGLFilterMode = function(value) {
+ switch (value) {
+ case gl.NEAREST: return tcuTexture.FilterMode.NEAREST;
+ case gl.LINEAR: return tcuTexture.FilterMode.LINEAR;
+ case gl.NEAREST_MIPMAP_NEAREST: return tcuTexture.FilterMode.NEAREST_MIPMAP_NEAREST;
+ case gl.NEAREST_MIPMAP_LINEAR: return tcuTexture.FilterMode.NEAREST_MIPMAP_LINEAR;
+ case gl.LINEAR_MIPMAP_NEAREST: return tcuTexture.FilterMode.LINEAR_MIPMAP_NEAREST;
+ case gl.LINEAR_MIPMAP_LINEAR: return tcuTexture.FilterMode.LINEAR_MIPMAP_LINEAR;
+ }
+ return null;
+ };
+
+ /**
+ * @param {number} target
+ * @param {number} pname
+ * @param {number} value
+ */
+ sglrReferenceContext.ReferenceContext.prototype.texParameteri = function(target, pname, value) {
+ /** @type {sglrReferenceContext.TextureUnit} */ var unit = this.m_textureUnits[this.m_activeTexture];
+ /** @type {sglrReferenceContext.TextureContainer} */ var container = null;
+
+ switch (target) {
+ case gl.TEXTURE_2D: container = unit.tex2DBinding; break;
+ case gl.TEXTURE_CUBE_MAP: container = unit.texCubeBinding; break;
+ case gl.TEXTURE_2D_ARRAY: container = unit.tex2DArrayBinding; break;
+ case gl.TEXTURE_3D: container = unit.tex3DBinding; break;
+
+ default: this.setError(gl.INVALID_ENUM);
+ }
+
+ if (!container)
+ return;
+
+ /** @type {sglrReferenceContext.Texture} */
+ var texture = container.texture;
+
+ switch (pname) {
+ case gl.TEXTURE_WRAP_S: {
+ /** @type {?tcuTexture.WrapMode} */ var wrapS = sglrReferenceContext.mapGLWrapMode(value);
+ if (this.conditionalSetError(null == wrapS, gl.INVALID_VALUE))
+ return;
+ texture.getSampler().wrapS = /** @type {tcuTexture.WrapMode} */ (wrapS);
+ break;
+ }
+
+ case gl.TEXTURE_WRAP_T: {
+ /** @type {?tcuTexture.WrapMode} */ var wrapT = sglrReferenceContext.mapGLWrapMode(value);
+ if (this.conditionalSetError(null == wrapT, gl.INVALID_VALUE))
+ return;
+ texture.getSampler().wrapT = /** @type {tcuTexture.WrapMode} */ (wrapT);
+ break;
+ }
+
+ case gl.TEXTURE_WRAP_R: {
+ /** @type {?tcuTexture.WrapMode} */ var wrapR = sglrReferenceContext.mapGLWrapMode(value);
+ if (this.conditionalSetError(null == wrapR, gl.INVALID_VALUE))
+ return;
+ texture.getSampler().wrapR = /** @type {tcuTexture.WrapMode} */ (wrapR);
+ break;
+ }
+
+ case gl.TEXTURE_MIN_FILTER: {
+ /** @type {?tcuTexture.FilterMode} */ var minMode = sglrReferenceContext.mapGLFilterMode(value);
+ if (this.conditionalSetError(null == minMode, gl.INVALID_VALUE))
+ return;
+ texture.getSampler().minFilter = /** @type {tcuTexture.FilterMode} */ (minMode);
+ break;
+ }
+
+ case gl.TEXTURE_MAG_FILTER: {
+ /** @type {?tcuTexture.FilterMode} */ var magMode = sglrReferenceContext.mapGLFilterMode(value);
+ if (this.conditionalSetError(null == magMode, gl.INVALID_VALUE))
+ return;
+ texture.getSampler().magFilter = /** @type {tcuTexture.FilterMode} */ (magMode);
+ break;
+ }
+
+ case gl.TEXTURE_MAX_LEVEL: {
+ if (this.conditionalSetError(value < 0, gl.INVALID_VALUE))
+ return;
+ texture.setMaxLevel(value);
+ break;
+ }
+
+ default:
+ this.setError(gl.INVALID_ENUM);
+ return;
+ }
+ };
+
+ sglrReferenceContext.ReferenceContext.prototype.invalidateFramebuffer = function(target, attachments) {};
+ sglrReferenceContext.ReferenceContext.prototype.invalidateSubFramebuffer = function(target, attachments, x, y, width, height) {};
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContextTest.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContextTest.js
new file mode 100644
index 0000000000..cc8abf5969
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceContextTest.js
@@ -0,0 +1,834 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+'use strict';
+goog.provide('framework.opengl.simplereference.sglrReferenceContextTest');
+goog.require('framework.common.tcuLogImage');
+goog.require('framework.common.tcuPixelFormat');
+goog.require('framework.common.tcuRGBA');
+goog.require('framework.common.tcuSurface');
+goog.require('framework.common.tcuTestCase');
+goog.require('framework.opengl.gluDrawUtil');
+goog.require('framework.opengl.simplereference.sglrReferenceContext');
+goog.require('framework.opengl.simplereference.sglrShaderProgram');
+goog.require('framework.referencerenderer.rrFragmentOperations');
+goog.require('framework.referencerenderer.rrGenericVector');
+goog.require('framework.referencerenderer.rrShadingContext');
+goog.require('framework.referencerenderer.rrVertexAttrib');
+goog.require('framework.referencerenderer.rrVertexPacket');
+
+goog.scope(function() {
+ var sglrReferenceContextTest = framework.opengl.simplereference.sglrReferenceContextTest;
+ var sglrReferenceContext = framework.opengl.simplereference.sglrReferenceContext;
+ var tcuTestCase = framework.common.tcuTestCase;
+ var tcuPixelFormat = framework.common.tcuPixelFormat;
+ var gluDrawUtil = framework.opengl.gluDrawUtil;
+ var tcuSurface = framework.common.tcuSurface;
+ var tcuLogImage = framework.common.tcuLogImage;
+ var sglrShaderProgram = framework.opengl.simplereference.sglrShaderProgram;
+ var rrGenericVector = framework.referencerenderer.rrGenericVector;
+ var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib;
+ var rrShadingContext = framework.referencerenderer.rrShadingContext;
+ var rrVertexPacket = framework.referencerenderer.rrVertexPacket;
+ var rrFragmentOperations = framework.referencerenderer.rrFragmentOperations;
+ var tcuRGBA = framework.common.tcuRGBA;
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ */
+ sglrReferenceContextTest.ClearContext = function(name, description) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ };
+
+ sglrReferenceContextTest.ClearContext.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ sglrReferenceContextTest.ClearContext.prototype.constructor = sglrReferenceContextTest.ClearContext;
+
+ sglrReferenceContextTest.ClearContext.prototype.init = function() {};
+
+ sglrReferenceContextTest.ClearContext.prototype.iterate = function() {
+
+ var width = 200;
+ var height = 188;
+ var samples = 1;
+ var limits = new sglrReferenceContext.ReferenceContextLimits(gl);
+ var format = new tcuPixelFormat.PixelFormat(8, 8, 8, 8);
+ var buffers = new sglrReferenceContext.ReferenceContextBuffers(format, 24, 8, width, height, samples);
+ var ctx = new sglrReferenceContext.ReferenceContext(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
+ ctx.clearColor(1, 0, 0, 1);
+ ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+ var pixels = new tcuSurface.Surface(width, height);
+ ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr());
+
+ var numFailedPixels = 0;
+ var redPixel = new gluDrawUtil.Pixel([255, 0, 0, 255]);
+ for (var x = 0; x < width; x++)
+ for (var y = 0; y < height; y++) {
+ var pixel = new gluDrawUtil.Pixel(pixels.getPixel(x, y));
+ if (!pixel.equals(redPixel))
+ numFailedPixels += 1;
+ }
+
+ var access = pixels.getAccess();
+
+ tcuLogImage.logImage('Result', '', access);
+
+ if (numFailedPixels > 0)
+ testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false);
+ else
+ testPassedOptions('Image comparison succeed', true);
+
+ ctx.scissor(width / 4, height / 4, width / 2, height / 2);
+ ctx.enable(gl.SCISSOR_TEST);
+ ctx.clearColor(0, 1, 1, 1);
+ ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+ ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr());
+
+ numFailedPixels = 0;
+ var greenBluePixel = new gluDrawUtil.Pixel([0, 255, 255, 255]);
+ for (var x = 0; x < width; x++)
+ for (var y = 0; y < height; y++) {
+ var pixel = new gluDrawUtil.Pixel(pixels.getPixel(x, y));
+ if ((x >= width / 4 && x < width - width / 4) && (y >= height / 4 && y < height - height / 4)) {
+ if (!pixel.equals(greenBluePixel))
+ numFailedPixels += 1;
+ } else
+ if (!pixel.equals(redPixel))
+ numFailedPixels += 1;
+ }
+
+ access = pixels.getAccess();
+
+ tcuLogImage.logImage('Result', '', access);
+
+ if (numFailedPixels > 0)
+ testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false);
+ else
+ testPassedOptions('Image comparison succeed', true);
+
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ */
+ sglrReferenceContextTest.Framebuffer = function(name, description) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ };
+
+ sglrReferenceContextTest.Framebuffer.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ sglrReferenceContextTest.Framebuffer.prototype.constructor = sglrReferenceContextTest.Framebuffer;
+
+ sglrReferenceContextTest.Framebuffer.prototype.init = function() {};
+
+ sglrReferenceContextTest.Framebuffer.prototype.iterate = function() {
+ var limits = new sglrReferenceContext.ReferenceContextLimits(gl);
+ var format = new tcuPixelFormat.PixelFormat(8, 8, 8, 8);
+ var width = 200;
+ var height = 188;
+ var samples = 1;
+ var buffers = new sglrReferenceContext.ReferenceContextBuffers(format, 24, 8, width, height, samples);
+ var ctx = new sglrReferenceContext.ReferenceContext(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
+ ctx.clearColor(0, 0, 1, 1);
+ ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+ var fbo = ctx.createFramebuffer();
+ var rbo = ctx.createRenderbuffer();
+ ctx.bindFramebuffer(gl.FRAMEBUFFER, fbo);
+ ctx.bindRenderbuffer(gl.RENDERBUFFER, rbo);
+ ctx.renderbufferStorage(gl.RENDERBUFFER, gl.RGBA8, width, height);
+ ctx.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
+ bufferedLogToConsole('Framebuffer status: ' + (ctx.checkFramebufferStatus(gl.FRAMEBUFFER) == gl.FRAMEBUFFER_COMPLETE));
+ ctx.clearColor(1, 0, 0, 1);
+ ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+ var pixels = new tcuSurface.Surface(width, height);
+ ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr());
+ var numFailedPixels = 0;
+ var redPixel = new gluDrawUtil.Pixel([255, 0, 0, 255]);
+ for (var x = 0; x < width; x++)
+ for (var y = 0; y < height; y++) {
+ var pixel = new gluDrawUtil.Pixel(pixels.getPixel(x, y));
+ if (!pixel.equals(redPixel))
+ numFailedPixels += 1;
+ }
+ var access = pixels.getAccess();
+ tcuLogImage.logImage('Result', '', access);
+
+ if (numFailedPixels > 0)
+ testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false);
+ else
+ testPassedOptions('Image comparison succeed', true);
+
+ ctx.scissor(width / 4, height / 4, width / 2, height / 2);
+ ctx.enable(gl.SCISSOR_TEST);
+ ctx.clearColor(0, 1, 1, 1);
+ ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+ ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr());
+
+ numFailedPixels = 0;
+ var greenBluePixel = new gluDrawUtil.Pixel([0, 255, 255, 255]);
+ for (var x = 0; x < width; x++)
+ for (var y = 0; y < height; y++) {
+ var pixel = new gluDrawUtil.Pixel(pixels.getPixel(x, y));
+ if ((x >= width / 4 && x < width - width / 4) && (y >= height / 4 && y < height - height / 4)) {
+ if (!pixel.equals(greenBluePixel))
+ numFailedPixels += 1;
+ } else
+ if (!pixel.equals(redPixel))
+ numFailedPixels += 1;
+ }
+
+ access = pixels.getAccess();
+
+ tcuLogImage.logImage('Result', '', access);
+
+ if (numFailedPixels > 0)
+ testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false);
+ else
+ testPassedOptions('Image comparison succeed', true);
+
+ ctx.bindFramebuffer(gl.FRAMEBUFFER, null);
+ ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr());
+
+ var bluePixel = new gluDrawUtil.Pixel([0, 0, 255, 255]);
+ for (var x = 0; x < width; x++)
+ for (var y = 0; y < height; y++) {
+ var pixel = new gluDrawUtil.Pixel(pixels.getPixel(x, y));
+ if (!pixel.equals(bluePixel))
+ numFailedPixels += 1;
+ }
+ access = pixels.getAccess();
+ tcuLogImage.logImage('Result', '', access);
+
+ if (numFailedPixels > 0)
+ testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false);
+ else
+ testPassedOptions('Image comparison succeed', true);
+
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ */
+ sglrReferenceContextTest.Shader = function(name, description) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ };
+
+ sglrReferenceContextTest.Shader.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ sglrReferenceContextTest.Shader.prototype.constructor = sglrReferenceContextTest.Shader;
+
+ sglrReferenceContextTest.Shader.prototype.init = function() {};
+
+ sglrReferenceContextTest.Shader.prototype.iterate = function() {
+ var limits = new sglrReferenceContext.ReferenceContextLimits(gl);
+ var format = new tcuPixelFormat.PixelFormat(8, 8, 8, 8);
+ var width = 200;
+ var height = 188;
+ var samples = 1;
+ var buffers = new sglrReferenceContext.ReferenceContextBuffers(format, 24, 8, width, height, samples);
+ var ctx = new sglrReferenceContext.ReferenceContext(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
+ ctx.clearColor(0, 0, 1, 1);
+ ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+
+ var vertices = [
+ -0.5, 0.5,
+ 0.5, 0.5,
+ -0.5, -0.5,
+ 0.5, 0.5,
+ 0.5, -0.5,
+ -0.5, -0.5
+ ];
+
+ var vertices32 = new Float32Array(vertices);
+
+ var squareVerticesBuffer = ctx.createBuffer();
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
+ ctx.bufferData(gl.ARRAY_BUFFER, vertices32, gl.STATIC_DRAW);
+
+ var colors = [
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1
+ ];
+
+ var colors32 = new Float32Array(colors);
+
+ var squareColorsBuffer = ctx.createBuffer();
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer);
+ ctx.bufferData(gl.ARRAY_BUFFER, colors32, gl.STATIC_DRAW);
+
+ /** @type {sglrShaderProgram.ShaderProgramDeclaration} */ var progDecl = new sglrShaderProgram.ShaderProgramDeclaration();
+
+ progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexPosition', rrGenericVector.GenericVecType.FLOAT));
+
+ progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexColor', rrGenericVector.GenericVecType.FLOAT));
+
+ progDecl.pushVertexSource(new sglrShaderProgram.VertexSource(''));
+
+ progDecl.pushFragmentOutput(new sglrShaderProgram.FragmentOutput(rrGenericVector.GenericVecType.FLOAT));
+
+ progDecl.pushFragmentSource(new sglrShaderProgram.FragmentSource(''));
+
+ /** @type {sglrReferenceContextTest.ContextShaderProgram} */ var program = new sglrReferenceContextTest.ContextShaderProgram(progDecl);
+
+ //Create program
+ ctx.createProgram(program);
+
+ //Use program
+ ctx.useProgram(program);
+
+ var vertexPositionAttribute = ctx.getAttribLocation(program, 'aVertexPosition');
+ var vertexColorAttribute = ctx.getAttribLocation(program, 'aVertexColor');
+ ctx.enableVertexAttribArray(vertexPositionAttribute);
+ ctx.enableVertexAttribArray(vertexColorAttribute);
+
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
+ ctx.vertexAttribPointer(vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer);
+ ctx.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
+
+ ctx.drawQuads(gl.TRIANGLES, 0, 6);
+
+ var pixels = new tcuSurface.Surface(width, height);
+ ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr());
+
+ var numFailedPixels = 0;
+
+ var redPixel = new gluDrawUtil.Pixel([255, 0, 0, 255]);
+ var bluePixel = new gluDrawUtil.Pixel([0, 0, 255, 255]);
+
+ var pixel = new gluDrawUtil.Pixel(pixels.getPixel(0, 0));
+ if (!pixel.equals(bluePixel))
+ numFailedPixels += 1;
+
+ pixel = new gluDrawUtil.Pixel(pixels.getPixel(100, 94));
+ if (!pixel.equals(redPixel))
+ numFailedPixels += 1;
+
+ var access = pixels.getAccess();
+
+ tcuLogImage.logImage('Result', '', access);
+
+ if (numFailedPixels > 0)
+ testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false);
+ else
+ testPassedOptions('Image comparison succeed', true);
+
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ */
+ sglrReferenceContextTest.TriangleStrip = function(name, description) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ };
+
+ sglrReferenceContextTest.TriangleStrip.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ sglrReferenceContextTest.TriangleStrip.prototype.constructor = sglrReferenceContextTest.TriangleStrip;
+
+ sglrReferenceContextTest.TriangleStrip.prototype.init = function() {};
+
+ sglrReferenceContextTest.TriangleStrip.prototype.iterate = function() {
+ var limits = new sglrReferenceContext.ReferenceContextLimits(gl);
+ var format = new tcuPixelFormat.PixelFormat(8, 8, 8, 8);
+ var width = 200;
+ var height = 188;
+ var samples = 1;
+ var buffers = new sglrReferenceContext.ReferenceContextBuffers(format, 24, 8, width, height, samples);
+ var ctx = new sglrReferenceContext.ReferenceContext(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
+ ctx.clearColor(0, 0, 1, 1);
+ ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+
+ var vertices = [
+ -0.5, 0.5,
+ 0.5, 0.5,
+ -0.5, 0,
+ 0.5, 0,
+ -0.5, -0.5,
+ 0.5, -0.5
+ ];
+
+ var vertices32 = new Float32Array(vertices);
+
+ var squareVerticesBuffer = ctx.createBuffer();
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
+ ctx.bufferData(gl.ARRAY_BUFFER, vertices32, gl.STATIC_DRAW);
+
+ var colors = [
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1
+ ];
+
+ var colors32 = new Float32Array(colors);
+
+ var squareColorsBuffer = ctx.createBuffer();
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer);
+ ctx.bufferData(gl.ARRAY_BUFFER, colors32, gl.STATIC_DRAW);
+
+ /** @type {sglrShaderProgram.ShaderProgramDeclaration} */ var progDecl = new sglrShaderProgram.ShaderProgramDeclaration();
+
+ progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexPosition', rrGenericVector.GenericVecType.FLOAT));
+
+ progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexColor', rrGenericVector.GenericVecType.FLOAT));
+
+ progDecl.pushVertexSource(new sglrShaderProgram.VertexSource(''));
+
+ progDecl.pushFragmentOutput(new sglrShaderProgram.FragmentOutput(rrGenericVector.GenericVecType.FLOAT));
+
+ progDecl.pushFragmentSource(new sglrShaderProgram.FragmentSource(''));
+
+ /** @type {sglrReferenceContextTest.ContextShaderProgram} */ var program = new sglrReferenceContextTest.ContextShaderProgram(progDecl);
+
+ //Create program
+ ctx.createProgram(program);
+
+ //Use program
+ ctx.useProgram(program);
+
+ var vertexPositionAttribute = ctx.getAttribLocation(program, 'aVertexPosition');
+ var vertexColorAttribute = ctx.getAttribLocation(program, 'aVertexColor');
+ ctx.enableVertexAttribArray(vertexPositionAttribute);
+ ctx.enableVertexAttribArray(vertexColorAttribute);
+
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
+ ctx.vertexAttribPointer(vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer);
+ ctx.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
+
+ ctx.drawQuads(gl.TRIANGLE_STRIP, 0, 6);
+
+ var pixels = new tcuSurface.Surface(width, height);
+ ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr());
+
+ var numFailedPixels = 0;
+
+ var redPixel = new gluDrawUtil.Pixel([255, 0, 0, 255]);
+ var bluePixel = new gluDrawUtil.Pixel([0, 0, 255, 255]);
+
+ var pixel = new gluDrawUtil.Pixel(pixels.getPixel(0, 0));
+ if (!pixel.equals(bluePixel))
+ numFailedPixels += 1;
+
+ pixel = new gluDrawUtil.Pixel(pixels.getPixel(100, 94));
+ if (!pixel.equals(redPixel))
+ numFailedPixels += 1;
+
+ var access = pixels.getAccess();
+
+ tcuLogImage.logImage('Result', '', access);
+
+ if (numFailedPixels > 0)
+ testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false);
+ else
+ testPassedOptions('Image comparison succeed', true);
+
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ */
+ sglrReferenceContextTest.TriangleFan = function(name, description) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ };
+
+ sglrReferenceContextTest.TriangleFan.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ sglrReferenceContextTest.TriangleFan.prototype.constructor = sglrReferenceContextTest.TriangleFan;
+
+ sglrReferenceContextTest.TriangleFan.prototype.init = function() {};
+
+ sglrReferenceContextTest.TriangleFan.prototype.iterate = function() {
+ var limits = new sglrReferenceContext.ReferenceContextLimits(gl);
+ var format = new tcuPixelFormat.PixelFormat(8, 8, 8, 8);
+ var width = 200;
+ var height = 188;
+ var samples = 1;
+ var buffers = new sglrReferenceContext.ReferenceContextBuffers(format, 24, 8, width, height, samples);
+ var ctx = new sglrReferenceContext.ReferenceContext(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
+ ctx.clearColor(0, 0, 1, 1);
+ ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+
+ var vertices = [
+ -0.5, 0,
+ -0.5, 0.5,
+ 0.5, 0.5,
+ 0.5, 0,
+ 0.5, -0.5,
+ -0.5, -0.5
+ ];
+
+ var vertices32 = new Float32Array(vertices);
+
+ var squareVerticesBuffer = ctx.createBuffer();
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
+ ctx.bufferData(gl.ARRAY_BUFFER, vertices32, gl.STATIC_DRAW);
+
+ var colors = [
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1,
+ 1, 0, 0, 1
+ ];
+
+ var colors32 = new Float32Array(colors);
+
+ var squareColorsBuffer = ctx.createBuffer();
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer);
+ ctx.bufferData(gl.ARRAY_BUFFER, colors32, gl.STATIC_DRAW);
+
+ /** @type {sglrShaderProgram.ShaderProgramDeclaration} */ var progDecl = new sglrShaderProgram.ShaderProgramDeclaration();
+
+ progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexPosition', rrGenericVector.GenericVecType.FLOAT));
+
+ progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexColor', rrGenericVector.GenericVecType.FLOAT));
+
+ progDecl.pushVertexSource(new sglrShaderProgram.VertexSource(''));
+
+ progDecl.pushFragmentOutput(new sglrShaderProgram.FragmentOutput(rrGenericVector.GenericVecType.FLOAT));
+
+ progDecl.pushFragmentSource(new sglrShaderProgram.FragmentSource(''));
+
+ /** @type {sglrReferenceContextTest.ContextShaderProgram} */ var program = new sglrReferenceContextTest.ContextShaderProgram(progDecl);
+
+ //Create program
+ ctx.createProgram(program);
+
+ //Use program
+ ctx.useProgram(program);
+
+ var vertexPositionAttribute = ctx.getAttribLocation(program, 'aVertexPosition');
+ var vertexColorAttribute = ctx.getAttribLocation(program, 'aVertexColor');
+ ctx.enableVertexAttribArray(vertexPositionAttribute);
+ ctx.enableVertexAttribArray(vertexColorAttribute);
+
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
+ ctx.vertexAttribPointer(vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer);
+ ctx.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
+
+ ctx.drawQuads(gl.TRIANGLE_FAN, 0, 6);
+
+ var pixels = new tcuSurface.Surface(width, height);
+ ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr());
+
+ var numFailedPixels = 0;
+
+ var redPixel = new gluDrawUtil.Pixel([255, 0, 0, 255]);
+ var bluePixel = new gluDrawUtil.Pixel([0, 0, 255, 255]);
+
+ var pixel = new gluDrawUtil.Pixel(pixels.getPixel(0, 0));
+ if (!pixel.equals(bluePixel))
+ numFailedPixels += 1;
+
+ pixel = new gluDrawUtil.Pixel(pixels.getPixel(100, 94));
+ if (!pixel.equals(redPixel))
+ numFailedPixels += 1;
+
+ var access = pixels.getAccess();
+
+ tcuLogImage.logImage('Result', '', access);
+
+ if (numFailedPixels > 0)
+ testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false);
+ else
+ testPassedOptions('Image comparison succeed', true);
+
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {tcuTestCase.DeqpTest}
+ * @param {string} name
+ * @param {string} description
+ */
+ sglrReferenceContextTest.DrawElements = function(name, description) {
+ tcuTestCase.DeqpTest.call(this, name, description);
+ };
+
+ sglrReferenceContextTest.DrawElements.prototype = Object.create(tcuTestCase.DeqpTest.prototype);
+ sglrReferenceContextTest.DrawElements.prototype.constructor = sglrReferenceContextTest.DrawElements;
+
+ sglrReferenceContextTest.DrawElements.prototype.init = function() {};
+
+ sglrReferenceContextTest.DrawElements.prototype.iterate = function() {
+ var limits = new sglrReferenceContext.ReferenceContextLimits(gl);
+ var format = new tcuPixelFormat.PixelFormat(8, 8, 8, 8);
+ var width = 200;
+ var height = 188;
+ var samples = 1;
+ var buffers = new sglrReferenceContext.ReferenceContextBuffers(format, 24, 8, width, height, samples);
+ var ctx = new sglrReferenceContext.ReferenceContext(limits, buffers.getColorbuffer(), buffers.getDepthbuffer(), buffers.getStencilbuffer());
+ ctx.clearColor(0, 0, 1, 1);
+ ctx.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT | gl.STENCIL_BUFFER_BIT);
+
+ var vertices = [
+ -0.5, 0.5,
+ 0, 0.5,
+ 0.4, 0.5,
+
+ -0.5, 0.1,
+ 0, 0.1,
+ 0.4, 0.1,
+
+ -0.5, -0.7,
+ 0, -0.7,
+ 0.4, -0.7
+ ];
+
+ var vertices32 = new Float32Array(vertices);
+
+ var squareVerticesBuffer = ctx.createBuffer();
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
+ ctx.bufferData(gl.ARRAY_BUFFER, vertices32, gl.STATIC_DRAW);
+
+ var indices = [
+ 0, 1, 3, 1, 3, 4,
+ 1, 2, 4, 2, 4, 5,
+ 3, 4, 6, 4, 6, 7,
+ 4, 5, 7, 5, 7, 8
+ ];
+ var indicesBuffer = ctx.createBuffer();
+ ctx.bindBuffer(gl.ELEMENT_ARRAY_BUFFER, indicesBuffer);
+ ctx.bufferData(gl.ELEMENT_ARRAY_BUFFER, new Uint16Array(indices), gl.STATIC_DRAW);
+
+ var colors = [
+ 1, 0, 0, 1,
+ 0, 1, 0, 1,
+ 0, 0, 1, 1,
+ 1, 1, 1, 1,
+ 1, 1, 0, 1,
+ 0, 1, 1, 1,
+ 1, 0, 1, 1,
+ 0.5, 0.5, 0.5, 1,
+ 0, 0, 0, 0
+ ];
+
+ var colors32 = new Float32Array(colors);
+
+ var squareColorsBuffer = ctx.createBuffer();
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer);
+ ctx.bufferData(gl.ARRAY_BUFFER, colors32, gl.STATIC_DRAW);
+
+ /** @type {sglrShaderProgram.ShaderProgramDeclaration} */ var progDecl = new sglrShaderProgram.ShaderProgramDeclaration();
+
+ progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexPosition', rrGenericVector.GenericVecType.FLOAT));
+
+ progDecl.pushVertexAttribute(new sglrShaderProgram.VertexAttribute('aVertexColor', rrGenericVector.GenericVecType.FLOAT));
+
+ progDecl.pushVertexSource(new sglrShaderProgram.VertexSource(''));
+
+ progDecl.pushFragmentOutput(new sglrShaderProgram.FragmentOutput(rrGenericVector.GenericVecType.FLOAT));
+
+ progDecl.pushFragmentSource(new sglrShaderProgram.FragmentSource(''));
+
+ /** @type {sglrReferenceContextTest.ContextShaderProgram} */ var program = new sglrReferenceContextTest.ContextShaderProgram(progDecl);
+
+ //Create program
+ ctx.createProgram(program);
+
+ //Use program
+ ctx.useProgram(program);
+
+ var vertexPositionAttribute = ctx.getAttribLocation(program, 'aVertexPosition');
+ var vertexColorAttribute = ctx.getAttribLocation(program, 'aVertexColor');
+ ctx.enableVertexAttribArray(vertexPositionAttribute);
+ ctx.enableVertexAttribArray(vertexColorAttribute);
+
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareVerticesBuffer);
+ ctx.vertexAttribPointer(vertexPositionAttribute, 2, gl.FLOAT, false, 0, 0);
+
+ ctx.bindBuffer(gl.ARRAY_BUFFER, squareColorsBuffer);
+ ctx.vertexAttribPointer(vertexColorAttribute, 4, gl.FLOAT, false, 0, 0);
+
+ ctx.drawElements(gl.TRIANGLES, indices.length, gl.UNSIGNED_SHORT, 0);
+
+ var pixels = new tcuSurface.Surface(width, height);
+ ctx.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, pixels.getAccess().getDataPtr());
+
+ var numFailedPixels = 0;
+
+ var access = pixels.getAccess();
+
+ var pixelsTotest = [
+ // location, color
+ [2, 1], [0, 0, 255, 255],
+ // The red vertex is between 140 and 141 so account for some blending with the white vertex
+ [50, 140], [255, 5, 5, 255],
+ [50, 28], [255, 0, 255, 255],
+ [139, 28], [0, 0, 0, 255],
+ [50, 102], [255, 255, 255, 255],
+ [139, 102], [0, 255, 255, 255]
+ ];
+
+ var threshold = new tcuRGBA.RGBA([5, 5, 5, 5]);
+
+ for (var i = 0; i < pixelsTotest.length; i += 2) {
+ var location = pixelsTotest[i];
+ var reference = new tcuRGBA.RGBA(pixelsTotest[i + 1]);
+ var color = access.getPixelInt(location[0], location[1]);
+ var pixel = new tcuRGBA.RGBA(color);
+ if (!tcuRGBA.compareThreshold(pixel, reference, threshold))
+ numFailedPixels++;
+ }
+
+ tcuLogImage.logImage('Result', '', access);
+
+ if (numFailedPixels > 0)
+ testFailedOptions('Image comparison failed, got ' + numFailedPixels + ' non-equal pixels.', false);
+ else
+ testPassedOptions('Image comparison succeed', true);
+
+ return tcuTestCase.IterateResult.STOP;
+ };
+
+ /**
+ * @constructor
+ * @extends {sglrShaderProgram.ShaderProgram}
+ * @param {sglrShaderProgram.ShaderProgramDeclaration} progDecl
+ */
+ sglrReferenceContextTest.ContextShaderProgram = function(progDecl) {
+ sglrShaderProgram.ShaderProgram.call(this, progDecl);
+ };
+
+ sglrReferenceContextTest.ContextShaderProgram.prototype = Object.create(sglrShaderProgram.ShaderProgram.prototype);
+ sglrReferenceContextTest.ContextShaderProgram.prototype.constructor = sglrReferenceContextTest.ContextShaderProgram;
+
+ /**
+ * @param {Array<rrVertexAttrib.VertexAttrib>} inputs
+ * @param {Array<rrVertexPacket.VertexPacket>} packets
+ * @param {number} numPackets
+ */
+ sglrReferenceContextTest.ContextShaderProgram.prototype.shadeVertices = function(inputs, packets, numPackets) {
+ for (var packetNdx = 0; packetNdx < numPackets; ++packetNdx) {
+ /** @type {number} */ var varyingLocColor = 0;
+
+ /** @type {rrVertexPacket.VertexPacket} */ var packet = packets[packetNdx];
+
+ // Calc output color
+ /** @type {Array<number>} */ var coord = [1.0, 1.0];
+ /** @type {Array<number>} */ var color = [1.0, 1.0, 1.0];
+
+ for (var attribNdx = 0; attribNdx < this.getVertexShader().getInputs().length; attribNdx++) {
+ /** @type {number} */ var numComponents = inputs[attribNdx].componentCount;
+
+ var attribValue = rrVertexAttrib.readVertexAttrib(inputs[attribNdx], packet.instanceNdx, packet.vertexNdx, this.getVertexShader().getInputs()[attribNdx].type);
+
+ if (attribNdx == 0) {
+ coord[0] = attribValue[0];
+ coord[1] = attribValue[1];
+ } else {
+ color[0] = attribValue[0] * attribValue[3];
+ color[1] = attribValue[1] * attribValue[3];
+ color[2] = attribValue[2] * attribValue[3];
+ }
+ }
+
+ // Transform position
+ packet.position = [coord[0], coord[1], 1.0, 1.0];
+
+ // Pass color to FS
+ packet.outputs[varyingLocColor] = [color[0], color[1], color[2], 1.0];
+ }
+ };
+
+ /**
+ * @param {Array<rrFragmentOperations.Fragment>} packets
+ * @param {rrShadingContext.FragmentShadingContext} context
+ */
+ sglrReferenceContextTest.ContextShaderProgram.prototype.shadeFragments = function(packets, context) {
+ var varyingLocColor = 0;
+
+ // Normal shading
+ for (var packetNdx = 0; packetNdx < packets.length; ++packetNdx)
+ packets[packetNdx].value = rrShadingContext.readTriangleVarying(packets[packetNdx], context, varyingLocColor);
+ };
+
+ sglrReferenceContextTest.init = function() {
+ var state = tcuTestCase.runner;
+ /** @type {tcuTestCase.DeqpTest} */ var testGroup = state.testCases;
+
+ /** @type {tcuTestCase.DeqpTest} */ var referenceContextGroup = tcuTestCase.newTest('reference_context', 'Test reference context');
+
+ referenceContextGroup.addChild(new sglrReferenceContextTest.ClearContext('clear_context', 'Clear Context Test'));
+ referenceContextGroup.addChild(new sglrReferenceContextTest.Framebuffer('Framebuffer', 'Framebuffer Test'));
+ referenceContextGroup.addChild(new sglrReferenceContextTest.Shader('Shaders', 'Drawing using TRIANGLES'));
+ referenceContextGroup.addChild(new sglrReferenceContextTest.TriangleStrip('TriangleStrip', 'Drawing using TRIANGLE_STRIP'));
+ referenceContextGroup.addChild(new sglrReferenceContextTest.TriangleFan('TriangleFan', 'Drawing using TRIANGLE_FAN'));
+ referenceContextGroup.addChild(new sglrReferenceContextTest.DrawElements('DrawElements', 'Drawing using DrawElements and TRIANGLES'));
+
+ testGroup.addChild(referenceContextGroup);
+
+ };
+
+ sglrReferenceContextTest.run = function(context) {
+ gl = context;
+ //Set up Test Root parameters
+ var testName = 'single_reference_context';
+ var testDescription = 'Single Reference Context Tests';
+ var state = tcuTestCase.runner;
+
+ state.testName = testName;
+ state.testCases = tcuTestCase.newTest(testName, testDescription, null);
+
+ //Set up name and description of this test series.
+ setCurrentTestName(testName);
+ description(testDescription);
+
+ try {
+ //Create test cases
+ sglrReferenceContextTest.init();
+ //Run test cases
+ tcuTestCase.runTestCases();
+ }
+ catch (err) {
+ bufferedLogToConsole(err);
+ tcuTestCase.runner.terminate();
+ }
+
+ };
+
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceUtils.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceUtils.js
new file mode 100644
index 0000000000..3b93dd8f9f
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrReferenceUtils.js
@@ -0,0 +1,317 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ *//*!
+ * \file
+ * \brief Reference context utils
+ *//*--------------------------------------------------------------------*/
+
+'use strict';
+goog.provide('framework.opengl.simplereference.sglrReferenceUtils');
+goog.require('framework.common.tcuFloat');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.referencerenderer.rrDefs');
+goog.require('framework.referencerenderer.rrGenericVector');
+goog.require('framework.referencerenderer.rrRenderState');
+goog.require('framework.referencerenderer.rrRenderer');
+goog.require('framework.referencerenderer.rrShaders');
+goog.require('framework.referencerenderer.rrVertexAttrib');
+
+goog.scope(function() {
+
+ var sglrReferenceUtils = framework.opengl.simplereference.sglrReferenceUtils;
+ var deMath = framework.delibs.debase.deMath;
+ var tcuFloat = framework.common.tcuFloat;
+ var rrGenericVector = framework.referencerenderer.rrGenericVector;
+ var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib;
+ var rrRenderer = framework.referencerenderer.rrRenderer;
+ var rrDefs = framework.referencerenderer.rrDefs;
+ var rrShaders = framework.referencerenderer.rrShaders;
+ var rrRenderState = framework.referencerenderer.rrRenderState;
+
+ /**
+ * @param {number} type (32-bit, unsigend)
+ * @return {rrVertexAttrib.VertexAttribType}
+ * @throws {Error}
+ */
+ sglrReferenceUtils.mapGLPureIntegerVertexAttributeType = function(type) {
+ switch (type) {
+ case gl.UNSIGNED_BYTE: return rrVertexAttrib.VertexAttribType.PURE_UINT8;
+ case gl.UNSIGNED_SHORT: return rrVertexAttrib.VertexAttribType.PURE_UINT16;
+ case gl.UNSIGNED_INT: return rrVertexAttrib.VertexAttribType.PURE_UINT32;
+ case gl.BYTE: return rrVertexAttrib.VertexAttribType.PURE_INT8;
+ case gl.SHORT: return rrVertexAttrib.VertexAttribType.PURE_INT16;
+ case gl.INT: return rrVertexAttrib.VertexAttribType.PURE_INT32;
+ default:
+ throw new Error('Value to do mapping not compatible');
+ }
+ };
+
+ /**
+ * @param {number} type (32-bit, unsigend)
+ * @param {boolean} normalizedInteger
+ * @param {number} size
+ * @return {rrVertexAttrib.VertexAttribType} converted value from type to VertexAttribType
+ * @throws {Error}
+ */
+ sglrReferenceUtils.mapGLFloatVertexAttributeType = function(type, normalizedInteger, size) {
+
+ /** @type {boolean} */ var useClampingNormalization = true;
+
+ switch (type) {
+ case gl.FLOAT:
+ return rrVertexAttrib.VertexAttribType.FLOAT;
+ case gl.HALF_FLOAT:
+ return rrVertexAttrib.VertexAttribType.HALF;
+ /* Not supported in WebGL 1/2 case gl.FIXED:
+ return rrVertexAttrib.VertexAttribType.FIXED;
+ case gl.DOUBLE:
+ return rrVertexAttrib.VertexAttribType.DOUBLE; */
+ case gl.UNSIGNED_BYTE:
+ if (!normalizedInteger)
+ return rrVertexAttrib.VertexAttribType.NONPURE_UINT8;
+ else
+ return rrVertexAttrib.VertexAttribType.NONPURE_UNORM8;
+
+ case gl.UNSIGNED_SHORT:
+ if (!normalizedInteger)
+ return rrVertexAttrib.VertexAttribType.NONPURE_UINT16;
+ else
+ return rrVertexAttrib.VertexAttribType.NONPURE_UNORM16;
+
+ case gl.UNSIGNED_INT:
+ if (!normalizedInteger)
+ return rrVertexAttrib.VertexAttribType.NONPURE_UINT32;
+ else
+ return rrVertexAttrib.VertexAttribType.NONPURE_UNORM32;
+
+ case gl.UNSIGNED_INT_2_10_10_10_REV:
+ if (!normalizedInteger)
+ return rrVertexAttrib.VertexAttribType.NONPURE_UINT_2_10_10_10_REV;
+ else
+ return rrVertexAttrib.VertexAttribType.NONPURE_UNORM_2_10_10_10_REV;
+
+ case gl.BYTE:
+ if (!normalizedInteger)
+ return rrVertexAttrib.VertexAttribType.NONPURE_INT8;
+ else if (useClampingNormalization)
+ return rrVertexAttrib.VertexAttribType.NONPURE_SNORM8_CLAMP;
+ else
+ return rrVertexAttrib.VertexAttribType.NONPURE_SNORM8_SCALE;
+
+ case gl.SHORT:
+ if (!normalizedInteger)
+ return rrVertexAttrib.VertexAttribType.NONPURE_INT16;
+ else if (useClampingNormalization)
+ return rrVertexAttrib.VertexAttribType.NONPURE_SNORM16_CLAMP;
+ else
+ return rrVertexAttrib.VertexAttribType.NONPURE_SNORM16_SCALE;
+
+ case gl.INT:
+ if (!normalizedInteger)
+ return rrVertexAttrib.VertexAttribType.NONPURE_INT32;
+ else if (useClampingNormalization)
+ return rrVertexAttrib.VertexAttribType.NONPURE_SNORM32_CLAMP;
+ else
+ return rrVertexAttrib.VertexAttribType.NONPURE_SNORM32_SCALE;
+
+ case gl.INT_2_10_10_10_REV:
+ if (!normalizedInteger)
+ return rrVertexAttrib.VertexAttribType.NONPURE_INT_2_10_10_10_REV;
+ else if (useClampingNormalization)
+ return rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_CLAMP;
+ else
+ return rrVertexAttrib.VertexAttribType.NONPURE_SNORM_2_10_10_10_REV_SCALE;
+
+ default:
+ throw new Error('Value to do mapping not compatible');
+
+ }
+
+ };
+
+ /**
+ * @param {number} size
+ * @return {number}
+ * @throws {Error}
+ */
+ sglrReferenceUtils.mapGLSize = function(size) {
+ switch (size) {
+ case 1: return 1;
+ case 2: return 2;
+ case 3: return 3;
+ case 4: return 4;
+ /* NOT in GL
+ case gl.BGRA: return 4;
+ */
+
+ default:
+ throw new Error('Value to do mapping not compatible');
+ }
+ };
+
+ /**
+ * @param {number} type (32-bit, unsigned)
+ * @return {rrRenderer.PrimitiveType}
+ * @throws {Error}
+ */
+ sglrReferenceUtils.mapGLPrimitiveType = function(type) {
+ switch (type) {
+ case gl.TRIANGLES: return rrRenderer.PrimitiveType.TRIANGLES;
+ case gl.TRIANGLE_STRIP: return rrRenderer.PrimitiveType.TRIANGLE_STRIP;
+ case gl.TRIANGLE_FAN: return rrRenderer.PrimitiveType.TRIANGLE_FAN;
+ case gl.LINES: return rrRenderer.PrimitiveType.LINES;
+ case gl.LINE_STRIP: return rrRenderer.PrimitiveType.LINE_STRIP;
+ case gl.LINE_LOOP: return rrRenderer.PrimitiveType.LINE_LOOP;
+ case gl.POINTS: return rrRenderer.PrimitiveType.POINTS;
+
+ default:
+ throw new Error('Value to do mapping not compatible');
+ }
+ };
+
+ /**
+ * @param {number} type (32-bit, unsigned)
+ * @return {rrDefs.IndexType}
+ * @throws {Error}
+ */
+ sglrReferenceUtils.mapGLIndexType = function(type) {
+ switch (type) {
+ case gl.UNSIGNED_BYTE: return rrDefs.IndexType.INDEXTYPE_UINT8;
+ case gl.UNSIGNED_SHORT: return rrDefs.IndexType.INDEXTYPE_UINT16;
+ case gl.UNSIGNED_INT: return rrDefs.IndexType.INDEXTYPE_UINT32;
+ default:
+ throw new Error('Value to do mapping not compatible');
+ }
+ };
+
+ /**
+ * @param {number} func (deUint32)
+ * @return {rrRenderState.TestFunc}
+ * @throws {Error}
+ */
+ sglrReferenceUtils.mapGLTestFunc = function(func) {
+ switch (func) {
+ case gl.ALWAYS: return rrRenderState.TestFunc.ALWAYS;
+ case gl.EQUAL: return rrRenderState.TestFunc.EQUAL;
+ case gl.GEQUAL: return rrRenderState.TestFunc.GEQUAL;
+ case gl.GREATER: return rrRenderState.TestFunc.GREATER;
+ case gl.LEQUAL: return rrRenderState.TestFunc.LEQUAL;
+ case gl.LESS: return rrRenderState.TestFunc.LESS;
+ case gl.NEVER: return rrRenderState.TestFunc.NEVER;
+ case gl.NOTEQUAL: return rrRenderState.TestFunc.NOTEQUAL;
+ default:
+ throw new Error('Value to do mapping not compatible');
+ }
+ };
+
+ /**
+ * @param {number} op (deUint32)
+ * @return {rrRenderState.StencilOp}
+ * @throws {Error}
+ */
+ sglrReferenceUtils.mapGLStencilOp = function(op) {
+ switch (op) {
+ case gl.KEEP: return rrRenderState.StencilOp.KEEP;
+ case gl.ZERO: return rrRenderState.StencilOp.ZERO;
+ case gl.REPLACE: return rrRenderState.StencilOp.REPLACE;
+ case gl.INCR: return rrRenderState.StencilOp.INCR;
+ case gl.DECR: return rrRenderState.StencilOp.DECR;
+ case gl.INCR_WRAP: return rrRenderState.StencilOp.INCR_WRAP;
+ case gl.DECR_WRAP: return rrRenderState.StencilOp.DECR_WRAP;
+ case gl.INVERT: return rrRenderState.StencilOp.INVERT;
+ default:
+ throw new Error('Value to do mapping not compatible');
+ }
+ };
+
+ /**
+ * @param {number} equation (deUint32)
+ * @return {rrRenderState.BlendEquation}
+ * @throws {Error}
+ */
+ sglrReferenceUtils.mapGLBlendEquation = function(equation) {
+ switch (equation) {
+ case gl.FUNC_ADD: return rrRenderState.BlendEquation.ADD;
+ case gl.FUNC_SUBTRACT: return rrRenderState.BlendEquation.SUBTRACT;
+ case gl.FUNC_REVERSE_SUBTRACT: return rrRenderState.BlendEquation.REVERSE_SUBTRACT;
+ case gl.MIN: return rrRenderState.BlendEquation.MIN;
+ case gl.MAX: return rrRenderState.BlendEquation.MAX;
+ default:
+ throw new Error('Value to do mapping not compatible');
+ }
+ };
+
+ /**
+ * @param {number} equation (deUint32)
+ * @return {rrRenderState.BlendEquationAdvanced}
+ * @throws {Error}
+ */
+ /*sglrReferenceUtils.mapGLBlendEquationAdvanced = function(equation) {
+ switch (equation) {
+ case gl.MULTIPLY_KHR: return rrRenderState.BlendEquationAdvanced.MULTIPLY;
+ case gl.SCREEN_KHR: return rrRenderState.BlendEquationAdvanced.SCREEN;
+ case gl.OVERLAY_KHR: return rrRenderState.BlendEquationAdvanced.OVERLAY;
+ case gl.DARKEN_KHR: return rrRenderState.BlendEquationAdvanced.DARKEN;
+ case gl.LIGHTEN_KHR: return rrRenderState.BlendEquationAdvanced.LIGHTEN;
+ case gl.COLORDODGE_KHR: return rrRenderState.BlendEquationAdvanced.COLORDODGE;
+ case gl.COLORBURN_KHR: return rrRenderState.BlendEquationAdvanced.COLORBURN;
+ case gl.HARDLIGHT_KHR: return rrRenderState.BlendEquationAdvanced.HARDLIGHT;
+ case gl.SOFTLIGHT_KHR: return rrRenderState.BlendEquationAdvanced.SOFTLIGHT;
+ case gl.DIFFERENCE_KHR: return rrRenderState.BlendEquationAdvanced.DIFFERENCE;
+ case gl.EXCLUSION_KHR: return rrRenderState.BlendEquationAdvanced.EXCLUSION;
+ case gl.HSL_HUE_KHR: return rrRenderState.BlendEquationAdvanced.HSL_HUE;
+ case gl.HSL_SATURATION_KHR: return rrRenderState.BlendEquationAdvanced.HSL_SATURATION;
+ case gl.HSL_COLOR_KHR: return rrRenderState.BlendEquationAdvanced.HSL_COLOR;
+ case gl.HSL_LUMINOSITY_KHR: return rrRenderState.BlendEquationAdvanced.HSL_LUMINOSITY;
+ default:
+ throw new Error("Value to do mapping not compatible");
+ }
+ };*/
+
+ /**
+ * @param {number} func (deUint32)
+ * @return {rrRenderState.BlendFunc}
+ * @throws {Error}
+ */
+ sglrReferenceUtils.mapGLBlendFunc = function(func) {
+ switch (func) {
+ case gl.ZERO: return rrRenderState.BlendFunc.ZERO;
+ case gl.ONE: return rrRenderState.BlendFunc.ONE;
+ case gl.SRC_COLOR: return rrRenderState.BlendFunc.SRC_COLOR;
+ case gl.ONE_MINUS_SRC_COLOR: return rrRenderState.BlendFunc.ONE_MINUS_SRC_COLOR;
+ case gl.DST_COLOR: return rrRenderState.BlendFunc.DST_COLOR;
+ case gl.ONE_MINUS_DST_COLOR: return rrRenderState.BlendFunc.ONE_MINUS_DST_COLOR;
+ case gl.SRC_ALPHA: return rrRenderState.BlendFunc.SRC_ALPHA;
+ case gl.ONE_MINUS_SRC_ALPHA: return rrRenderState.BlendFunc.ONE_MINUS_SRC_ALPHA;
+ case gl.DST_ALPHA: return rrRenderState.BlendFunc.DST_ALPHA;
+ case gl.ONE_MINUS_DST_ALPHA: return rrRenderState.BlendFunc.ONE_MINUS_DST_ALPHA;
+ case gl.CONSTANT_COLOR: return rrRenderState.BlendFunc.CONSTANT_COLOR;
+ case gl.ONE_MINUS_CONSTANT_COLOR: return rrRenderState.BlendFunc.ONE_MINUS_CONSTANT_COLOR;
+ case gl.CONSTANT_ALPHA: return rrRenderState.BlendFunc.CONSTANT_ALPHA;
+ case gl.ONE_MINUS_CONSTANT_ALPHA: return rrRenderState.BlendFunc.ONE_MINUS_CONSTANT_ALPHA;
+ case gl.SRC_ALPHA_SATURATE: return rrRenderState.BlendFunc.SRC_ALPHA_SATURATE;
+ // case gl.SRC1_COLOR: return rrRenderState.BlendFunc.SRC1_COLOR;
+ // case gl.ONE_MINUS_SRC1_COLOR: return rrRenderState.BlendFunc.ONE_MINUS_SRC1_COLOR;
+ // case gl.SRC1_ALPHA: return rrRenderState.BlendFunc.SRC1_ALPHA;
+ // case gl.ONE_MINUS_SRC1_ALPHA: return rrRenderState.BlendFunc.ONE_MINUS_SRC1_ALPHA;
+ default:
+ throw new Error('Value to do mapping not compatible');
+ }
+ };
+});
diff --git a/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrShaderProgram.js b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrShaderProgram.js
new file mode 100644
index 0000000000..f5201a5315
--- /dev/null
+++ b/dom/canvas/test/webgl-conf/checkout/deqp/framework/opengl/simplereference/sglrShaderProgram.js
@@ -0,0 +1,336 @@
+/*-------------------------------------------------------------------------
+ * drawElements Quality Program OpenGL ES Utilities
+ * ------------------------------------------------
+ *
+ * Copyright 2014 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ *
+ */
+
+'use strict';
+goog.provide('framework.opengl.simplereference.sglrShaderProgram');
+goog.require('framework.common.tcuTexture');
+goog.require('framework.common.tcuTextureUtil');
+goog.require('framework.delibs.debase.deMath');
+goog.require('framework.opengl.gluShaderUtil');
+goog.require('framework.opengl.gluTextureUtil');
+goog.require('framework.referencerenderer.rrDefs');
+goog.require('framework.referencerenderer.rrFragmentOperations');
+goog.require('framework.referencerenderer.rrGenericVector');
+goog.require('framework.referencerenderer.rrShaders');
+goog.require('framework.referencerenderer.rrShadingContext');
+goog.require('framework.referencerenderer.rrVertexAttrib');
+goog.require('framework.referencerenderer.rrVertexPacket');
+
+goog.scope(function() {
+
+ var sglrShaderProgram = framework.opengl.simplereference.sglrShaderProgram;
+ var rrShaders = framework.referencerenderer.rrShaders;
+ var rrGenericVector = framework.referencerenderer.rrGenericVector;
+ var tcuTexture = framework.common.tcuTexture;
+ var deMath = framework.delibs.debase.deMath;
+ var gluTextureUtil = framework.opengl.gluTextureUtil;
+ var gluShaderUtil = framework.opengl.gluShaderUtil;
+ var tcuTextureUtil = framework.common.tcuTextureUtil;
+ var rrDefs = framework.referencerenderer.rrDefs;
+ var rrFragmentOperations = framework.referencerenderer.rrFragmentOperations;
+ var rrVertexAttrib = framework.referencerenderer.rrVertexAttrib;
+ var rrVertexPacket = framework.referencerenderer.rrVertexPacket;
+ var rrShadingContext = framework.referencerenderer.rrShadingContext;
+
+ var DE_ASSERT = function(x) {
+ if (!x)
+ throw new Error('Assert failed');
+ };
+
+ /**
+ * sglrShaderProgram.VaryingFlags
+ * @constructor
+ * @struct
+ */
+ sglrShaderProgram.VaryingFlags = function() {
+ this.NONE = true; //TODO: is NONE necessary?
+ this.FLATSHADE = false;
+ };
+
+ /**
+ * sglrShaderProgram.VertexAttribute
+ * @constructor
+ * @param {string} name_
+ * @param {rrGenericVector.GenericVecType} type_
+ */
+ sglrShaderProgram.VertexAttribute = function(name_, type_) {
+ this.name = name_;
+ this.type = type_;
+ };
+
+ /**
+ * sglrShaderProgram.VertexToFragmentVarying
+ * @constructor
+ * @param {rrGenericVector.GenericVecType} type_
+ * @param {sglrShaderProgram.VaryingFlags=} flags
+ */
+ sglrShaderProgram.VertexToFragmentVarying = function(type_, flags) {
+ this.type = type_;
+ this.flatshade = flags === undefined ? new sglrShaderProgram.VaryingFlags().FLATSHADE : flags.FLATSHADE;
+ };
+
+ /**
+ * sglrShaderProgram.FragmentOutput
+ * @constructor
+ * @param {rrGenericVector.GenericVecType} type_
+ */
+ sglrShaderProgram.FragmentOutput = function(type_) {
+ /** @type {rrGenericVector.GenericVecType} */ this.type = type_;
+ };
+
+ /**
+ * sglrShaderProgram.Uniform
+ * @constructor
+ * @param {string} name_
+ * @param {gluShaderUtil.DataType} type_
+ */
+ sglrShaderProgram.Uniform = function(name_, type_) {
+ /** @type {string} */ this.name = name_;
+ /** @type {gluShaderUtil.DataType} */ this.type = type_;
+ /** @type {Array<number>} */ this.value;
+ /** @type {?rrDefs.Sampler} */ this.sampler = null;
+ };
+
+ /**
+ * sglrShaderProgram.VertexSource
+ * @constructor
+ * @param {string} str
+ */
+ sglrShaderProgram.VertexSource = function(str) {
+ /** @type {string} */ this.source = str;
+ };
+
+ /**
+ * sglrShaderProgram.FragmentSource
+ * @constructor
+ * @param {string} str
+ */
+ sglrShaderProgram.FragmentSource = function(str) {
+ /** @type {string} */ this.source = str;
+ };
+
+ /**
+ * sglrShaderProgram.ShaderProgramDeclaration
+ * @constructor
+ */
+ sglrShaderProgram.ShaderProgramDeclaration = function() {
+ /** @type {Array<sglrShaderProgram.VertexAttribute>} */ this.m_vertexAttributes = [];
+ /** @type {Array<sglrShaderProgram.VertexToFragmentVarying>} */ this.m_vertexToFragmentVaryings = [];
+ /** @type {Array<sglrShaderProgram.FragmentOutput>} */ this.m_fragmentOutputs = [];
+ /** @type {Array<sglrShaderProgram.Uniform>} */ this.m_uniforms = [];
+ /** @type {string} */ this.m_vertexSource;
+ /** @type {string} */ this.m_fragmentSource;
+
+ /** @type {boolean} */ this.m_vertexShaderSet = false;
+ /** @type {boolean} */ this.m_fragmentShaderSet = false;
+ };
+
+ /**
+ * Add a vertex attribute to the shader program declaration.
+ * @param {sglrShaderProgram.VertexAttribute} v
+ * @return {sglrShaderProgram.ShaderProgramDeclaration}
+ */
+ sglrShaderProgram.ShaderProgramDeclaration.prototype.pushVertexAttribute = function(v) {
+ this.m_vertexAttributes.push(v);
+ return this;
+ };
+
+ /**
+ * Add a vertex to fragment varying to the shader program declaration.
+ * @param {sglrShaderProgram.VertexToFragmentVarying} v
+ * @return {sglrShaderProgram.ShaderProgramDeclaration}
+ */
+ sglrShaderProgram.ShaderProgramDeclaration.prototype.pushVertexToFragmentVarying = function(v) {
+ this.m_vertexToFragmentVaryings.push(v);
+ return this;
+ };
+
+ /**
+ * Add a fragment output to the shader program declaration.
+ * @param {sglrShaderProgram.FragmentOutput} v
+ * @return {sglrShaderProgram.ShaderProgramDeclaration}
+ */
+ sglrShaderProgram.ShaderProgramDeclaration.prototype.pushFragmentOutput = function(v) {
+ this.m_fragmentOutputs.push(v);
+ return this;
+ };
+
+ /**
+ * Add a uniform to the shader program declaration.
+ * @param {sglrShaderProgram.Uniform} v
+ * @return {sglrShaderProgram.ShaderProgramDeclaration}
+ */
+ sglrShaderProgram.ShaderProgramDeclaration.prototype.pushUniform = function(v) {
+ this.m_uniforms.push(v);
+ return this;
+ };
+
+ /**
+ * @param {sglrShaderProgram.VertexSource} c
+ * @return {sglrShaderProgram.ShaderProgramDeclaration}
+ */
+ sglrShaderProgram.ShaderProgramDeclaration.prototype.pushVertexSource = function(c) {
+ DE_ASSERT(!this.m_vertexShaderSet);
+ this.m_vertexSource = c.source;
+ this.m_vertexShaderSet = true;
+ return this;
+ };
+
+ /**
+ * @param {sglrShaderProgram.FragmentSource} c
+ * @return {sglrShaderProgram.ShaderProgramDeclaration}
+ */
+ sglrShaderProgram.ShaderProgramDeclaration.prototype.pushFragmentSource = function(c) {
+ DE_ASSERT(!this.m_fragmentSource);
+ /** @type {sglrShaderProgram.FragmentSource} */ this.m_fragmentSource = c.source;
+ /** @type {boolean} */ this.m_fragmentShaderSet = true;
+ return this;
+ };
+
+ /**
+ * @return {boolean}
+ */
+ sglrShaderProgram.ShaderProgramDeclaration.prototype.valid = function() {
+ if (!this.m_vertexShaderSet || !this.m_fragmentShaderSet)
+ return false;
+
+ if (this.m_fragmentOutputs.length == 0)
+ return false;
+
+ return true;
+ };
+
+ /**
+ * @return {number}
+ */
+ sglrShaderProgram.ShaderProgramDeclaration.prototype.getVertexInputCount = function() {
+ return this.m_vertexAttributes.length;
+ };
+
+ /**
+ * @return {number}
+ */
+ sglrShaderProgram.ShaderProgramDeclaration.prototype.getVertexOutputCount = function() {
+ return this.m_vertexToFragmentVaryings.length;
+ };
+
+ /**
+ * @return {number}
+ */
+ sglrShaderProgram.ShaderProgramDeclaration.prototype.getFragmentInputCount = function() {
+ return this.m_vertexToFragmentVaryings.length;
+ };
+
+ /**
+ * @return {number}
+ */
+ sglrShaderProgram.ShaderProgramDeclaration.prototype.getFragmentOutputCount = function() {
+ return this.m_fragmentOutputs.length;
+ };
+
+ /**
+ * @constructor
+ * @param {sglrShaderProgram.ShaderProgramDeclaration} decl
+ */
+ sglrShaderProgram.ShaderProgram = function(decl) {
+ /** @type {rrShaders.VertexShader} */ this.vertexShader = new rrShaders.VertexShader(decl.getVertexInputCount(), decl.getVertexOutputCount());
+ /** @type {rrShaders.FragmentShader} */ this.fragmentShader = new rrShaders.FragmentShader(decl.getFragmentInputCount(), decl.getFragmentOutputCount());
+
+ /** @type {Array<string>} */ this.m_attributeNames = [];
+ /** @type {Array<sglrShaderProgram.Uniform>} */ this.m_uniforms = [];
+ /** @type {string} */ this.m_vertSrc = decl.m_vertexSource;
+ /** @type {string} */ this.m_fragSrc = decl.m_fragmentSource;
+
+ DE_ASSERT(decl.valid());
+
+ // Set up shader IO
+
+ for (var ndx = 0; ndx < decl.m_vertexAttributes.length; ++ndx) {
+ this.vertexShader.m_inputs[ndx].type = decl.m_vertexAttributes[ndx].type;
+ this.m_attributeNames[ndx] = decl.m_vertexAttributes[ndx].name;
+ }
+
+ for (var ndx = 0; ndx < decl.m_vertexToFragmentVaryings.length; ++ndx) {
+ this.vertexShader.m_outputs[ndx].type = decl.m_vertexToFragmentVaryings[ndx].type;
+ this.vertexShader.m_outputs[ndx].flatshade = decl.m_vertexToFragmentVaryings[ndx].flatshade;
+
+ this.fragmentShader.m_inputs[ndx] = this.vertexShader.m_outputs[ndx];
+ }
+
+ for (var ndx = 0; ndx < decl.m_fragmentOutputs.length; ++ndx)
+ this.fragmentShader.m_outputs[ndx].type = decl.m_fragmentOutputs[ndx].type;
+
+ // Set up uniforms
+
+ for (var ndx = 0; ndx < decl.m_uniforms.length; ++ndx)
+ this.m_uniforms[ndx] = new sglrShaderProgram.Uniform(decl.m_uniforms[ndx].name, decl.m_uniforms[ndx].type);
+ };
+
+ /**
+ * @return {rrShaders.VertexShader}
+ */
+ sglrShaderProgram.ShaderProgram.prototype.getVertexShader = function() {
+ return this.vertexShader;
+ };
+
+ /**
+ * @return {rrShaders.FragmentShader}
+ */
+ sglrShaderProgram.ShaderProgram.prototype.getFragmentShader = function() {
+ return this.fragmentShader;
+ };
+
+ /**
+ * @param {string} name
+ * @return {sglrShaderProgram.Uniform}
+ * @throws {Error}
+ */
+ sglrShaderProgram.ShaderProgram.prototype.getUniformByName = function(name) {
+ DE_ASSERT(name);
+
+ for (var ndx = 0; ndx < this.m_uniforms.length; ++ndx)
+ if (this.m_uniforms[ndx].name == name)
+ return this.m_uniforms[ndx];
+
+ throw new Error('Invalid uniform name, uniform not found.');
+ };
+
+ /**
+ * shadeFragments - abstract function, to be implemented by children classes
+ * @param {Array<rrFragmentOperations.Fragment>} packets
+ * @param {rrShadingContext.FragmentShadingContext} context
+ * @throws {Error}
+ */
+ sglrShaderProgram.ShaderProgram.prototype.shadeFragments = function(packets, context) {
+ throw new Error('This function needs to be overwritten in a child class.');
+ };
+
+ /**
+ * shadeVertices - abstract function, to be implemented by children classes
+ * @param {Array<rrVertexAttrib.VertexAttrib>} inputs
+ * @param {Array<rrVertexPacket.VertexPacket>} packets
+ * @param {number} numPackets
+ * @throws {Error}
+ */
+ sglrShaderProgram.ShaderProgram.prototype.shadeVertices = function(inputs, packets, numPackets) {
+ throw new Error('This function needs to be overwritten in a child class.');
+ };
+
+});
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;
+ };
+
+});