From 4d3996009bd1e26286ebbcc3b1cfdb74d904280c Mon Sep 17 00:00:00 2001 From: Christopher Cameron Date: Wed, 27 Apr 2022 13:09:57 -0700 Subject: [PATCH 1/5] Add unpackColorSpace tests to tex-image-and-sub-image-2d-with-video --- .../tex-image-and-sub-image-2d-with-video.js | 66 ++++++------- .../js/tests/tex-image-and-sub-image-utils.js | 62 ++++++++++++- sdk/tests/js/webgl-test-utils.js | 92 +++++++++++++++++++ 3 files changed, 183 insertions(+), 37 deletions(-) diff --git a/sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js b/sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js index 82e1c7377b..92caf21ae5 100644 --- a/sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js +++ b/sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js @@ -20,8 +20,6 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource var tiu = TexImageUtils; var gl = null; var successfullyParsed = false; - var redColor = [255, 0, 0]; - var greenColor = [0, 255, 0]; // Test each format separately because many browsers implement each // differently. Some might be GPU accelerated, some might not. Etc... @@ -45,31 +43,13 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource return; } - switch (gl[pixelFormat]) { - case gl.RED: - case gl.RED_INTEGER: - greenColor = [0, 0, 0]; - break; - case gl.LUMINANCE: - case gl.LUMINANCE_ALPHA: - redColor = [255, 255, 255]; - greenColor = [0, 0, 0]; - break; - case gl.ALPHA: - redColor = [0, 0, 0]; - greenColor = [0, 0, 0]; - break; - default: - break; - } - gl.clearColor(0,0,0,1); gl.clearDepth(1); runTest(); } - function runOneIteration(videoElement, useTexSubImage2D, flipY, topColor, bottomColor, sourceSubRectangle, program, bindingTarget) + function runOneIteration(videoElement, unpackColorSpace, useTexSubImage2D, flipY, topColorName, bottomColorName, sourceSubRectangle, program, bindingTarget) { sourceSubRectangleString = ''; if (sourceSubRectangle) { @@ -102,6 +82,10 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource gl.TEXTURE_CUBE_MAP_POSITIVE_Z, gl.TEXTURE_CUBE_MAP_NEGATIVE_Z]; } + // Handle target color space. + if (unpackColorSpace) { + gl.unpackColorSpace = unpackColorSpace; + } // Handle the source sub-rectangle if specified (WebGL 2.0 only) if (sourceSubRectangle) { gl.pixelStorei(gl.UNPACK_SKIP_PIXELS, sourceSubRectangle[0]); @@ -165,6 +149,12 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource loc = gl.getUniformLocation(program, "face"); } + const topColor = wtu.colorAsSampledWithInternalFormat( + wtu.namedColorInColorSpace(topColorName, unpackColorSpace), + internalFormat); + const bottomColor = wtu.colorAsSampledWithInternalFormat( + wtu.namedColorInColorSpace(bottomColorName, unpackColorSpace), + internalFormat); for (var tt = 0; tt < targets.length; ++tt) { if (bindingTarget == gl.TEXTURE_CUBE_MAP) { gl.uniform1i(loc, targets[tt]); @@ -173,7 +163,7 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource wtu.clearAndDrawUnitQuad(gl, [0, 0, 0, 255]); // Check a few pixels near the top and bottom and make sure they have // the right color. - const tolerance = 6; + const tolerance = Math.max(6, tiu.tolerance(internalFormat, pixelFormat, pixelType)); debug("Checking lower left corner"); wtu.checkCanvasRect(gl, 4, 4, 2, 2, bottomColor, "shouldBe " + bottomColor, tolerance); @@ -186,33 +176,36 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource function runTest(videoElement) { var cases = [ - { sub: false, flipY: true, topColor: redColor, bottomColor: greenColor }, - { sub: false, flipY: false, topColor: greenColor, bottomColor: redColor }, - { sub: true, flipY: true, topColor: redColor, bottomColor: greenColor }, - { sub: true, flipY: false, topColor: greenColor, bottomColor: redColor }, + { sub: false, flipY: true, topColor: 'Red', bottomColor: 'Green' }, + { sub: false, flipY: false, topColor: 'Green', bottomColor: 'Red' }, + { sub: true, flipY: true, topColor: 'Red', bottomColor: 'Green' }, + { sub: true, flipY: false, topColor: 'Green', bottomColor: 'Red' }, ]; if (wtu.getDefault3DContextVersion() > 1) { cases = cases.concat([ - { sub: false, flipY: false, topColor: redColor, bottomColor: redColor, + { sub: false, flipY: false, topColor: 'Red', bottomColor: 'Red', sourceSubRectangle: [20, 16, 40, 32] }, - { sub: false, flipY: true, topColor: greenColor, bottomColor: greenColor, + { sub: false, flipY: true, topColor: 'Green', bottomColor: 'Green', sourceSubRectangle: [20, 16, 40, 32] }, - { sub: false, flipY: false, topColor: greenColor, bottomColor: greenColor, + { sub: false, flipY: false, topColor: 'Green', bottomColor: 'Green', sourceSubRectangle: [20, 80, 40, 32] }, - { sub: false, flipY: true, topColor: redColor, bottomColor: redColor, + { sub: false, flipY: true, topColor: 'Red', bottomColor: 'Red', sourceSubRectangle: [20, 80, 40, 32] }, - { sub: true, flipY: false, topColor: redColor, bottomColor: redColor, + { sub: true, flipY: false, topColor: 'Red', bottomColor: 'Red', sourceSubRectangle: [20, 16, 40, 32] }, - { sub: true, flipY: true, topColor: greenColor, bottomColor: greenColor, + { sub: true, flipY: true, topColor: 'Green', bottomColor: 'Green', sourceSubRectangle: [20, 16, 40, 32] }, - { sub: true, flipY: false, topColor: greenColor, bottomColor: greenColor, + { sub: true, flipY: false, topColor: 'Green', bottomColor: 'Green', sourceSubRectangle: [20, 80, 40, 32] }, - { sub: true, flipY: true, topColor: redColor, bottomColor: redColor, + { sub: true, flipY: true, topColor: 'Red', bottomColor: 'Red', sourceSubRectangle: [20, 80, 40, 32] }, ]); } + cases = tiu.crossProductTestCasesWithUnpackColorSpaces( + cases, tiu.unpackColorSpacesToTest(gl)); + function runTexImageTest(bindingTarget) { var program; if (bindingTarget == gl.TEXTURE_2D) { @@ -269,8 +262,9 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource break; } } - runOneIteration(video, cases[i].sub, cases[i].flipY, - cases[i].topColor, cases[i].bottomColor, + runOneIteration(video, cases[i].unpackColorSpace, cases[i].sub, cases[i].flipY, + cases[i].topColor, + cases[i].bottomColor, cases[i].sourceSubRectangle, program, bindingTarget); } diff --git a/sdk/tests/js/tests/tex-image-and-sub-image-utils.js b/sdk/tests/js/tests/tex-image-and-sub-image-utils.js index 7a7f05984b..22e0ecacb6 100644 --- a/sdk/tests/js/tests/tex-image-and-sub-image-utils.js +++ b/sdk/tests/js/tests/tex-image-and-sub-image-utils.js @@ -791,11 +791,71 @@ var TexImageUtils = (function() { return program; }; + /** + * Return a list of unpack color spaces to test, supported by the specified + * WebGLRenderingContext. + */ + var unpackColorSpacesToTest = function(gl) + { + if ('unpackColorSpace' in gl) + return ['srgb', 'display-p3']; + else + return [null]; + } + + /** + * For each entry in unpackColorSpaces, duplicate all of cases, adding an + * unpackColorSpace key with its value set to that entry to each case. + */ + var crossProductTestCasesWithUnpackColorSpaces = function(cases, unpackColorSpaces) + { + var caseWithColorSpace = function(c, cs) { return Object.assign({}, c, {unpackColorSpace:cs}); } + var casesList = unpackColorSpaces.map(cs => cases.map(c => caseWithColorSpace(c, cs))); + return [].concat.apply([], casesList); + } + + /** + * Given given an internalformat, format, and type, return the tolerance + * that should be used when comparing an input 8-bit value to one that has + * been truncated through the specified formats. + */ + var tolerance = function(internalformat, format, type) { + function typeTolerance(type) { + switch(type) { + case 'UNSIGNED_SHORT_5_6_5': + case 'UNSIGNED_SHORT_5_5_5_1': + return 255 / 31; + case 'UNSIGNED_SHORT_4_4_4_4': + return 255 / 15; + break; + default: + return 1; + } + }; + function formatTolerance(format) { + switch(format) { + case 'RGB565': + case 'RGB5_A1': + return 255/31; + case 'RGBA4': + return 255/15; + default: + return 1; + } + }; + return Math.max(formatTolerance(internalformat), + formatTolerance(format), + typeTolerance(type)); + } + return { setupTexturedQuad: setupTexturedQuad, setupTexturedQuadWithCubeMap: setupTexturedQuadWithCubeMap, setupTexturedQuadWith3D: setupTexturedQuadWith3D, - setupTexturedQuadWith2DArray: setupTexturedQuadWith2DArray + setupTexturedQuadWith2DArray: setupTexturedQuadWith2DArray, + unpackColorSpacesToTest: unpackColorSpacesToTest, + crossProductTestCasesWithUnpackColorSpaces: crossProductTestCasesWithUnpackColorSpaces, + tolerance: tolerance }; }()); diff --git a/sdk/tests/js/webgl-test-utils.js b/sdk/tests/js/webgl-test-utils.js index 9affa10823..04e22cafcd 100644 --- a/sdk/tests/js/webgl-test-utils.js +++ b/sdk/tests/js/webgl-test-utils.js @@ -3296,6 +3296,94 @@ function linearChannelToSRGB(value) { return Math.trunc(value * 255 + 0.5); } +/** + * Return the named color in the specified color space. + * @param {string} colorName The name of the color to convert. + * Supported color names are: + * 'Red', which is maximum sRGB red. + * 'Green', which is maximum sRGB green. + * @param {string} colorSpace The color space to convert to. Supported + color spaces are: + * null, which is treated as sRGB + * 'srgb' + * 'display-p3'. + * @return {!Array.} color The color in the specified color + * space as an 8-bit RGBA array with unpremultiplied alpha. + */ +var namedColorInColorSpace = function(colorName, colorSpace) { + var result; + switch (colorSpace) { + case null: + case 'srgb': + switch(colorName) { + case 'Red': + return [255, 0, 0, 255]; + case 'Green': + return [0, 255, 0, 255]; + break; + default: + throw 'unexpected color name: ' + colorName; + }; + break; + case 'display-p3': + switch(colorName) { + case 'Red': + return [234, 51, 35, 255]; + break; + case 'Green': + return [117, 251, 76, 255]; + break; + default: + throw 'unexpected color name: ' + colorName; + } + break; + default: + throw 'unexpected color space: ' + colorSpace; + } +} + +/** + * Return the named color as it would be sampled with the specified + * internal format + * @param {!Array.} color The color as an 8-bit RGBA array. + * @param {string} internalformat The internal format. + * @return {!Array.} color The color, as it would be sampled by + * the specified internal format, as an 8-bit RGBA array. + */ +var colorAsSampledWithInternalFormat = function(color, internalFormat) { + switch (internalFormat) { + case 'ALPHA': + return [0, 0, 0, color[3]]; + case 'LUMINANCE': + case 'LUMINANCE_ALPHA': + return [color[0], color[0], color[0], color[3]]; + case 'SRGB8': + case 'SRGB8_ALPHA8': + return [sRGBChannelToLinear(color[0]), + sRGBChannelToLinear(color[1]), + sRGBChannelToLinear(color[2]), + color[3]]; + case 'R16F': + case 'R32F': + case 'R8': + case 'R8UI': + case 'RED': + case 'RED_INTEGER': + return [result[0], 0, 0, 0]; + case 'RG': + case 'RG16F': + case 'RG32F': + case 'RG8': + case 'RG8UI': + case 'RG_INTEGER': + return [color[0], color[1], 0, 0]; + break; + default: + break; + } + return color; +} + function comparePixels(cmp, ref, tolerance, diff) { if (cmp.length != ref.length) { testFailed("invalid pixel size."); @@ -3516,6 +3604,10 @@ var API = { // fullscreen api setupFullscreen: setupFullscreen, + // color converter API + namedColorInColorSpace: namedColorInColorSpace, + colorAsSampledWithInternalFormat: colorAsSampledWithInternalFormat, + // sRGB converter api sRGBToLinear: sRGBToLinear, linearToSRGB: linearToSRGB, From d2e0a531432a2036193c8a2c793d9615b84939a1 Mon Sep 17 00:00:00 2001 From: Christopher Cameron Date: Wed, 27 Apr 2022 13:54:23 -0700 Subject: [PATCH 2/5] Fix lint errors --- sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js b/sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js index 92caf21ae5..ff0217e845 100644 --- a/sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js +++ b/sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js @@ -83,7 +83,7 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource gl.TEXTURE_CUBE_MAP_NEGATIVE_Z]; } // Handle target color space. - if (unpackColorSpace) { + if (unpackColorSpace) { gl.unpackColorSpace = unpackColorSpace; } // Handle the source sub-rectangle if specified (WebGL 2.0 only) From 713618060309cd73078969cc48f6fc233307c756 Mon Sep 17 00:00:00 2001 From: Christopher Cameron Date: Wed, 4 May 2022 11:49:32 -0700 Subject: [PATCH 3/5] Only test RGB, fix LUMINANCE alpha channel --- .../js/tests/tex-image-and-sub-image-2d-with-video.js | 11 ++++++++--- sdk/tests/js/webgl-test-utils.js | 1 + 2 files changed, 9 insertions(+), 3 deletions(-) diff --git a/sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js b/sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js index ff0217e845..6e8bcf96e9 100644 --- a/sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js +++ b/sdk/tests/js/tests/tex-image-and-sub-image-2d-with-video.js @@ -55,10 +55,14 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource if (sourceSubRectangle) { sourceSubRectangleString = ' sourceSubRectangle=' + sourceSubRectangle; } + unpackColorSpaceString = ''; + if (unpackColorSpace) { + unpackColorSpaceString = ' unpackColorSpace=' + unpackColorSpace; + } debug('Testing ' + (useTexSubImage2D ? 'texSubImage2D' : 'texImage2D') + ' with flipY=' + flipY + ' bindingTarget=' + (bindingTarget == gl.TEXTURE_2D ? 'TEXTURE_2D' : 'TEXTURE_CUBE_MAP') + - sourceSubRectangleString); + sourceSubRectangleString + unpackColorSpaceString); gl.clear(gl.COLOR_BUFFER_BIT | gl.DEPTH_BUFFER_BIT); // Disable any writes to the alpha channel gl.colorMask(1, 1, 1, 0); @@ -149,12 +153,13 @@ function generateTest(internalFormat, pixelFormat, pixelType, prologue, resource loc = gl.getUniformLocation(program, "face"); } + // Compute the test colors. This test only tests RGB (not A). const topColor = wtu.colorAsSampledWithInternalFormat( wtu.namedColorInColorSpace(topColorName, unpackColorSpace), - internalFormat); + internalFormat).slice(0, 3); const bottomColor = wtu.colorAsSampledWithInternalFormat( wtu.namedColorInColorSpace(bottomColorName, unpackColorSpace), - internalFormat); + internalFormat).slice(0, 3); for (var tt = 0; tt < targets.length; ++tt) { if (bindingTarget == gl.TEXTURE_CUBE_MAP) { gl.uniform1i(loc, targets[tt]); diff --git a/sdk/tests/js/webgl-test-utils.js b/sdk/tests/js/webgl-test-utils.js index 04e22cafcd..d20a853121 100644 --- a/sdk/tests/js/webgl-test-utils.js +++ b/sdk/tests/js/webgl-test-utils.js @@ -3355,6 +3355,7 @@ var colorAsSampledWithInternalFormat = function(color, internalFormat) { case 'ALPHA': return [0, 0, 0, color[3]]; case 'LUMINANCE': + return [color[0], color[0], color[0], 255]; case 'LUMINANCE_ALPHA': return [color[0], color[0], color[0], color[3]]; case 'SRGB8': From faf3fdf53e9170d7e74e61f4fccb87f8bc4d196d Mon Sep 17 00:00:00 2001 From: Christopher Cameron Date: Wed, 4 May 2022 11:52:33 -0700 Subject: [PATCH 4/5] Incorporate review feedback --- sdk/tests/js/tests/tex-image-and-sub-image-utils.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/sdk/tests/js/tests/tex-image-and-sub-image-utils.js b/sdk/tests/js/tests/tex-image-and-sub-image-utils.js index 22e0ecacb6..5dc9fc7bb1 100644 --- a/sdk/tests/js/tests/tex-image-and-sub-image-utils.js +++ b/sdk/tests/js/tests/tex-image-and-sub-image-utils.js @@ -809,9 +809,9 @@ var TexImageUtils = (function() { */ var crossProductTestCasesWithUnpackColorSpaces = function(cases, unpackColorSpaces) { - var caseWithColorSpace = function(c, cs) { return Object.assign({}, c, {unpackColorSpace:cs}); } + var caseWithColorSpace = function(c, cs) { return {...c, ...{unpackColorSpace:cs}}; } var casesList = unpackColorSpaces.map(cs => cases.map(c => caseWithColorSpace(c, cs))); - return [].concat.apply([], casesList); + return casesList.flat(); } /** From f77ed50523b5bab2e887e62f137a5bb4cd6a0db7 Mon Sep 17 00:00:00 2001 From: Christopher Cameron Date: Mon, 9 May 2022 14:15:21 -0700 Subject: [PATCH 5/5] Incorporate review feedback --- .../js/tests/tex-image-and-sub-image-utils.js | 14 +++++++++----- sdk/tests/js/webgl-test-utils.js | 9 ++++++--- 2 files changed, 15 insertions(+), 8 deletions(-) diff --git a/sdk/tests/js/tests/tex-image-and-sub-image-utils.js b/sdk/tests/js/tests/tex-image-and-sub-image-utils.js index 5dc9fc7bb1..f37f12fe91 100644 --- a/sdk/tests/js/tests/tex-image-and-sub-image-utils.js +++ b/sdk/tests/js/tests/tex-image-and-sub-image-utils.js @@ -800,18 +800,22 @@ var TexImageUtils = (function() { if ('unpackColorSpace' in gl) return ['srgb', 'display-p3']; else - return [null]; + return [undefined]; } /** * For each entry in unpackColorSpaces, duplicate all of cases, adding an * unpackColorSpace key with its value set to that entry to each case. */ - var crossProductTestCasesWithUnpackColorSpaces = function(cases, unpackColorSpaces) + var crossProductTestCasesWithUnpackColorSpaces = function(testCaseList, unpackColorSpaces) { - var caseWithColorSpace = function(c, cs) { return {...c, ...{unpackColorSpace:cs}}; } - var casesList = unpackColorSpaces.map(cs => cases.map(c => caseWithColorSpace(c, cs))); - return casesList.flat(); + var testCaseWithUnpackColorSpace = function(testCase, colorSpace) + { + return {...testCase, ...{unpackColorSpace:colorSpace}}; + } + var listOfTestCaseLists = unpackColorSpaces.map(colorSpace => + testCaseList.map(testCase => testCaseWithUnpackColorSpace(testCase, colorSpace))); + return listOfTestCaseLists.flat(); } /** diff --git a/sdk/tests/js/webgl-test-utils.js b/sdk/tests/js/webgl-test-utils.js index d20a853121..af9a7e75f5 100644 --- a/sdk/tests/js/webgl-test-utils.js +++ b/sdk/tests/js/webgl-test-utils.js @@ -3300,20 +3300,23 @@ function linearChannelToSRGB(value) { * Return the named color in the specified color space. * @param {string} colorName The name of the color to convert. * Supported color names are: - * 'Red', which is maximum sRGB red. - * 'Green', which is maximum sRGB green. + * 'Red', which is the CSS color color('srgb' 1 0 0 1) + * 'Green', which is the CSS color color('srgb' 0 1 0 1) * @param {string} colorSpace The color space to convert to. Supported color spaces are: * null, which is treated as sRGB * 'srgb' * 'display-p3'. + * Documentation on the formulas for color conversion between + * spaces can be found at + https://www.w3.org/TR/css-color-4/#predefined-to-predefined * @return {!Array.} color The color in the specified color * space as an 8-bit RGBA array with unpremultiplied alpha. */ var namedColorInColorSpace = function(colorName, colorSpace) { var result; switch (colorSpace) { - case null: + case undefined: case 'srgb': switch(colorName) { case 'Red':