Title: [268234] trunk
Revision
268234
Author
[email protected]
Date
2020-10-08 17:24:42 -0700 (Thu, 08 Oct 2020)

Log Message

Support EXT_texture_compression_rgtc WebGL extension
https://bugs.webkit.org/show_bug.cgi?id=217198

Reviewed by Kenneth Russell.

Source/WebCore:

Test: webgl/conformance/extensions/ext-texture-compression-rgtc.html

* CMakeLists.txt:
* DerivedSources-input.xcfilelist:
* DerivedSources-output.xcfilelist:
* DerivedSources.make:
* Sources.txt:
* WebCore.xcodeproj/project.pbxproj:
* bindings/js/JSDOMConvertWebGL.cpp:
(WebCore::convertToJSValue):
* html/canvas/EXTTextureCompressionRGTC.cpp: Added.
(WebCore::EXTTextureCompressionRGTC::EXTTextureCompressionRGTC):
(WebCore::EXTTextureCompressionRGTC::getName const):
* html/canvas/EXTTextureCompressionRGTC.h: Added.
* html/canvas/EXTTextureCompressionRGTC.idl: Added.
* html/canvas/WebGL2RenderingContext.cpp:
(WebCore::WebGL2RenderingContext::getExtension):
(WebCore::WebGL2RenderingContext::getSupportedExtensions):
* html/canvas/WebGLExtension.h:
* html/canvas/WebGLRenderingContext.cpp:
(WebCore::WebGLRenderingContext::getExtension):
(WebCore::WebGLRenderingContext::getSupportedExtensions):
* html/canvas/WebGLRenderingContextBase.cpp:
(WebCore::WebGLRenderingContextBase::extensionIsEnabled):
(WebCore::WebGLRenderingContextBase::validateCompressedTexFuncData):
(WebCore::WebGLRenderingContextBase::loseExtensions):
* html/canvas/WebGLRenderingContextBase.h:
* platform/graphics/ExtensionsGL.h:

LayoutTests:

* webgl/conformance/extensions/ext-texture-compression-rgtc-expected.txt: Added.
* webgl/conformance/extensions/ext-texture-compression-rgtc.html: Added.
* webgl/conformance/extensions/s3tc-and-rgtc-expected.txt: Added.
* webgl/conformance/extensions/s3tc-and-rgtc.html: Added.
* webgl/resources/webgl_test_files/conformance/extensions/ext-texture-compression-rgtc.html: Added.
* webgl/resources/webgl_test_files/conformance/extensions/s3tc-and-rgtc.html: Added.
* webgl/resources/webgl_test_files/js/tests/compressed-texture-utils.js: Added.

Modified Paths

Added Paths

Diff

Modified: trunk/LayoutTests/ChangeLog (268233 => 268234)


--- trunk/LayoutTests/ChangeLog	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/LayoutTests/ChangeLog	2020-10-09 00:24:42 UTC (rev 268234)
@@ -1,3 +1,18 @@
+2020-10-08  James Darpinian  <[email protected]>
+
+        Support EXT_texture_compression_rgtc WebGL extension
+        https://bugs.webkit.org/show_bug.cgi?id=217198
+
+        Reviewed by Kenneth Russell.
+
+        * webgl/conformance/extensions/ext-texture-compression-rgtc-expected.txt: Added.
+        * webgl/conformance/extensions/ext-texture-compression-rgtc.html: Added.
+        * webgl/conformance/extensions/s3tc-and-rgtc-expected.txt: Added.
+        * webgl/conformance/extensions/s3tc-and-rgtc.html: Added.
+        * webgl/resources/webgl_test_files/conformance/extensions/ext-texture-compression-rgtc.html: Added.
+        * webgl/resources/webgl_test_files/conformance/extensions/s3tc-and-rgtc.html: Added.
+        * webgl/resources/webgl_test_files/js/tests/compressed-texture-utils.js: Added.
+
 2020-10-08  Hector Lopez  <[email protected]>
 
         Add Mojave specific result

Added: trunk/LayoutTests/webgl/conformance/extensions/ext-texture-compression-rgtc-expected.txt (0 => 268234)


--- trunk/LayoutTests/webgl/conformance/extensions/ext-texture-compression-rgtc-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webgl/conformance/extensions/ext-texture-compression-rgtc-expected.txt	2020-10-09 00:24:42 UTC (rev 268234)
@@ -0,0 +1,4 @@
+This test runs the WebGL Test listed below in an iframe and reports PASS or FAIL.
+
+Test: ../../resources/webgl_test_files/conformance/extensions/ext-texture-compression-rgtc.html
+PASS

Added: trunk/LayoutTests/webgl/conformance/extensions/ext-texture-compression-rgtc.html (0 => 268234)


--- trunk/LayoutTests/webgl/conformance/extensions/ext-texture-compression-rgtc.html	                        (rev 0)
+++ trunk/LayoutTests/webgl/conformance/extensions/ext-texture-compression-rgtc.html	2020-10-09 00:24:42 UTC (rev 268234)
@@ -0,0 +1,18 @@
+<!-- This file is auto-generated by generate-webgl-tests.py. DO NOT EDIT -->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL Conformance Test Wrapper for ext-texture-compression-rgtc.html</title>
+<script type="text/_javascript_" src=""
+<script type="text/_javascript_" src=""
+</head>
+<body>
+<p>This test runs the WebGL Test listed below in an iframe and reports PASS or FAIL.</p>
+Test: <a href=""
+<div id="iframe">
+<iframe src="" width="800" height="600"></iframe>
+</div>
+<div id="result"></div>
+</body>
+</html>

Added: trunk/LayoutTests/webgl/conformance/extensions/s3tc-and-rgtc-expected.txt (0 => 268234)


--- trunk/LayoutTests/webgl/conformance/extensions/s3tc-and-rgtc-expected.txt	                        (rev 0)
+++ trunk/LayoutTests/webgl/conformance/extensions/s3tc-and-rgtc-expected.txt	2020-10-09 00:24:42 UTC (rev 268234)
@@ -0,0 +1,4 @@
+This test runs the WebGL Test listed below in an iframe and reports PASS or FAIL.
+
+Test: ../../resources/webgl_test_files/conformance/extensions/s3tc-and-rgtc.html
+PASS

Added: trunk/LayoutTests/webgl/conformance/extensions/s3tc-and-rgtc.html (0 => 268234)


--- trunk/LayoutTests/webgl/conformance/extensions/s3tc-and-rgtc.html	                        (rev 0)
+++ trunk/LayoutTests/webgl/conformance/extensions/s3tc-and-rgtc.html	2020-10-09 00:24:42 UTC (rev 268234)
@@ -0,0 +1,18 @@
+<!-- This file is auto-generated by generate-webgl-tests.py. DO NOT EDIT -->
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL Conformance Test Wrapper for s3tc-and-rgtc.html</title>
+<script type="text/_javascript_" src=""
+<script type="text/_javascript_" src=""
+</head>
+<body>
+<p>This test runs the WebGL Test listed below in an iframe and reports PASS or FAIL.</p>
+Test: <a href=""
+<div id="iframe">
+<iframe src="" width="800" height="600"></iframe>
+</div>
+<div id="result"></div>
+</body>
+</html>

Added: trunk/LayoutTests/webgl/resources/webgl_test_files/conformance/extensions/ext-texture-compression-rgtc.html (0 => 268234)


--- trunk/LayoutTests/webgl/resources/webgl_test_files/conformance/extensions/ext-texture-compression-rgtc.html	                        (rev 0)
+++ trunk/LayoutTests/webgl/resources/webgl_test_files/conformance/extensions/ext-texture-compression-rgtc.html	2020-10-09 00:24:42 UTC (rev 268234)
@@ -0,0 +1,146 @@
+<!--
+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.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<title>WebGL EXT_texture_compression_rgtc Conformance Tests</title>
+<LINK rel="stylesheet" href=""
+<script src=""
+<script src=""
+<script src=""
+</head>
+<body>
+<div id="description"></div>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the EXT_texture_compression_rgtc extension, if it is available.");
+
+debug("");
+
+var validFormats = {
+  COMPRESSED_RED_RGTC1_EXT: 0x8DBB,
+  COMPRESSED_SIGNED_RED_RGTC1_EXT: 0x8DBC,
+  COMPRESSED_RED_GREEN_RGTC2_EXT: 0x8DBD,
+  COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: 0x8DBE
+};
+
+function expectedByteLength(width, height, format) {
+  if (format == validFormats.COMPRESSED_RED_RGTC1_EXT || format == validFormats.COMPRESSED_SIGNED_RED_RGTC1_EXT) {
+    return Math.ceil(width / 4) * Math.ceil(height / 4) * 8;
+  }
+  else {
+    return Math.ceil(width / 4) * Math.ceil(height / 4) * 16;
+  }
+}
+
+function getBlockDimensions(format) {
+  return {width: 4, height: 4};
+}
+
+var wtu = WebGLTestUtils;
+var ctu = CompressedTextureUtils;
+var contextVersion = wtu.getDefault3DContextVersion();
+var gl = wtu.create3DContext();
+var ext;
+
+var formats = null;
+
+function runTestExtension() {
+  // Test that enum values are listed correctly in supported formats and in the extension object.
+  ctu.testCompressedFormatsListed(gl, validFormats);
+  ctu.testCorrectEnumValuesInExt(ext, validFormats);
+  // Test that texture upload buffer size is validated correctly.
+  ctu.testFormatRestrictionsOnBufferSize(gl, validFormats, expectedByteLength, getBlockDimensions);
+  // Test TexSubImage validation on dimensions
+  // CompressedTexSubImage* will result in an
+  // INVALID_OPERATION error only if one of the following conditions occurs:
+  // * <width> is not a multiple of four, and <width> plus <xoffset> is not
+  // equal to TEXTURE_WIDTH;
+  // * <height> is not a multiple of four, and <height> plus <yoffset> is
+  //           not equal to TEXTURE_HEIGHT; or
+  // * <xoffset> or <yoffset> is not a multiple of four.
+  ctu.testTexSubImageDimensions(gl, validFormats, expectedByteLength, getBlockDimensions,
+    16, 16, [
+      { xoffset: 0, yoffset: 0, width: 4, height: 3,
+        expectation: gl.INVALID_OPERATION, message: "height is not a multiple of 4" },
+      { xoffset: 0, yoffset: 0, width: 3, height: 4,
+        expectation: gl.INVALID_OPERATION, message: "width is not a multiple of 4" },
+      { xoffset: 1, yoffset: 0, width: 4, height: 4,
+        expectation: gl.INVALID_OPERATION, message: "xoffset is not a multiple of 4" },
+      { xoffset: 0, yoffset: 1, width: 4, height: 4,
+        expectation: gl.INVALID_OPERATION, message: "yoffset is not a multiple of 4" },
+      { xoffset: 12, yoffset: 12, width: 4, height: 4,
+        expectation: gl.NO_ERROR, message: "is valid" },
+  ]);
+
+  // Test TexImage validation on level dimensions combinations.
+  // When level equals 0, width and height must be a multiple of 4.
+  // When level is larger than 0, this constraint doesn't apply.
+  ctu.testTexImageLevelDimensions(gl, validFormats, expectedByteLength, getBlockDimensions,
+    [
+      { level: 0, width: 4, height: 3,
+        expectation: gl.INVALID_OPERATION, message: "level is 0, height is not a multiple of 4" },
+      { level: 0, width: 3, height: 4,
+        expectation: gl.INVALID_OPERATION, message: "level is 0, width is not a multiple of 4" },
+      { level: 0, width: 2, height: 2,
+        expectation: gl.INVALID_OPERATION, message: "level is 0, width is not a multiple of 4" },
+      { level: 0, width: 4, height: 4,
+        expectation: gl.NO_ERROR, message: "is valid" },
+      { level: 1, width: 2, height: 2,
+        expectation: gl.NO_ERROR, message: "level > 0, is valid" },
+      { level: 2, width: 1, height: 1,
+        expectation: gl.NO_ERROR, message: "level > 0, is valid" },
+  ]);
+
+  // Test that RGTC enums are not accepted by texImage2D
+  if (contextVersion >= 2) {
+    var tex = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, tex);
+
+    gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RED_RGTC1_EXT, 4, 4, 0, gl.RED, gl.UNSIGNED_BYTE, null);
+    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_RED_RGTC1_EXT fails with texImage2D");
+
+    gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_SIGNED_RED_RGTC1_EXT, 4, 4, 0, gl.RED, gl.BYTE, null);
+    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_SIGNED_RED_RGTC1_EXT fails with texImage2D");
+
+    gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_RED_GREEN_RGTC2_EXT, 4, 4, 0, gl.RG, gl.UNSIGNED_BYTE, null);
+    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_RED_GREEN_RGTC2_EXT fails with texImage2D");
+
+    gl.texImage2D(gl.TEXTURE_2D, 0, ext.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT, 4, 4, 0, gl.RG, gl.BYTE, null);
+    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT fails with texImage2D");
+
+    gl.deleteTexture(tex);
+  }
+};
+
+function runTest() {
+  if (!gl) {
+    testFailed("context does not exist");
+  } else {
+    testPassed("context exists");
+
+    ctu.testCompressedFormatsUnavailableWhenExtensionDisabled(gl, validFormats, expectedByteLength, 4);
+
+    ext = gl.getExtension("EXT_texture_compression_rgtc");
+
+    wtu.runExtensionSupportedTest(gl, "EXT_texture_compression_rgtc", ext !== null);
+
+    if (ext !== null) {
+      runTestExtension();
+    }
+  }
+}
+
+runTest();
+
+var successfullyParsed = true;
+</script>
+<script src=""
+</body>
+</html>

Added: trunk/LayoutTests/webgl/resources/webgl_test_files/conformance/extensions/s3tc-and-rgtc.html (0 => 268234)


--- trunk/LayoutTests/webgl/resources/webgl_test_files/conformance/extensions/s3tc-and-rgtc.html	                        (rev 0)
+++ trunk/LayoutTests/webgl/resources/webgl_test_files/conformance/extensions/s3tc-and-rgtc.html	2020-10-09 00:24:42 UTC (rev 268234)
@@ -0,0 +1,976 @@
+<!--
+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.
+-->
+
+<!DOCTYPE html>
+<html>
+<head>
+<meta charset="utf-8">
+<link rel="stylesheet" href=""
+<script src=""
+<script src=""
+<script src=""
+<title>WebGL WEBGL_compressed_texture_s3tc and EXT_texture_compression_rgtc Conformance Tests</title>
+<style>
+img {
+ border: 1px solid black;
+ margin-right: 1em;
+}
+
+.testimages br {
+  clear: both;
+}
+
+.testimages > div {
+  float: left;
+  margin: 1em;
+}
+</style>
+</head>
+<body>
+<div id="description"></div>
+<canvas id="canvas" width="8" height="8" style="width: 8px; height: 8px;"></canvas>
+<div id="console"></div>
+<script>
+"use strict";
+description("This test verifies the functionality of the WEBGL_compressed_texture_s3tc extension, if it is available. It also tests the related formats from the EXT_texture_compression_rgtc extension.");
+
+debug("");
+
+/*
+BC1 (DXT1) block
+e0 = [  0, 255, 0]
+e1 = [255,   0, 0]
+e0 < e1, so it uses 3-color mode
+
+local palette
+    0: [  0, 255, 0, 255]
+    1: [255,   0, 0, 255]
+    2: [128, 128, 0, 255]
+    3: [  0,   0, 0, 255] // for BC1 RGB
+    3: [  0,   0, 0,   0] // for BC1 RGBA
+selectors
+    3 2 1 0
+    2 2 1 0
+    1 1 1 0
+    0 0 0 0
+
+Extending this block with opaque alpha and uploading as BC2 or BC3
+will generate wrong colors because BC2 and BC3 do not have 3-color mode.
+*/
+var img_4x4_rgba_dxt1 = new Uint8Array([
+    0xE0, 0x07, 0x00, 0xF8, 0x1B, 0x1A, 0x15, 0x00
+]);
+
+/*
+BC2 (DXT3) block
+
+Quantized alpha values
+    0 1 2 3
+    4 5 6 7
+    8 9 A B
+    C D E F
+
+RGB block
+e0 = [255,   0, 0]
+e1 = [  0, 255, 0]
+BC2 has only 4-color mode
+
+local palette
+    0: [255,   0, 0]
+    1: [  0, 255, 0]
+    2: [170,  85, 0]
+    3: [ 85, 170, 0]
+selectors
+    0 1 2 3
+    1 1 2 3
+    2 2 2 3
+    3 3 3 3
+*/
+var img_4x4_rgba_dxt3 = new Uint8Array([
+    0x10, 0x32, 0x54, 0x76, 0x98, 0xBA, 0xDC, 0xFE,
+    0x00, 0xF8, 0xE0, 0x07, 0xE4, 0xE5, 0xEA, 0xFF
+]);
+
+/*
+BC3 (DXT5) block
+
+Alpha block (aka DXT5A)
+e0 = 255
+e1 = 0
+e0 > e1, so using 6 intermediate points
+local palette
+    255, 0, 219, 182, 146, 109, 73, 36
+selectors
+    0 1 2 3
+    1 2 3 4
+    2 3 4 5
+    3 4 5 6
+
+RGB block
+e0 = [255,   0, 0]
+e1 = [  0, 255, 0]
+BC3 has only 4-color mode
+
+local palette
+    0: [255,   0, 0]
+    1: [  0, 255, 0]
+    2: [170,  85, 0]
+    3: [ 85, 170, 0]
+selectors
+    3 2 1 0
+    3 2 1 1
+    3 2 2 2
+    3 3 3 3
+*/
+var img_4x4_rgba_dxt5 = new Uint8Array([
+    0xFF, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+    0x00, 0xF8, 0xE0, 0x07, 0x1B, 0x5B, 0xAB, 0xFF
+]);
+
+// BC4 - just the alpha block from BC3 above, interpreted as the red channel.
+// See http://www.reedbeta.com/blog/understanding-bcn-texture-compression-formats/#bc4
+// for format details.
+var img_4x4_r_bc4 = new Uint8Array([
+    0xFF, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+]);
+
+// BC5 - Two BC3 alpha blocks, interpreted as the red and green channels.
+var img_4x4_rg_bc5 = new Uint8Array([
+    0xFF, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+    0x00, 0xFF, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+]);
+
+// Signed BC4 - change endpoints to use full -1 to 1 range.
+var img_4x4_signed_r_bc4 = new Uint8Array([
+    0x7F, 0x80, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+]);
+
+// Signed BC5 - Two BC3 alpha blocks, interpreted as the red and green channels.
+var img_4x4_signed_rg_bc5 = new Uint8Array([
+    0x7F, 0x80, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+    0x80, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+]);
+
+
+/*
+8x8 block endpoints use half-intensity values (appear darker than 4x4)
+*/
+var img_8x8_rgba_dxt1 = new Uint8Array([
+    0xe0,0x03,0x00,0x78,0x13,0x10,0x15,0x00,
+    0x0f,0x00,0xe0,0x7b,0x11,0x10,0x15,0x00,
+    0xe0,0x03,0x0f,0x78,0x44,0x45,0x40,0x55,
+    0x0f,0x00,0xef,0x03,0x44,0x45,0x40,0x55
+]);
+var img_8x8_rgba_dxt3 = new Uint8Array([
+    0xf6,0xff,0xf6,0xff,0xff,0xff,0xff,0xff,0x00,0x78,0xe0,0x03,0x44,0x45,0x40,0x55,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xe0,0x7b,0x0f,0x00,0x44,0x45,0x40,0x55,
+    0xff,0xff,0xff,0xff,0xf6,0xff,0xf6,0xff,0x0f,0x78,0xe0,0x03,0x11,0x10,0x15,0x00,
+    0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xef,0x03,0x0f,0x00,0x11,0x10,0x15,0x00
+]);
+var img_8x8_rgba_dxt5 = new Uint8Array([
+    0xff,0x69,0x01,0x10,0x00,0x00,0x00,0x00,0x00,0x78,0xe0,0x03,0x44,0x45,0x40,0x55,
+    0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xe0,0x7b,0x0f,0x00,0x44,0x45,0x40,0x55,
+    0xff,0x69,0x00,0x00,0x00,0x01,0x10,0x00,0x0f,0x78,0xe0,0x03,0x11,0x10,0x15,0x00,
+    0xff,0xff,0x00,0x00,0x00,0x00,0x00,0x00,0xef,0x03,0xef,0x00,0x11,0x10,0x15,0x00
+]);
+var img_8x8_r_bc4 = new Uint8Array([
+    0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+    0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+    0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+    0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+]);
+var img_8x8_rg_bc5 = new Uint8Array([
+    0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6, 0x00, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+    0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6, 0x00, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+    0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6, 0x00, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+    0x7F, 0x00, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6, 0x00, 0x7F, 0x88, 0x16, 0x8D, 0x1A, 0x3B, 0xD6,
+]);
+
+var wtu = WebGLTestUtils;
+var ctu = CompressedTextureUtils;
+var contextVersion = wtu.getDefault3DContextVersion();
+var canvas = document.getElementById("canvas");
+var gl = wtu.create3DContext(canvas, {antialias: false});
+var program = wtu.setupTexturedQuad(gl);
+var ext = null;
+var ext_rgtc = {};
+var vao = null;
+var validFormats = {
+    COMPRESSED_RGB_S3TC_DXT1_EXT  : 0x83F0,
+    COMPRESSED_RGBA_S3TC_DXT1_EXT : 0x83F1,
+    COMPRESSED_RGBA_S3TC_DXT3_EXT : 0x83F2,
+    COMPRESSED_RGBA_S3TC_DXT5_EXT : 0x83F3,
+};
+var name;
+var supportedFormats;
+
+if (!gl) {
+    testFailed("WebGL context does not exist");
+} else {
+    testPassed("WebGL context exists");
+
+    // Run tests with extension disabled
+    ctu.testCompressedFormatsUnavailableWhenExtensionDisabled(gl, validFormats, expectedByteLength, 4);
+
+    // Query the extension and store globally so shouldBe can access it
+    ext = wtu.getExtensionWithKnownPrefixes(gl, "WEBGL_compressed_texture_s3tc");
+    if (!ext) {
+        testPassed("No WEBGL_compressed_texture_s3tc support -- this is legal");
+        wtu.runExtensionSupportedTest(gl, "WEBGL_compressed_texture_s3tc", false);
+    } else {
+        testPassed("Successfully enabled WEBGL_compressed_texture_s3tc extension");
+
+        wtu.runExtensionSupportedTest(gl, "WEBGL_compressed_texture_s3tc", true);
+        runTestExtension();
+    }
+    ext_rgtc = wtu.getExtensionWithKnownPrefixes(gl, "EXT_texture_compression_rgtc");
+    if (ext_rgtc) {
+        ext = ext || {};
+        // Make ctu.formatToString work for rgtc enums.
+        for (const name in ext_rgtc)
+            ext[name] = ext_rgtc[name];
+        runTestRGTC();
+    }
+}
+
+function expectedByteLength(width, height, format) {
+    if (format == validFormats.COMPRESSED_RGBA_S3TC_DXT3_EXT || format == validFormats.COMPRESSED_RGBA_S3TC_DXT5_EXT) {
+        return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 16;
+    }
+    return Math.floor((width + 3) / 4) * Math.floor((height + 3) / 4) * 8;
+}
+
+function getBlockDimensions(format) {
+    return {width: 4, height: 4};
+}
+
+function runTestExtension() {
+    debug("");
+    debug("Testing WEBGL_compressed_texture_s3tc");
+
+    // Test that enum values are listed correctly in supported formats and in the extension object.
+    ctu.testCompressedFormatsListed(gl, validFormats);
+    ctu.testCorrectEnumValuesInExt(ext, validFormats);
+    // Test that texture upload buffer size is validated correctly.
+    ctu.testFormatRestrictionsOnBufferSize(gl, validFormats, expectedByteLength, getBlockDimensions);
+
+    // Test each format
+    testDXT1_RGB();
+    testDXT1_RGBA();
+    testDXT3_RGBA();
+    testDXT5_RGBA();
+
+    // Test compressed PBOs with a single format
+    if (contextVersion >= 2) {
+        testDXT5_RGBA_PBO();
+    }
+}
+
+function runTestRGTC() {
+    var tests = [
+        {   width: 4,
+            height: 4,
+            channels: 1,
+            data: img_4x4_r_bc4,
+            format: ext_rgtc.COMPRESSED_RED_RGTC1_EXT,
+            hasAlpha: false,
+        },
+        {   width: 4,
+            height: 4,
+            channels: 1,
+            data: img_4x4_signed_r_bc4,
+            format: ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT,
+            hasAlpha: false,
+        },
+        {   width: 4,
+            height: 4,
+            channels: 2,
+            data: img_4x4_rg_bc5,
+            format: ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT,
+            hasAlpha: false,
+        },
+        {   width: 4,
+            height: 4,
+            channels: 2,
+            data: img_4x4_signed_rg_bc5,
+            format: ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT,
+            hasAlpha: false,
+        },
+        {   width: 8,
+            height: 8,
+            channels: 2,
+            data: img_8x8_r_bc4,
+            format: ext_rgtc.COMPRESSED_RED_RGTC1_EXT,
+            hasAlpha: false,
+            subX0: 0,
+            subY0: 0,
+            subWidth: 4,
+            subHeight: 4,
+            subData: img_4x4_r_bc4,
+        },
+        {   width: 8,
+            height: 8,
+            channels: 2,
+            data: img_8x8_rg_bc5,
+            format: ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT,
+            hasAlpha: false,
+            subX0: 0,
+            subY0: 0,
+            subWidth: 4,
+            subHeight: 4,
+            subData: img_4x4_rg_bc5,
+        },
+    ];
+    testDXTTextures(tests);
+}
+
+function testDXT1_RGB() {
+    var tests = [
+        {   width: 4,
+            height: 4,
+            channels: 3,
+            data: img_4x4_rgba_dxt1,
+            format: ext.COMPRESSED_RGB_S3TC_DXT1_EXT,
+            hasAlpha: false,
+        },
+        {   width: 8,
+            height: 8,
+            channels: 3,
+            data: img_8x8_rgba_dxt1,
+            format: ext.COMPRESSED_RGB_S3TC_DXT1_EXT,
+            hasAlpha: false,
+            subX0: 0,
+            subY0: 0,
+            subWidth: 4,
+            subHeight: 4,
+            subData: img_4x4_rgba_dxt1
+        }
+    ];
+    testDXTTextures(tests);
+}
+
+function testDXT1_RGBA() {
+    var tests = [
+        {   width: 4,
+            height: 4,
+            channels: 4,
+            data: img_4x4_rgba_dxt1,
+            format: ext.COMPRESSED_RGBA_S3TC_DXT1_EXT,
+            // This is a special case -- the texture is still opaque
+            // though it's RGBA.
+            hasAlpha: false,
+        },
+        {   width: 8,
+            height: 8,
+            channels: 4,
+            data: img_8x8_rgba_dxt1,
+            format: ext.COMPRESSED_RGBA_S3TC_DXT1_EXT,
+            // This is a special case -- the texture is still opaque
+            // though it's RGBA.
+            hasAlpha: false,
+        }
+    ];
+    testDXTTextures(tests);
+}
+
+function testDXT3_RGBA() {
+    var tests = [
+        {   width: 4,
+            height: 4,
+            channels: 4,
+            data: img_4x4_rgba_dxt3,
+            format: ext.COMPRESSED_RGBA_S3TC_DXT3_EXT,
+            hasAlpha: true,
+        },
+        {   width: 8,
+            height: 8,
+            channels: 4,
+            data: img_8x8_rgba_dxt3,
+            format: ext.COMPRESSED_RGBA_S3TC_DXT3_EXT,
+            hasAlpha: true,
+            subX0: 0,
+            subY0: 0,
+            subWidth: 4,
+            subHeight: 4,
+            subData: img_4x4_rgba_dxt3
+        }
+    ];
+    testDXTTextures(tests);
+}
+
+function testDXT5_RGBA() {
+    var tests = [
+        {   width: 4,
+            height: 4,
+            channels: 4,
+            data: img_4x4_rgba_dxt5,
+            format: ext.COMPRESSED_RGBA_S3TC_DXT5_EXT,
+            hasAlpha: true,
+        },
+        {   width: 8,
+            height: 8,
+            channels: 4,
+            data: img_8x8_rgba_dxt5,
+            format: ext.COMPRESSED_RGBA_S3TC_DXT5_EXT,
+            hasAlpha: true,
+            subX0: 0,
+            subY0: 0,
+            subWidth: 4,
+            subHeight: 4,
+            subData: img_4x4_rgba_dxt5
+        }
+    ];
+    testDXTTextures(tests);
+}
+
+function testDXTTextures(tests) {
+    debug("<hr/>");
+    for (var ii = 0; ii < tests.length; ++ii) {
+        testDXTTexture(tests[ii], false);
+        if (contextVersion >= 2) {
+            debug("<br/>");
+            testDXTTexture(tests[ii], true);
+        }
+    }
+}
+
+function uncompressDXTBlock(
+    destBuffer, destX, destY, destWidth, src, srcOffset, format) {
+    // Decoding routines follow D3D11 functional spec wrt
+    // endpoints unquantization and interpolation.
+    // Some hardware may produce slightly different values - it's normal.
+
+    function make565(src, offset) {
+        return src[offset + 0] + (src[offset + 1] << 8);
+    }
+    function make8888From565(c) {
+        // These values exactly match hw decoder when selectors are 0 or 1.
+        function replicateBits(v, w) {
+           return (v << (8 - w)) | (v >> (w + w - 8));
+        }
+        return [
+                replicateBits((c >> 11) & 0x1F, 5),
+                replicateBits((c >>  5) & 0x3F, 6),
+                replicateBits((c >>  0) & 0x1F, 5),
+                255
+            ];
+    }
+    function mix(mult, c0, c1, div) {
+        var r = [];
+        for (var ii = 0; ii < c0.length; ++ii) {
+            // For green channel (6 bits), this interpolation exactly matches hw decoders
+
+            // For red and blue channels (5 bits), this interpolation exactly
+            // matches only some hw decoders and stays within acceptable range for others.
+            r[ii] = Math.floor((c0[ii] * mult + c1[ii]) / div + 0.5);
+        }
+        return r;
+    }
+    var isBC45 = ext_rgtc &&
+        (format == ext_rgtc.COMPRESSED_RED_RGTC1_EXT ||
+         format == ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT ||
+         format == ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT ||
+         format == ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT);
+    if (!isBC45) {
+        var isDXT1 = format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT ||
+                     format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
+        var colorOffset = srcOffset + (isDXT1 ? 0 : 8);
+        var color0 = make565(src, colorOffset + 0);
+        var color1 = make565(src, colorOffset + 2);
+        var c0gtc1 = color0 > color1 || !isDXT1;
+        var rgba0 = make8888From565(color0);
+        var rgba1 = make8888From565(color1);
+        var colors = [
+                rgba0,
+                rgba1,
+                c0gtc1 ? mix(2, rgba0, rgba1, 3) : mix(1, rgba0, rgba1, 2),
+                c0gtc1 ? mix(2, rgba1, rgba0, 3) : [0, 0, 0, 255]
+            ];
+    }
+    const isSigned = ext_rgtc && (format == ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT || format == ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT);
+    const signedSrc = new Int8Array(src);
+
+    // yea I know there is a lot of math in this inner loop.
+    // so sue me.
+    for (var yy = 0; yy < 4; ++yy) {
+        var pixels = src[colorOffset + 4 + yy];
+        for (var xx = 0; xx < 4; ++xx) {
+            var dstOff = ((destY + yy) * destWidth + destX + xx) * 4;
+            if (!isBC45) {
+                var code = (pixels >> (xx * 2)) & 0x3;
+                var srcColor = colors[code];
+            }
+            var alpha;
+            var rgChannel2 = 0;
+            let decodeAlpha = (offset) => {
+                let alpha;
+                var alpha0 = (isSigned ? signedSrc : src)[offset + 0];
+                var alpha1 = (isSigned ? signedSrc : src)[offset + 1];
+                var alphaOff = (yy >> 1) * 3 + 2;
+                var alphaBits =
+                     src[offset + alphaOff + 0] +
+                     src[offset + alphaOff + 1] * 256 +
+                     src[offset + alphaOff + 2] * 65536;
+                var alphaShift = (yy % 2) * 12 + xx * 3;
+                var alphaCode = (alphaBits >> alphaShift) & 0x7;
+                if (alpha0 > alpha1) {
+                    switch (alphaCode) {
+                    case 0:
+                        alpha = alpha0;
+                        break;
+                    case 1:
+                        alpha = alpha1;
+                        break;
+                    default:
+                        alpha = Math.floor(((8 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 7.0 + 0.5);
+                        break;
+                    }
+                } else {
+                    switch (alphaCode) {
+                    case 0:
+                        alpha = alpha0;
+                        break;
+                    case 1:
+                        alpha = alpha1;
+                        break;
+                    case 6:
+                        alpha = 0;
+                        break;
+                    case 7:
+                        alpha = 255;
+                        break;
+                    default:
+                        alpha = Math.floor(((6 - alphaCode) * alpha0 + (alphaCode - 1) * alpha1) / 5.0 + 0.5);
+                        break;
+                    }
+                }
+                return alpha;
+            }
+
+            switch (format) {
+            case ext.COMPRESSED_RGB_S3TC_DXT1_EXT:
+                alpha = 255;
+                break;
+            case ext.COMPRESSED_RGBA_S3TC_DXT1_EXT:
+                alpha = (code == 3 && !c0gtc1) ? 0 : 255;
+                break;
+            case ext.COMPRESSED_RGBA_S3TC_DXT3_EXT:
+                {
+                    var alpha0 = src[srcOffset + yy * 2 + (xx >> 1)];
+                    var alpha1 = (alpha0 >> ((xx % 2) * 4)) & 0xF;
+                    alpha = alpha1 | (alpha1 << 4);
+                }
+                break;
+            case ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT:
+            case ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
+                rgChannel2 = decodeAlpha(srcOffset + 8);
+                // FALLTHROUGH
+            case ext.COMPRESSED_RGBA_S3TC_DXT5_EXT:
+            case ext_rgtc.COMPRESSED_RED_RGTC1_EXT:
+            case ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT:
+                alpha = decodeAlpha(srcOffset);
+                break;
+            default:
+                throw "bad format";
+            }
+            if (isBC45) {
+                destBuffer[dstOff + 0] = alpha;
+                destBuffer[dstOff + 1] = rgChannel2;
+                destBuffer[dstOff + 2] = 0;
+                destBuffer[dstOff + 3] = 255;
+                if (isSigned) {
+                    destBuffer[dstOff + 0] = Math.max(0, alpha) * 2;
+                    destBuffer[dstOff + 1] = Math.max(0, rgChannel2) * 2;
+                }
+            } else {
+                destBuffer[dstOff + 0] = srcColor[0];
+                destBuffer[dstOff + 1] = srcColor[1];
+                destBuffer[dstOff + 2] = srcColor[2];
+                destBuffer[dstOff + 3] = alpha;
+            }
+        }
+    }
+}
+
+function getBlockSize(format) {
+  var isDXT1 = format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT ||
+               format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
+  var isBC4 = ext_rgtc && (format == ext_rgtc.COMPRESSED_RED_RGTC1_EXT || format == ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT);
+  return isDXT1 || isBC4 ? 8 : 16;
+}
+
+function uncompressDXT(width, height, data, format) {
+    if (width % 4 || height % 4) throw "bad width or height";
+
+    var dest = new Uint8Array(width * height * 4);
+    var blocksAcross = width / 4;
+    var blocksDown = height / 4;
+    var blockSize = getBlockSize(format);
+    for (var yy = 0; yy < blocksDown; ++yy) {
+        for (var xx = 0; xx < blocksAcross; ++xx) {
+            uncompressDXTBlock(
+                dest, xx * 4, yy * 4, width, data,
+                (yy * blocksAcross + xx) * blockSize, format);
+        }
+    }
+    return dest;
+}
+
+function uncompressDXTIntoSubRegion(width, height, subX0, subY0, subWidth, subHeight, data, format)
+{
+    if (width % 4 || height % 4 || subX0 % 4 || subY0 % 4 || subWidth % 4 || subHeight % 4)
+        throw "bad dimension";
+
+    var dest = new Uint8Array(width * height * 4);
+    // Zero-filled DXT1 or BC4/5 texture represents [0, 0, 0, 255]
+    if (format == ext.COMPRESSED_RGB_S3TC_DXT1_EXT || format == ext.COMPRESSED_RGBA_S3TC_DXT1_EXT ||
+        format == ext.COMPRESSED_RED_RGTC1_EXT || format == ext.COMPRESSED_SIGNED_RED_RGTC1_EXT ||
+        format == ext.COMPRESSED_RED_GREEN_RGTC2_EXT || format == ext.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT) {
+        for (var i = 3; i < dest.length; i += 4) dest[i] = 255;
+    }
+    var blocksAcross = subWidth / 4;
+    var blocksDown = subHeight / 4;
+    var blockSize = getBlockSize(format);
+    for (var yy = 0; yy < blocksDown; ++yy) {
+        for (var xx = 0; xx < blocksAcross; ++xx) {
+            uncompressDXTBlock(
+                dest, subX0 + xx * 4, subY0 + yy * 4, width, data,
+                (yy * blocksAcross + xx) * blockSize, format);
+        }
+    }
+    return dest;
+}
+
+function copyRect(data, srcX, srcY, dstX, dstY, width, height, stride) {
+  var bytesPerLine = width * 4;
+  var srcOffset = srcX * 4 + srcY * stride;
+  var dstOffset = dstX * 4 + dstY * stride;
+  for (; height > 0; --height) {
+    for (var ii = 0; ii < bytesPerLine; ++ii) {
+      data[dstOffset + ii] = data[srcOffset + ii];
+    }
+    srcOffset += stride;
+    dstOffset += stride;
+  }
+}
+
+function testDXTTexture(test, useTexStorage) {
+    var data = "" Uint8Array(test.data);
+    var width = test.width;
+    var height = test.height;
+    var format = test.format;
+
+    var uncompressedData = uncompressDXT(width, height, data, format);
+
+    canvas.width = width;
+    canvas.height = height;
+    gl.viewport(0, 0, width, height);
+    debug("testing " + ctu.formatToString(ext, format) + " " + width + "x" + height +
+          (useTexStorage ? " via texStorage2D" : " via compressedTexImage2D"));
+
+    var tex = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, tex);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+    if (useTexStorage) {
+        if (test.subData) {
+            var uncompressedDataSub = uncompressDXTIntoSubRegion(
+                width, height, test.subX0, test.subY0, test.subWidth, test.subHeight, test.subData, format);
+            var tex1 = gl.createTexture();
+            gl.bindTexture(gl.TEXTURE_2D, tex1);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_S, gl.CLAMP_TO_EDGE);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_WRAP_T, gl.CLAMP_TO_EDGE);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+
+            gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
+            wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating compressed texture via texStorage2D");
+            gl.compressedTexSubImage2D(
+                gl.TEXTURE_2D, 0, test.subX0, test.subY0, test.subWidth, test.subHeight, format, test.subData);
+            wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture data via compressedTexSubImage2D");
+
+            wtu.clearAndDrawUnitQuad(gl);
+            wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad 1");
+            compareRect(width, height, test.channels, uncompressedDataSub, "NEAREST");
+
+            // Clean up and recover
+            gl.deleteTexture(tex1);
+            gl.bindTexture(gl.TEXTURE_2D, tex);
+        }
+
+        gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
+        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "allocating compressed texture via texStorage2D");
+        wtu.clearAndDrawUnitQuad(gl);
+        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+        var clearColor = (test.hasAlpha ? [0, 0, 0, 0] : [0, 0, 0, 255]);
+        wtu.checkCanvas(gl, clearColor, "texture should be initialized to black");
+        gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data);
+        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture data via compressedTexSubImage2D");
+    } else {
+        gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
+        wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
+    }
+    gl.generateMipmap(gl.TEXTURE_2D);
+    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "trying to generate mipmaps from compressed texture");
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "after clearing generateMipmap error");
+    wtu.clearAndDrawUnitQuad(gl);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad 1");
+    compareRect(width, height, test.channels, uncompressedData, "NEAREST");
+    // Test again with linear filtering.
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+    gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+    wtu.clearAndDrawUnitQuad(gl);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad 2");
+    compareRect(width, height, test.channels, uncompressedData, "LINEAR");
+
+    if (!useTexStorage) {
+        // It's not allowed to redefine textures defined via texStorage2D.
+        gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 1, data);
+        wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "non 0 border");
+
+        gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width + 4, height, 0, data);
+        wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+        gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height + 4, 0, data);
+        wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+        gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 4, height, 0, data);
+        wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+        gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 4, 0, data);
+        wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+
+        gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 1, height, 0, data);
+        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+        gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 2, height, 0, data);
+        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+        gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 1, 0, data);
+        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+        gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 2, 0, data);
+        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+
+        if (width == 4) {
+            gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 1, height, 0, data);
+            wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
+            gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 2, height, 0, data);
+            wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
+        }
+        if (height == 4) {
+            gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 1, 0, data);
+            wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
+            gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 2, 0, data);
+            wtu.glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
+        }
+    }
+
+    // pick a wrong format that uses the same amount of data.
+    var wrongFormat;
+    switch (format) {
+    case ext.COMPRESSED_RGB_S3TC_DXT1_EXT:
+      wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT1_EXT;
+      break;
+    case ext.COMPRESSED_RGBA_S3TC_DXT1_EXT:
+      wrongFormat = ext.COMPRESSED_RGB_S3TC_DXT1_EXT;
+      break;
+    case ext.COMPRESSED_RGBA_S3TC_DXT3_EXT:
+      wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
+      break;
+    case ext.COMPRESSED_RGBA_S3TC_DXT5_EXT:
+      wrongFormat = ext.COMPRESSED_RGBA_S3TC_DXT3_EXT;
+      break;
+    case ext_rgtc.COMPRESSED_RED_RGTC1_EXT:
+    case ext_rgtc.COMPRESSED_SIGNED_RED_RGTC1_EXT:
+      wrongFormat = ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT;
+      break;
+    case ext_rgtc.COMPRESSED_RED_GREEN_RGTC2_EXT:
+    case ext_rgtc.COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT:
+      wrongFormat = ext_rgtc.COMPRESSED_RED_RGTC1_EXT;
+      break;
+    }
+
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, wrongFormat, data);
+    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "format does not match");
+
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 4, 0, width, height, format, data);
+    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "dimension out of range");
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 4, width, height, format, data);
+    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "dimension out of range");
+
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width + 4, height, format, data);
+    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height + 4, format, data);
+    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 4, height, format, data);
+    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 4, format, data);
+    wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
+
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 1, height, format, data);
+    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 2, height, format, data);
+    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 1, format, data);
+    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 2, format, data);
+    wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
+
+    var subData = new Uint8Array(data.buffer, 0, getBlockSize(format));
+
+    if (width == 8 && height == 8) {
+        gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 1, 0, 4, 4, format, subData);
+        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset");
+        gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 1, 4, 4, format, subData);
+        wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset");
+    }
+
+    var stride = width * 4;
+    for (var yoff = 0; yoff < height; yoff += 4) {
+        for (var xoff = 0; xoff < width; xoff += 4) {
+            copyRect(uncompressedData, 0, 0, xoff, yoff, 4, 4, stride);
+            gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, xoff, yoff, 4, 4, format, subData);
+            wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
+            // First test NEAREST filtering.
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.NEAREST);
+            wtu.clearAndDrawUnitQuad(gl);
+            compareRect(width, height, test.channels, uncompressedData, "NEAREST");
+            wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+            // Next test LINEAR filtering.
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.LINEAR);
+            gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
+            wtu.clearAndDrawUnitQuad(gl);
+            wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+            compareRect(width, height, test.channels, uncompressedData, "LINEAR");
+        }
+    }
+}
+
+function testDXT5_RGBA_PBO() {
+    debug("");
+    debug("testing PBO uploads");
+    var width = 8;
+    var height = 8;
+    var channels = 4;
+    var data = ""
+    var format = ext.COMPRESSED_RGBA_S3TC_DXT5_EXT;
+    var uncompressedData = uncompressDXT(width, height, data, format);
+
+    var tex = gl.createTexture();
+
+    // First, PBO size = image size
+    var pbo1 = gl.createBuffer();
+    gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo1);
+    gl.bufferData(gl.PIXEL_UNPACK_BUFFER, data, gl.STATIC_DRAW);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a PBO");
+
+    gl.bindTexture(gl.TEXTURE_2D, tex);
+    gl.texStorage2D(gl.TEXTURE_2D, 1, format, width, height);
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data.length, 0);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a texture from a PBO");
+
+    gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+    wtu.clearAndDrawUnitQuad(gl);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+    compareRect(width, height, channels, uncompressedData, "NEAREST");
+
+    // Clear the texture before the next test
+    gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, new Uint8Array(data.length));
+
+    // Second, image is just a subrange of the PBO
+    var pbo2 = gl.createBuffer();
+    gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, pbo2);
+    gl.bufferData(gl.PIXEL_UNPACK_BUFFER, data.length*3, gl.STATIC_DRAW);
+    gl.bufferSubData(gl.PIXEL_UNPACK_BUFFER, data.length, data);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a PBO subrange");
+    gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, format, data.length, data.length);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "uploading a texture from a PBO subrange");
+    gl.bindBuffer(gl.PIXEL_UNPACK_BUFFER, null);
+    wtu.clearAndDrawUnitQuad(gl);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "drawing unit quad");
+    compareRect(width, height, channels, uncompressedData, "NEAREST");
+}
+
+function compareRect(width, height, channels, expectedData, filteringMode) {
+    var actual = new Uint8Array(width * height * 4);
+    gl.readPixels(0, 0, width, height, gl.RGBA, gl.UNSIGNED_BYTE, actual);
+    wtu.glErrorShouldBe(gl, gl.NO_ERROR, "reading back pixels");
+
+    var div = document.createElement("div");
+    div.className = "testimages";
+    ctu.insertCaptionedImg(div, "expected", ctu.makeScaledImage(width, height, width, expectedData, true));
+    ctu.insertCaptionedImg(div, "actual", ctu.makeScaledImage(width, height, width, actual, true));
+    div.appendChild(document.createElement('br'));
+    document.getElementById("console").appendChild(div);
+
+    var failed = false;
+    for (var yy = 0; yy < height; ++yy) {
+        for (var xx = 0; xx < width; ++xx) {
+            var offset = (yy * width + xx) * 4;
+            var expected = expectedData.slice(offset, offset + 4);
+            // Compare RGB values
+            for (var jj = 0; jj < 3; ++jj) {
+                // Acceptable interpolation error depends on endpoints:
+                // 1.0 / 255.0 + 0.03 * max(abs(endpoint0 - endpoint1), abs(endpoint0_p - endpoint1_p))
+                // For simplicity, assume the worst case (e0 is 0.0, e1 is 1.0). After conversion to unorm8, it is 9.
+                if (Math.abs(actual[offset + jj] - expected[jj]) > 9) {
+                    var was = actual[offset + 0].toString();
+                    for (var j = 1; j < 3; ++j) {
+                        was += "," + actual[offset + j];
+                    }
+                    failed = true;
+                    testFailed('RGB at (' + xx + ', ' + yy +
+                                        ') expected: ' + expected + ' ± 9 was ' + was);
+                }
+            }
+
+            if (channels == 3) {
+                // BC1 RGB is allowed to be mapped to BC1 RGBA.
+                // In such a case, 3-color mode black value can be transparent:
+                // [0, 0, 0, 0] instead of [0, 0, 0, 255].
+
+                if (actual[offset + 3] != expected[3]) {
+                    // Got non-opaque value for opaque format
+
+                    // Check RGB values. Notice, that the condition here
+                    // is more permissive than needed since we don't have
+                    // compressed data at this point.
+                    if (actual[offset] == 0 &&
+                        actual[offset + 1] == 0 &&
+                        actual[offset + 2] == 0 &&
+                        actual[offset + 3] == 0) {
+                            debug("<b>DXT1 RGB is mapped to DXT1 RGBA</b>");
+                    } else {
+                        failed = true;
+                        testFailed('Alpha at (' + xx + ', ' + yy +
+                                              ') expected: ' + expected[3] + ' was ' + actual[offset + 3]);
+                    }
+                }
+            } else {
+                // Compare Alpha values
+                // Acceptable interpolation error depends on endpoints:
+                // 1.0 / 65535.0 + 0.03 * max(abs(endpoint0 - endpoint1), abs(endpoint0_p - endpoint1_p))
+                // For simplicity, assume the worst case (e0 is 0.0, e1 is 1.0). After conversion to unorm8, it is 8.
+                if (Math.abs(actual[offset + 3] - expected[3]) > 8) {
+                    var was = actual[offset + 3].toString();
+                    failed = true;
+                    testFailed('Alpha at (' + xx + ', ' + yy +
+                                          ') expected: ' + expected + ' ± 8 was ' + was);
+                }
+            }
+        }
+    }
+    if (!failed) {
+        testPassed("texture rendered correctly with " + filteringMode + " filtering");
+    }
+}
+
+debug("");
+var successfullyParsed = true;
+</script>
+<script src=""
+
+</body>
+</html>

Added: trunk/LayoutTests/webgl/resources/webgl_test_files/js/tests/compressed-texture-utils.js (0 => 268234)


--- trunk/LayoutTests/webgl/resources/webgl_test_files/js/tests/compressed-texture-utils.js	                        (rev 0)
+++ trunk/LayoutTests/webgl/resources/webgl_test_files/js/tests/compressed-texture-utils.js	2020-10-09 00:24:42 UTC (rev 268234)
@@ -0,0 +1,229 @@
+/*
+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.
+*/
+
+"use strict";
+
+let CompressedTextureUtils = (function() {
+
+let formatToString = function(ext, format) {
+    for (let p in ext) {
+        if (ext[p] == format) {
+            return p;
+        }
+    }
+    return "0x" + format.toString(16);
+};
+
+/**
+ * Make an image element from Uint8Array bitmap data.
+ * @param {number} imageHeight Height of the data in pixels.
+ * @param {number} imageWidth Width of the data in pixels.
+ * @param {number} dataWidth Width of each row in the data buffer, in pixels.
+ * @param {Uint8Array} data Image data buffer to display. Each pixel takes up 4 bytes in the array regardless of the alpha parameter.
+ * @param {boolean} alpha True if alpha data should be taken from data. Otherwise alpha channel is set to 255.
+ * @return {HTMLImageElement} The image element.
+ */
+let makeScaledImage = function(imageWidth, imageHeight, dataWidth, data, alpha, opt_scale) {
+    let scale = opt_scale ? opt_scale : 8;
+    let c = document.createElement("canvas");
+    c.width = imageWidth * scale;
+    c.height = imageHeight * scale;
+    let ctx = c.getContext("2d");
+    for (let yy = 0; yy < imageHeight; ++yy) {
+        for (let xx = 0; xx < imageWidth; ++xx) {
+            let offset = (yy * dataWidth + xx) * 4;
+            ctx.fillStyle = "rgba(" +
+                    data[offset + 0] + "," +
+                    data[offset + 1] + "," +
+                    data[offset + 2] + "," +
+                    (alpha ? data[offset + 3] / 255 : 1) + ")";
+            ctx.fillRect(xx * scale, yy * scale, scale, scale);
+        }
+    }
+    return wtu.makeImageFromCanvas(c);
+};
+
+let insertCaptionedImg = function(parent, caption, img) {
+    let div = document.createElement("div");
+    div.appendChild(img);
+    let label = document.createElement("div");
+    label.appendChild(document.createTextNode(caption));
+    div.appendChild(label);
+    parent.appendChild(div);
+};
+
+/**
+ * @param {WebGLRenderingContextBase} gl
+ * @param {Object} compressedFormats Mapping from format names to format enum values.
+ * @param expectedByteLength A function that takes in width, height and format and returns the expected buffer size in bytes.
+ */
+let testCompressedFormatsUnavailableWhenExtensionDisabled = function(gl, compressedFormats, expectedByteLength, testSize) {
+    let tex = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, tex);
+    for (let name in compressedFormats) {
+        if (compressedFormats.hasOwnProperty(name)) {
+            gl.compressedTexImage2D(gl.TEXTURE_2D, 0, compressedFormats[name], testSize, testSize, 0, new Uint8Array(expectedByteLength(testSize, testSize, compressedFormats[name])));
+            wtu.glErrorShouldBe(gl, gl.INVALID_ENUM, "Trying to use format " + name + " with extension disabled.");
+        }
+    }
+    gl.bindTexture(gl.TEXTURE_2D, null);
+    gl.deleteTexture(tex);
+};
+
+/**
+ * @param {WebGLRenderingContextBase} gl
+ * @param {Object} expectedFormats Mapping from format names to format enum values.
+ */
+let testCompressedFormatsListed = function(gl, expectedFormats) {
+    debug("");
+    debug("Testing that every format is listed by the compressed texture formats query");
+
+    let supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
+
+    let failed;
+    let count = 0;
+    for (let name in expectedFormats) {
+        if (expectedFormats.hasOwnProperty(name)) {
+            ++count;
+            let format = expectedFormats[name];
+            failed = true;
+            for (let ii = 0; ii < supportedFormats.length; ++ii) {
+                if (format == supportedFormats[ii]) {
+                    testPassed("supported format " + name + " exists");
+                    failed = false;
+                    break;
+                }
+            }
+            if (failed) {
+                testFailed("supported format " + name + " does not exist");
+            }
+        }
+    }
+    if (supportedFormats.length != count) {
+        testFailed("Incorrect number of supported formats, was " + supportedFormats.length + " should be " + count);
+    }
+};
+
+/**
+ * @param {Object} ext Compressed texture extension object.
+ * @param {Object} expectedFormats Mapping from format names to format enum values.
+ */
+let testCorrectEnumValuesInExt = function(ext, expectedFormats) {
+    debug("");
+    debug("Testing that format enum values in the extension object are correct");
+
+    for (name in expectedFormats) {
+        if (expectedFormats.hasOwnProperty(name)) {
+            if (isResultCorrect(ext[name], expectedFormats[name])) {
+                testPassed("Enum value for " + name + " matches 0x" + ext[name].toString(16));
+            } else {
+                testFailed("Enum value for " + name + " mismatch: 0x" + ext[name].toString(16) + " should be 0x" + expectedFormats[name].toString(16));
+            }
+        }
+    }
+};
+
+/**
+ * @param {WebGLRenderingContextBase} gl
+ * @param {Object} validFormats Mapping from format names to format enum values.
+ * @param expectedByteLength A function that takes in width, height and format and returns the expected buffer size in bytes.
+ * @param getBlockDimensions A function that takes in a format and returns block size in pixels.
+ */
+let testFormatRestrictionsOnBufferSize = function(gl, validFormats, expectedByteLength, getBlockDimensions) {
+    debug("");
+    debug("Testing format restrictions on texture upload buffer size");
+
+    let tex = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, tex);
+    for (let formatId in validFormats) {
+        if (validFormats.hasOwnProperty(formatId)) {
+            let format = validFormats[formatId];
+            let blockSize = getBlockDimensions(format);
+            let expectedSize = expectedByteLength(blockSize.width * 4, blockSize.height * 4, format);
+            let data = "" Uint8Array(expectedSize);
+            gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 3, blockSize.height * 4, 0, data);
+            wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too small width)");
+            gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 5, blockSize.height * 4, 0, data);
+            wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too large width)");
+            gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 4, blockSize.height * 3, 0, data);
+            wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too small height)");
+            gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, blockSize.width * 4, blockSize.height * 5, 0, data);
+            wtu.glErrorShouldBe(gl, gl.INVALID_VALUE, formatId + " data size does not match dimensions (too large height)");
+        }
+    }
+};
+
+/**
+ * @param {WebGLRenderingContextBase} gl
+ * @param {Object} validFormats Mapping from format names to format enum values.
+ * @param expectedByteLength A function that takes in width, height and format and returns the expected buffer size in bytes.
+ * @param getBlockDimensions A function that takes in a format and returns block size in pixels.
+ * @param {number} width Width of the image in pixels.
+ * @param {number} height Height of the image in pixels.
+ * @param {Object} subImageConfigs configs for compressedTexSubImage calls
+ */
+let testTexSubImageDimensions = function(gl, validFormats, expectedByteLength, getBlockDimensions, width, height, subImageConfigs) {
+    let tex = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, tex);
+
+    for (let formatId in validFormats) {
+        if (validFormats.hasOwnProperty(formatId)) {
+            let format = validFormats[formatId];
+            let blockSize = getBlockDimensions(format);
+            let expectedSize = expectedByteLength(width, height, format);
+            let data = "" Uint8Array(expectedSize);
+
+            gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
+            wtu.glErrorShouldBe(gl, gl.NO_ERROR, "setting up compressed texture");
+
+            for (let i = 0, len = subImageConfigs.length; i < len; ++i) {
+                let c = subImageConfigs[i];
+                let subData = new Uint8Array(expectedByteLength(c.width, c.height, format));
+                gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, c.xoffset, c.yoffset, c.width, c.height, format, subData);
+                wtu.glErrorShouldBe(gl, c.expectation, c.message);
+            }
+        }
+    }
+
+    gl.bindTexture(gl.TEXTURE_2D, null);
+    gl.deleteTexture(tex);
+};
+
+let testTexImageLevelDimensions = function(gl, validFormats, expectedByteLength, getBlockDimensions, imageConfigs) {
+    let tex = gl.createTexture();
+    gl.bindTexture(gl.TEXTURE_2D, tex);
+
+    for (let formatId in validFormats) {
+        if (validFormats.hasOwnProperty(formatId)) {
+            let format = validFormats[formatId];
+            let blockSize = getBlockDimensions(format);
+
+            for (let i = 0, len = imageConfigs.length; i < len; ++i) {
+                let c = imageConfigs[i];
+                let data = "" Uint8Array(expectedByteLength(c.width, c.height, format));
+                gl.compressedTexImage2D(gl.TEXTURE_2D, c.level, format, c.width, c.height, 0, data);
+                wtu.glErrorShouldBe(gl, c.expectation, c.message);
+            }
+        }
+    }
+
+    gl.bindTexture(gl.TEXTURE_2D, null);
+    gl.deleteTexture(tex);
+}
+
+return {
+    formatToString: formatToString,
+    insertCaptionedImg: insertCaptionedImg,
+    makeScaledImage: makeScaledImage,
+    testCompressedFormatsListed: testCompressedFormatsListed,
+    testCompressedFormatsUnavailableWhenExtensionDisabled: testCompressedFormatsUnavailableWhenExtensionDisabled,
+    testCorrectEnumValuesInExt: testCorrectEnumValuesInExt,
+    testFormatRestrictionsOnBufferSize: testFormatRestrictionsOnBufferSize,
+    testTexSubImageDimensions: testTexSubImageDimensions,
+    testTexImageLevelDimensions: testTexImageLevelDimensions,
+};
+
+})();
\ No newline at end of file

Modified: trunk/Source/WebCore/CMakeLists.txt (268233 => 268234)


--- trunk/Source/WebCore/CMakeLists.txt	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/CMakeLists.txt	2020-10-09 00:24:42 UTC (rev 268234)
@@ -1479,6 +1479,7 @@
         html/canvas/EXTFloatBlend.cpp
         html/canvas/EXTFragDepth.cpp
         html/canvas/EXTShaderTextureLOD.cpp
+        html/canvas/EXTTextureCompressionRGTC.cpp
         html/canvas/EXTTextureFilterAnisotropic.cpp
         html/canvas/EXTsRGB.cpp
         html/canvas/OESElementIndexUint.cpp
@@ -1537,6 +1538,7 @@
     html/canvas/EXTFloatBlend.idl
     html/canvas/EXTFragDepth.idl
     html/canvas/EXTShaderTextureLOD.idl
+    html/canvas/EXTTextureCompressionRGTC.idl
     html/canvas/EXTTextureFilterAnisotropic.idl
     html/canvas/EXTsRGB.idl
     html/canvas/OESElementIndexUint.idl

Modified: trunk/Source/WebCore/ChangeLog (268233 => 268234)


--- trunk/Source/WebCore/ChangeLog	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/ChangeLog	2020-10-09 00:24:42 UTC (rev 268234)
@@ -1,3 +1,39 @@
+2020-10-08  James Darpinian  <[email protected]>
+
+        Support EXT_texture_compression_rgtc WebGL extension
+        https://bugs.webkit.org/show_bug.cgi?id=217198
+
+        Reviewed by Kenneth Russell.
+
+        Test: webgl/conformance/extensions/ext-texture-compression-rgtc.html
+
+        * CMakeLists.txt:
+        * DerivedSources-input.xcfilelist:
+        * DerivedSources-output.xcfilelist:
+        * DerivedSources.make:
+        * Sources.txt:
+        * WebCore.xcodeproj/project.pbxproj:
+        * bindings/js/JSDOMConvertWebGL.cpp:
+        (WebCore::convertToJSValue):
+        * html/canvas/EXTTextureCompressionRGTC.cpp: Added.
+        (WebCore::EXTTextureCompressionRGTC::EXTTextureCompressionRGTC):
+        (WebCore::EXTTextureCompressionRGTC::getName const):
+        * html/canvas/EXTTextureCompressionRGTC.h: Added.
+        * html/canvas/EXTTextureCompressionRGTC.idl: Added.
+        * html/canvas/WebGL2RenderingContext.cpp:
+        (WebCore::WebGL2RenderingContext::getExtension):
+        (WebCore::WebGL2RenderingContext::getSupportedExtensions):
+        * html/canvas/WebGLExtension.h:
+        * html/canvas/WebGLRenderingContext.cpp:
+        (WebCore::WebGLRenderingContext::getExtension):
+        (WebCore::WebGLRenderingContext::getSupportedExtensions):
+        * html/canvas/WebGLRenderingContextBase.cpp:
+        (WebCore::WebGLRenderingContextBase::extensionIsEnabled):
+        (WebCore::WebGLRenderingContextBase::validateCompressedTexFuncData):
+        (WebCore::WebGLRenderingContextBase::loseExtensions):
+        * html/canvas/WebGLRenderingContextBase.h:
+        * platform/graphics/ExtensionsGL.h:
+
 2020-10-08  Alex Christensen  <[email protected]>
 
         FileReader.result should return null if it isn't done yet

Modified: trunk/Source/WebCore/DerivedSources-input.xcfilelist (268233 => 268234)


--- trunk/Source/WebCore/DerivedSources-input.xcfilelist	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/DerivedSources-input.xcfilelist	2020-10-09 00:24:42 UTC (rev 268234)
@@ -951,6 +951,7 @@
 $(PROJECT_DIR)/html/canvas/EXTFloatBlend.idl
 $(PROJECT_DIR)/html/canvas/EXTFragDepth.idl
 $(PROJECT_DIR)/html/canvas/EXTShaderTextureLOD.idl
+$(PROJECT_DIR)/html/canvas/EXTTextureCompressionRGTC.idl
 $(PROJECT_DIR)/html/canvas/EXTTextureFilterAnisotropic.idl
 $(PROJECT_DIR)/html/canvas/EXTsRGB.idl
 $(PROJECT_DIR)/html/canvas/ImageBitmapRenderingContext.idl

Modified: trunk/Source/WebCore/DerivedSources-output.xcfilelist (268233 => 268234)


--- trunk/Source/WebCore/DerivedSources-output.xcfilelist	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/DerivedSources-output.xcfilelist	2020-10-09 00:24:42 UTC (rev 268234)
@@ -703,6 +703,8 @@
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSEXTFragDepth.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSEXTShaderTextureLOD.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSEXTShaderTextureLOD.h
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSEXTTextureCompressionRGTC.cpp
+$(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSEXTTextureCompressionRGTC.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSEXTTextureFilterAnisotropic.cpp
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSEXTTextureFilterAnisotropic.h
 $(BUILT_PRODUCTS_DIR)/DerivedSources/WebCore/JSEXTsRGB.cpp

Modified: trunk/Source/WebCore/DerivedSources.make (268233 => 268234)


--- trunk/Source/WebCore/DerivedSources.make	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/DerivedSources.make	2020-10-09 00:24:42 UTC (rev 268234)
@@ -971,6 +971,7 @@
     $(WebCore)/html/canvas/EXTFloatBlend.idl \
     $(WebCore)/html/canvas/EXTFragDepth.idl \
     $(WebCore)/html/canvas/EXTShaderTextureLOD.idl \
+    $(WebCore)/html/canvas/EXTTextureCompressionRGTC.idl \
     $(WebCore)/html/canvas/EXTTextureFilterAnisotropic.idl \
     $(WebCore)/html/canvas/EXTsRGB.idl \
     $(WebCore)/html/canvas/ImageBitmapRenderingContext.idl \

Modified: trunk/Source/WebCore/Sources.txt (268233 => 268234)


--- trunk/Source/WebCore/Sources.txt	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/Sources.txt	2020-10-09 00:24:42 UTC (rev 268234)
@@ -1259,6 +1259,7 @@
 html/canvas/EXTFloatBlend.cpp
 html/canvas/EXTFragDepth.cpp
 html/canvas/EXTShaderTextureLOD.cpp
+html/canvas/EXTTextureCompressionRGTC.cpp
 html/canvas/EXTTextureFilterAnisotropic.cpp
 html/canvas/EXTsRGB.cpp
 html/canvas/GPUBasedCanvasRenderingContext.cpp
@@ -2876,6 +2877,7 @@
 JSEXTFloatBlend.cpp
 JSEXTFragDepth.cpp
 JSEXTShaderTextureLOD.cpp
+JSEXTTextureCompressionRGTC.cpp
 JSEXTTextureFilterAnisotropic.cpp
 JSEXTsRGB.cpp
 JSEcKeyParams.cpp

Modified: trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj (268233 => 268234)


--- trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/WebCore.xcodeproj/project.pbxproj	2020-10-09 00:24:42 UTC (rev 268234)
@@ -12147,6 +12147,9 @@
 		A37A42CE251EB99600F75AFF /* OESFBORenderMipmap.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = OESFBORenderMipmap.cpp; sourceTree = "<group>"; };
 		A37A42D0251EB99600F75AFF /* OESFBORenderMipmap.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OESFBORenderMipmap.h; sourceTree = "<group>"; };
 		A37A42D1251EB99700F75AFF /* OESFBORenderMipmap.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = OESFBORenderMipmap.idl; sourceTree = "<group>"; };
+		A37A42E02527B49C00F75AFF /* EXTTextureCompressionRGTC.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = EXTTextureCompressionRGTC.cpp; sourceTree = "<group>"; };
+		A37A42E22527B49D00F75AFF /* EXTTextureCompressionRGTC.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = EXTTextureCompressionRGTC.h; sourceTree = "<group>"; };
+		A37A42E32527B49E00F75AFF /* EXTTextureCompressionRGTC.idl */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; path = EXTTextureCompressionRGTC.idl; sourceTree = "<group>"; };
 		A3AF9D81203252EE006CAD06 /* UserAgentCocoa.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = UserAgentCocoa.mm; sourceTree = "<group>"; };
 		A3AF9D8220325324006CAD06 /* UserAgent.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = UserAgent.h; sourceTree = "<group>"; };
 		A3AF9D8320325691006CAD06 /* UserAgentIOS.mm */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.objcpp; path = UserAgentIOS.mm; sourceTree = "<group>"; };
@@ -19441,6 +19444,9 @@
 				727AFED11A2EA6A0000442E8 /* EXTsRGB.cpp */,
 				727AFED21A2EA6A0000442E8 /* EXTsRGB.h */,
 				727AFED31A2EA6A0000442E8 /* EXTsRGB.idl */,
+				A37A42E02527B49C00F75AFF /* EXTTextureCompressionRGTC.cpp */,
+				A37A42E22527B49D00F75AFF /* EXTTextureCompressionRGTC.h */,
+				A37A42E32527B49E00F75AFF /* EXTTextureCompressionRGTC.idl */,
 				7728694B14F8882500F484DC /* EXTTextureFilterAnisotropic.cpp */,
 				7728694C14F8882500F484DC /* EXTTextureFilterAnisotropic.h */,
 				7728694D14F8882500F484DC /* EXTTextureFilterAnisotropic.idl */,

Modified: trunk/Source/WebCore/bindings/js/JSDOMConvertWebGL.cpp (268233 => 268234)


--- trunk/Source/WebCore/bindings/js/JSDOMConvertWebGL.cpp	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/bindings/js/JSDOMConvertWebGL.cpp	2020-10-09 00:24:42 UTC (rev 268234)
@@ -36,6 +36,7 @@
 #include "JSEXTFloatBlend.h"
 #include "JSEXTFragDepth.h"
 #include "JSEXTShaderTextureLOD.h"
+#include "JSEXTTextureCompressionRGTC.h"
 #include "JSEXTTextureFilterAnisotropic.h"
 #include "JSEXTsRGB.h"
 #include "JSOESElementIndexUint.h"
@@ -171,6 +172,8 @@
         return toJS(&lexicalGlobalObject, &globalObject, static_cast<WebGLLoseContext&>(extension));
     case WebGLExtension::EXTShaderTextureLODName:
         return toJS(&lexicalGlobalObject, &globalObject, static_cast<EXTShaderTextureLOD&>(extension));
+    case WebGLExtension::EXTTextureCompressionRGTCName:
+        return toJS(&lexicalGlobalObject, &globalObject, static_cast<EXTTextureCompressionRGTC&>(extension));
     case WebGLExtension::EXTTextureFilterAnisotropicName:
         return toJS(&lexicalGlobalObject, &globalObject, static_cast<EXTTextureFilterAnisotropic&>(extension));
     case WebGLExtension::EXTsRGBName:

Added: trunk/Source/WebCore/html/canvas/EXTTextureCompressionRGTC.cpp (0 => 268234)


--- trunk/Source/WebCore/html/canvas/EXTTextureCompressionRGTC.cpp	                        (rev 0)
+++ trunk/Source/WebCore/html/canvas/EXTTextureCompressionRGTC.cpp	2020-10-09 00:24:42 UTC (rev 268234)
@@ -0,0 +1,57 @@
+/*
+ * Copyright (C) 2020 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#include "config.h"
+
+#if ENABLE(WEBGL)
+#include "EXTTextureCompressionRGTC.h"
+
+#include <wtf/IsoMallocInlines.h>
+
+namespace WebCore {
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(EXTTextureCompressionRGTC);
+
+EXTTextureCompressionRGTC::EXTTextureCompressionRGTC(WebGLRenderingContextBase& context)
+    : WebGLExtension(context)
+{
+    context.graphicsContextGL()->getExtensions().ensureEnabled("GL_EXT_texture_compression_rgtc");
+
+    context.addCompressedTextureFormat(ExtensionsGL::COMPRESSED_RED_RGTC1_EXT);
+    context.addCompressedTextureFormat(ExtensionsGL::COMPRESSED_SIGNED_RED_RGTC1_EXT);
+    context.addCompressedTextureFormat(ExtensionsGL::COMPRESSED_RED_GREEN_RGTC2_EXT);
+    context.addCompressedTextureFormat(ExtensionsGL::COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT);
+}
+
+EXTTextureCompressionRGTC::~EXTTextureCompressionRGTC() = default;
+
+WebGLExtension::ExtensionName EXTTextureCompressionRGTC::getName() const
+{
+    return EXTTextureCompressionRGTCName;
+}
+
+} // namespace WebCore
+
+#endif // ENABLE(WEBGL)

Added: trunk/Source/WebCore/html/canvas/EXTTextureCompressionRGTC.h (0 => 268234)


--- trunk/Source/WebCore/html/canvas/EXTTextureCompressionRGTC.h	                        (rev 0)
+++ trunk/Source/WebCore/html/canvas/EXTTextureCompressionRGTC.h	2020-10-09 00:24:42 UTC (rev 268234)
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2020 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#pragma once
+
+#include "WebGLExtension.h"
+
+namespace WebCore {
+
+class EXTTextureCompressionRGTC final : public WebGLExtension {
+    WTF_MAKE_ISO_ALLOCATED(EXTTextureCompressionRGTC);
+public:
+    explicit EXTTextureCompressionRGTC(WebGLRenderingContextBase&);
+    virtual ~EXTTextureCompressionRGTC();
+
+    ExtensionName getName() const override;
+};
+
+} // namespace WebCore

Added: trunk/Source/WebCore/html/canvas/EXTTextureCompressionRGTC.idl (0 => 268234)


--- trunk/Source/WebCore/html/canvas/EXTTextureCompressionRGTC.idl	                        (rev 0)
+++ trunk/Source/WebCore/html/canvas/EXTTextureCompressionRGTC.idl	2020-10-09 00:24:42 UTC (rev 268234)
@@ -0,0 +1,35 @@
+/*
+ * Copyright (C) 2020 Google Inc. All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ *
+ * 1.  Redistributions of source code must retain the above copyright
+ *     notice, this list of conditions and the following disclaimer.
+ * 2.  Redistributions in binary form must reproduce the above copyright
+ *     notice, this list of conditions and the following disclaimer in the
+ *     documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY APPLE AND ITS CONTRIBUTORS "AS IS" AND ANY
+ * EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
+ * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
+ * DISCLAIMED. IN NO EVENT SHALL APPLE OR ITS CONTRIBUTORS BE LIABLE FOR ANY
+ * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
+ * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
+ * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
+ * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+[
+    Conditional=WEBGL,
+    GenerateIsReachable=ImplWebGLRenderingContext,
+    LegacyNoInterfaceObject,
+] interface EXTTextureCompressionRGTC {
+    const unsigned long COMPRESSED_RED_RGTC1_EXT = 0x8DBB;
+    const unsigned long COMPRESSED_SIGNED_RED_RGTC1_EXT = 0x8DBC;
+    const unsigned long COMPRESSED_RED_GREEN_RGTC2_EXT = 0x8DBD;
+    const unsigned long COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT = 0x8DBE;
+};

Modified: trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp (268233 => 268234)


--- trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/html/canvas/WebGL2RenderingContext.cpp	2020-10-09 00:24:42 UTC (rev 268234)
@@ -32,6 +32,7 @@
 #include "EXTColorBufferFloat.h"
 #include "EXTColorBufferHalfFloat.h"
 #include "EXTFloatBlend.h"
+#include "EXTTextureCompressionRGTC.h"
 #include "EXTTextureFilterAnisotropic.h"
 #include "EventLoop.h"
 #include "ExtensionsGL.h"
@@ -2671,6 +2672,7 @@
         return variable.get(); \
     }
 
+    ENABLE_IF_REQUESTED(EXTTextureCompressionRGTC, m_extTextureCompressionRGTC, "EXT_texture_compression_rgtc", enableSupportedExtension("GL_EXT_texture_compression_rgtc"_s));
     ENABLE_IF_REQUESTED(EXTTextureFilterAnisotropic, m_extTextureFilterAnisotropic, "EXT_texture_filter_anisotropic", enableSupportedExtension("GL_EXT_texture_filter_anisotropic"_s));
     ENABLE_IF_REQUESTED(OESTextureFloatLinear, m_oesTextureFloatLinear, "OES_texture_float_linear", enableSupportedExtension("GL_OES_texture_float_linear"_s));
     ENABLE_IF_REQUESTED(WebGLLoseContext, m_webglLoseContext, "WEBGL_lose_context", true);
@@ -2703,6 +2705,8 @@
     auto& extensions = m_context->getExtensions();
     if (extensions.supports("GL_OES_texture_float_linear"_s))
         result.append("OES_texture_float_linear"_s);
+    if (extensions.supports("GL_EXT_texture_compression_rgtc"_s))
+        result.append("EXT_texture_compression_rgtc"_s);
     if (extensions.supports("GL_EXT_texture_filter_anisotropic"_s))
         result.append("EXT_texture_filter_anisotropic"_s);
     if (WebGLCompressedTextureASTC::supported(*this))

Modified: trunk/Source/WebCore/html/canvas/WebGLExtension.h (268233 => 268234)


--- trunk/Source/WebCore/html/canvas/WebGLExtension.h	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/html/canvas/WebGLExtension.h	2020-10-09 00:24:42 UTC (rev 268234)
@@ -41,6 +41,7 @@
         EXTBlendMinMaxName,
         EXTFragDepthName,
         EXTShaderTextureLODName,
+        EXTTextureCompressionRGTCName,
         EXTTextureFilterAnisotropicName,
         EXTsRGBName,
         OESTextureFloatName,

Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp (268233 => 268234)


--- trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContext.cpp	2020-10-09 00:24:42 UTC (rev 268234)
@@ -35,6 +35,7 @@
 #include "EXTFloatBlend.h"
 #include "EXTFragDepth.h"
 #include "EXTShaderTextureLOD.h"
+#include "EXTTextureCompressionRGTC.h"
 #include "EXTTextureFilterAnisotropic.h"
 #include "EXTsRGB.h"
 #include "ExtensionsGL.h"
@@ -153,6 +154,7 @@
         return m_extShaderTextureLOD.get();
     }
     ENABLE_IF_REQUESTED(EXTTextureFilterAnisotropic, m_extTextureFilterAnisotropic, "EXT_texture_filter_anisotropic", enableSupportedExtension("GL_EXT_texture_filter_anisotropic"_s));
+    ENABLE_IF_REQUESTED(EXTTextureCompressionRGTC, m_extTextureCompressionRGTC, "EXT_texture_compression_rgtc", enableSupportedExtension("GL_EXT_texture_compression_rgtc"_s));
     ENABLE_IF_REQUESTED(OESStandardDerivatives, m_oesStandardDerivatives, "OES_standard_derivatives", enableSupportedExtension("GL_OES_standard_derivatives"_s));
     ENABLE_IF_REQUESTED(OESTextureFloat, m_oesTextureFloat, "OES_texture_float", OESTextureFloat::supported(*this));
     ENABLE_IF_REQUESTED(OESTextureFloatLinear, m_oesTextureFloatLinear, "OES_texture_float_linear", enableSupportedExtension("GL_OES_texture_float_linear"_s));
@@ -231,6 +233,8 @@
         result.append("OES_standard_derivatives"_s);
     if (m_context->getExtensions().supports("GL_EXT_shader_texture_lod"_s) || m_context->getExtensions().supports("GL_ARB_shader_texture_lod"_s))
         result.append("EXT_shader_texture_lod"_s);
+    if (m_context->getExtensions().supports("GL_EXT_texture_compression_rgtc"_s))
+        result.append("EXT_texture_compression_rgtc"_s);
     if (m_context->getExtensions().supports("GL_EXT_texture_filter_anisotropic"_s))
         result.append("EXT_texture_filter_anisotropic"_s);
     if (m_context->getExtensions().supports("GL_OES_vertex_array_object"_s))

Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp (268233 => 268234)


--- trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.cpp	2020-10-09 00:24:42 UTC (rev 268234)
@@ -40,6 +40,7 @@
 #include "EXTFloatBlend.h"
 #include "EXTFragDepth.h"
 #include "EXTShaderTextureLOD.h"
+#include "EXTTextureCompressionRGTC.h"
 #include "EXTTextureFilterAnisotropic.h"
 #include "EXTsRGB.h"
 #include "EventNames.h"
@@ -3707,6 +3708,7 @@
     CHECK_EXTENSION(m_extFragDepth, "EXT_frag_depth");
     CHECK_EXTENSION(m_extBlendMinMax, "EXT_blend_minmax");
     CHECK_EXTENSION(m_extsRGB, "EXT_sRGB");
+    CHECK_EXTENSION(m_extTextureCompressionRGTC, "EXT_texture_compression_rgtc");
     CHECK_EXTENSION(m_extTextureFilterAnisotropic, "EXT_texture_filter_anisotropic");
     CHECK_EXTENSION(m_extTextureFilterAnisotropic, "WEBKIT_EXT_texture_filter_anisotropic");
     CHECK_EXTENSION(m_extShaderTextureLOD, "EXT_shader_texture_lod");
@@ -6723,6 +6725,26 @@
         bytesRequired = checkedBytesRequired.unsafeGet();
         break;
     }
+    case ExtensionsGL::COMPRESSED_RED_RGTC1_EXT:
+    case ExtensionsGL::COMPRESSED_SIGNED_RED_RGTC1_EXT: {
+        const int kBlockSize = 8;
+        const int kBlockWidth = 4;
+        const int kBlockHeight = 4;
+        int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
+        int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
+        bytesRequired = numBlocksAcross * numBlocksDown * kBlockSize;
+        break;
+    }
+    case ExtensionsGL::COMPRESSED_RED_GREEN_RGTC2_EXT:
+    case ExtensionsGL::COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT: {
+        const int kBlockSize = 16;
+        const int kBlockWidth = 4;
+        const int kBlockHeight = 4;
+        int numBlocksAcross = (width + kBlockWidth - 1) / kBlockWidth;
+        int numBlocksDown = (height + kBlockHeight - 1) / kBlockHeight;
+        bytesRequired = numBlocksAcross * numBlocksDown * kBlockSize;
+        break;
+    }
     default:
         synthesizeGLError(GraphicsContextGL::INVALID_ENUM, functionName, "invalid format");
         return false;
@@ -7777,6 +7799,7 @@
     LOSE_EXTENSION(m_extFragDepth);
     LOSE_EXTENSION(m_extBlendMinMax);
     LOSE_EXTENSION(m_extsRGB);
+    LOSE_EXTENSION(m_extTextureCompressionRGTC);
     LOSE_EXTENSION(m_extTextureFilterAnisotropic);
     LOSE_EXTENSION(m_extShaderTextureLOD);
     LOSE_EXTENSION(m_oesTextureFloat);

Modified: trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.h (268233 => 268234)


--- trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.h	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/html/canvas/WebGLRenderingContextBase.h	2020-10-09 00:24:42 UTC (rev 268234)
@@ -72,6 +72,7 @@
 class EXTColorBufferFloat;
 class EXTColorBufferHalfFloat;
 class EXTFloatBlend;
+class EXTTextureCompressionRGTC;
 class EXTTextureFilterAnisotropic;
 class EXTShaderTextureLOD;
 class EXTsRGB;
@@ -428,6 +429,7 @@
     WebGLRenderingContextBase(CanvasBase&, WebGLContextAttributes);
     WebGLRenderingContextBase(CanvasBase&, Ref<GraphicsContextGLOpenGL>&&, WebGLContextAttributes);
 
+    friend class EXTTextureCompressionRGTC;
     friend class WebGLDrawBuffers;
     friend class WebGLFramebuffer;
     friend class WebGLObject;
@@ -669,6 +671,7 @@
     RefPtr<EXTFragDepth> m_extFragDepth;
     RefPtr<EXTBlendMinMax> m_extBlendMinMax;
     RefPtr<EXTsRGB> m_extsRGB;
+    RefPtr<EXTTextureCompressionRGTC> m_extTextureCompressionRGTC;
     RefPtr<EXTTextureFilterAnisotropic> m_extTextureFilterAnisotropic;
     RefPtr<EXTShaderTextureLOD> m_extShaderTextureLOD;
     RefPtr<OESTextureFloat> m_oesTextureFloat;

Modified: trunk/Source/WebCore/platform/graphics/ExtensionsGL.h (268233 => 268234)


--- trunk/Source/WebCore/platform/graphics/ExtensionsGL.h	2020-10-09 00:15:14 UTC (rev 268233)
+++ trunk/Source/WebCore/platform/graphics/ExtensionsGL.h	2020-10-09 00:24:42 UTC (rev 268234)
@@ -219,6 +219,12 @@
         COMPRESSED_SRGB8_ALPHA8_ASTC_12x10_KHR = 0x93DC,
         COMPRESSED_SRGB8_ALPHA8_ASTC_12x12_KHR = 0x93DD,
 
+        // GL_EXT_texture_compression_rgtc
+        COMPRESSED_RED_RGTC1_EXT = 0x8DBB,
+        COMPRESSED_SIGNED_RED_RGTC1_EXT = 0x8DBC,
+        COMPRESSED_RED_GREEN_RGTC2_EXT = 0x8DBD,
+        COMPRESSED_SIGNED_RED_GREEN_RGTC2_EXT = 0x8DBE,
+
         // GL_EXT_texture_filter_anisotropic
         TEXTURE_MAX_ANISOTROPY_EXT = 0x84FE,
         MAX_TEXTURE_MAX_ANISOTROPY_EXT = 0x84FF,
_______________________________________________
webkit-changes mailing list
[email protected]
https://lists.webkit.org/mailman/listinfo/webkit-changes

Reply via email to