Bug 917505 - Add WEBGL_compressed_texture_es3 support. r=jgilbert r=smaug

This commit is contained in:
Morris Tseng 2016-01-08 10:12:22 +08:00
parent a98389f8f4
commit f0d054dabe
13 changed files with 5579 additions and 0 deletions

View File

@ -1401,6 +1401,11 @@ DOMInterfaces = {
'headerFile': 'WebGLExtensions.h'
},
'WEBGL_compressed_texture_es3': {
'nativeType': 'mozilla::WebGLExtensionCompressedTextureES3',
'headerFile': 'WebGLExtensions.h'
},
'WEBGL_compressed_texture_pvrtc': {
'nativeType': 'mozilla::WebGLExtensionCompressedTexturePVRTC',
'headerFile': 'WebGLExtensions.h'

View File

@ -190,6 +190,7 @@ class WebGLContext
friend class WebGL2Context;
friend class WebGLContextUserData;
friend class WebGLExtensionCompressedTextureATC;
friend class WebGLExtensionCompressedTextureES3;
friend class WebGLExtensionCompressedTextureETC1;
friend class WebGLExtensionCompressedTexturePVRTC;
friend class WebGLExtensionCompressedTextureS3TC;

View File

@ -47,6 +47,7 @@ WebGLContext::GetExtensionString(WebGLExtensionID ext)
WEBGL_EXTENSION_IDENTIFIER(OES_vertex_array_object)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_color_buffer_float)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_atc)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_es3)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_etc1)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_pvrtc)
WEBGL_EXTENSION_IDENTIFIER(WEBGL_compressed_texture_s3tc)
@ -199,6 +200,8 @@ WebGLContext::IsExtensionSupported(WebGLExtensionID ext) const
switch (ext) {
case WebGLExtensionID::EXT_disjoint_timer_query:
return WebGLExtensionDisjointTimerQuery::IsSupported(this);
case WebGLExtensionID::WEBGL_compressed_texture_es3:
return gl->IsExtensionSupported(gl::GLContext::ARB_ES3_compatibility);
default:
// For warnings-as-errors.
@ -377,6 +380,9 @@ WebGLContext::EnableExtension(WebGLExtensionID ext)
case WebGLExtensionID::WEBGL_compressed_texture_atc:
obj = new WebGLExtensionCompressedTextureATC(this);
break;
case WebGLExtensionID::WEBGL_compressed_texture_es3:
obj = new WebGLExtensionCompressedTextureES3(this);
break;
case WebGLExtensionID::WEBGL_compressed_texture_etc1:
obj = new WebGLExtensionCompressedTextureETC1(this);
break;

View File

@ -0,0 +1,55 @@
/* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this file,
* You can obtain one at http://mozilla.org/MPL/2.0/. */
#include "WebGLExtensions.h"
#include "mozilla/dom/WebGLRenderingContextBinding.h"
#include "WebGLContext.h"
#ifdef FOO
#error FOO is already defined! We use FOO() macros to keep things succinct in this file.
#endif
namespace mozilla {
WebGLExtensionCompressedTextureES3::WebGLExtensionCompressedTextureES3(WebGLContext* webgl)
: WebGLExtensionBase(webgl)
{
RefPtr<WebGLContext> webgl_ = webgl; // Bug 1201275
const auto fnAdd = [&webgl_](GLenum sizedFormat, webgl::EffectiveFormat effFormat) {
auto& fua = webgl_->mFormatUsage;
auto usage = fua->EditUsage(effFormat);
usage->isFilterable = true;
fua->AllowSizedTexFormat(sizedFormat, usage);
webgl_->mCompressedTextureFormats.AppendElement(sizedFormat);
};
#define FOO(x) LOCAL_GL_ ## x, webgl::EffectiveFormat::x
fnAdd(FOO(COMPRESSED_R11_EAC));
fnAdd(FOO(COMPRESSED_SIGNED_R11_EAC));
fnAdd(FOO(COMPRESSED_RG11_EAC));
fnAdd(FOO(COMPRESSED_SIGNED_RG11_EAC));
fnAdd(FOO(COMPRESSED_RGB8_ETC2));
fnAdd(FOO(COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2));
fnAdd(FOO(COMPRESSED_RGBA8_ETC2_EAC));
// sRGB support is manadatory in GL 4.3 and GL ES 3.0, which are the only
// versions to support ETC2.
fnAdd(FOO(COMPRESSED_SRGB8_ALPHA8_ETC2_EAC));
fnAdd(FOO(COMPRESSED_SRGB8_ETC2));
fnAdd(FOO(COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2));
#undef FOO
}
WebGLExtensionCompressedTextureES3::~WebGLExtensionCompressedTextureES3()
{
}
IMPL_WEBGL_EXTENSION_GOOP(WebGLExtensionCompressedTextureES3, WEBGL_compressed_texture_es3)
} // namespace mozilla

View File

@ -71,6 +71,16 @@ public:
DECL_WEBGL_EXTENSION_GOOP
};
class WebGLExtensionCompressedTextureES3
: public WebGLExtensionBase
{
public:
explicit WebGLExtensionCompressedTextureES3(WebGLContext*);
virtual ~WebGLExtensionCompressedTextureES3();
DECL_WEBGL_EXTENSION_GOOP
};
class WebGLExtensionCompressedTextureETC1
: public WebGLExtensionBase
{

View File

@ -8,6 +8,7 @@
#include <map>
#include <set>
#include <string>
#include <vector>
#include "mozilla/LinkedList.h"

View File

@ -154,6 +154,7 @@ enum class WebGLExtensionID : uint8_t {
OES_vertex_array_object,
WEBGL_color_buffer_float,
WEBGL_compressed_texture_atc,
WEBGL_compressed_texture_es3,
WEBGL_compressed_texture_etc1,
WEBGL_compressed_texture_pvrtc,
WEBGL_compressed_texture_s3tc,

View File

@ -101,6 +101,7 @@ UNIFIED_SOURCES += [
'WebGLExtensionColorBufferFloat.cpp',
'WebGLExtensionColorBufferHalfFloat.cpp',
'WebGLExtensionCompressedTextureATC.cpp',
'WebGLExtensionCompressedTextureES3.cpp',
'WebGLExtensionCompressedTextureETC1.cpp',
'WebGLExtensionCompressedTexturePVRTC.cpp',
'WebGLExtensionCompressedTextureS3TC.cpp',

View File

@ -4,6 +4,7 @@ skip-if = ((os == 'linux') && (buildapp == 'b2g'))
support-files =
webgl-mochitest/driver-info.js
webgl-mochitest/es3-data.js
webgl-mochitest/webgl-util.js
[webgl-mochitest/test_backbuffer_channels.html]
@ -34,6 +35,7 @@ skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests
# We haven't cleaned up the Try results yet, but let's get this on the books first.
[webgl-mochitest/test_webgl_conformance.html]
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests
[webgl-mochitest/test_webgl_compressed_texture_es3.html]
[webgl-mochitest/test_webgl_disjoint_timer_query.html]
[webgl-mochitest/test_webgl_request_context.html]
skip-if = toolkit == 'android' #bug 865443- seperate suite - the non_conf* tests pass except for one on armv6 tests

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,753 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<script src="/tests/SimpleTest/SimpleTest.js"></script>
<link rel="stylesheet" href="/tests/SimpleTest/test.css">
<script src="webgl-util.js"></script>
<script src="es3-data.js"></script>
<title>WebGL test: test WEBGL_compressed_texture_es3 extension</title>
<style>
img {
border: 1px solid black;
margin-right: 1em;
}
.testimages {
}
.testimages br {
clear: both;
}
.testimages > div {
float: left;
margin: 1em;
}
</style>
</head>
<body>
<div id="description"></div>
<canvas id="canvas" width="8" height="8"></canvas>
<div id="console"></div>
<script id="vshader" type="x-shader/x-vertex">
attribute vec4 vPosition;
attribute vec2 texCoord0;
varying vec2 texCoord;
void main() {
gl_Position = vPosition;
texCoord = texCoord0;
}
</script>
<script id="fshader" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D tex;
varying vec2 texCoord;
void main() {
gl_FragData[0] = texture2D(tex, texCoord);
}
</script>
<script id="fshader-r" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D tex;
varying vec2 texCoord;
void main() {
vec4 pixel = (texture2D(tex, texCoord));
pixel.r = (pixel.r + 1.0) / 2.0;
gl_FragData[0] = pixel;
}
</script>
<script id="fshader-rg" type="x-shader/x-fragment">
precision mediump float;
uniform sampler2D tex;
varying vec2 texCoord;
void main() {
vec4 pixel = (texture2D(tex, texCoord));
pixel.rg = (pixel.rg + 1.0) / 2.0;
gl_FragData[0] = pixel;
}
</script>
<script>
"use strict";
var ext = null;
var vao = null;
var gl = null;
var validFormats = {
COMPRESSED_R11_EAC : 0x9270,
COMPRESSED_SIGNED_R11_EAC : 0x9271,
COMPRESSED_RG11_EAC : 0x9272,
COMPRESSED_SIGNED_RG11_EAC : 0x9273,
COMPRESSED_RGB8_ETC2 : 0x9274,
COMPRESSED_SRGB8_ETC2 : 0x9275,
COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 : 0x9276,
COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 : 0x9277,
COMPRESSED_RGBA8_ETC2_EAC : 0x9278,
COMPRESSED_SRGB8_ALPHA8_ETC2_EAC : 0x9279,
};
var name;
var supportedFormats;
function setupUnitQuad() {
var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
1.0, 1.0, 0.0,
-1.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, 1.0, 0.0,
-1.0, -1.0, 0.0,
1.0, -1.0, 0.0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(0);
gl.vertexAttribPointer(0, 3, gl.FLOAT, false, 0, 0);
var vertexObject = gl.createBuffer();
gl.bindBuffer(gl.ARRAY_BUFFER, vertexObject);
gl.bufferData(gl.ARRAY_BUFFER, new Float32Array([
1.0, 1.0,
0.0, 1.0,
0.0, 0.0,
1.0, 1.0,
0.0, 0.0,
1.0, 0.0]), gl.STATIC_DRAW);
gl.enableVertexAttribArray(1);
gl.vertexAttribPointer(1, 2, gl.FLOAT, false, 0, 0);
}
function runTest() {
gl = WebGLUtil.getWebGL("canvas", false, {antialias: false});
if (!gl) {
ok(false, "WebGL context does not exist");
} else {
ok(true, "WebGL context exists");
setupUnitQuad();
// Run tests with extension disabled
runTestDisabled();
// Query the extension and store globally so shouldBe can access it
ext = gl.getExtension("WEBGL_compressed_texture_es3");
if (!ext) {
ok(true, "No WEBGL_compressed_texture_es3 support -- this is legal");
runSupportedTest(false);
} else {
ok(true, "Successfully enabled WEBGL_compressed_texture_es3 extension");
runSupportedTest(true);
runTestExtension();
}
}
SimpleTest.finish();
}
function runSupportedTest(extensionEnabled) {
var supported = gl.getSupportedExtensions();
if (supported.indexOf("WEBGL_compressed_texture_es3") >= 0) {
if (extensionEnabled) {
ok(true, "WEBGL_compressed_texture_es3 listed as supported and getExtension succeeded");
} else {
ok(false, "WEBGL_compressed_texture_es3 listed as supported but getExtension failed");
}
} else {
if (extensionEnabled) {
ok(false, "WEBGL_compressed_texture_es3 not listed as supported but getExtension succeeded");
} else {
ok(true, "WEBGL_compressed_texture_es3 not listed as supported and getExtension failed -- this is legal");
}
}
}
function runTestDisabled() {
is(gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS).length, 0,
"Should be no compressed texture formats");
}
function formatExists(format, supportedFormats) {
for (var ii = 0; ii < supportedFormats.length; ++ii) {
if (format == supportedFormats[ii]) {
ok(true, "supported format " + formatToString(format) + " is exists");
return;
}
}
ok(false, "supported format " + formatToString(format) + " does not exist");
}
function formatToString(format) {
for (var p in ext) {
if (ext[p] == format) {
return p;
}
}
return "0x" + format.toString(16);
}
function runTestExtension() {
// check that all format enums exist.
for (name in validFormats) {
is(ext[name], validFormats[name], "format is match");
}
supportedFormats = gl.getParameter(gl.COMPRESSED_TEXTURE_FORMATS);
// There should be exactly 10 formats
is(supportedFormats.length, 10, "Should be exactly 10 formats");
// check that all 10 formats exist
for (var name in validFormats.length) {
formatExists(validFormats[name], supportedFormats);
}
// Test each format
testETC2_RGB();
}
function testETC2_RGB() {
var tests = [
{
width: 4,
height: 4,
channels: 1,
data: img_4x4_r11_eac,
format: ext.COMPRESSED_R11_EAC
},
{
width: 4,
height: 4,
channels: 1,
data: img_4x4_signed_r11_eac,
format: ext.COMPRESSED_SIGNED_R11_EAC
},
{
width: 4,
height: 4,
channels: 2,
data: img_4x4_rg11_eac,
format: ext.COMPRESSED_RG11_EAC
},
{
width: 4,
height: 4,
channels: 2,
data: img_4x4_signed_rg11_eac,
format: ext.COMPRESSED_SIGNED_RG11_EAC
},
{
width: 4,
height: 4,
channels: 3,
data: img_4x4_rgb_etc2,
format: ext.COMPRESSED_RGB8_ETC2
},
{
width: 4,
height: 4,
channels: 3,
data: img_4x4_rgb_etc2,
format: ext.COMPRESSED_SRGB8_ETC2
},
{
width: 4,
height: 4,
channels: 4,
data: img_4x4_rgb_punchthrough_etc2,
format: ext.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
},
{
width: 4,
height: 4,
channels: 4,
data: img_4x4_rgb_punchthrough_etc2,
format: ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2
},
{
width: 4,
height: 4,
channels: 4,
data: img_4x4_rgba_etc2,
format: ext.COMPRESSED_RGBA8_ETC2_EAC
},
{
width: 4,
height: 4,
channels: 4,
data: img_4x4_rgba_etc2,
format: ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
},
{
width: 8,
height: 8,
channels: 1,
data: img_8x8_r11_eac,
format: ext.COMPRESSED_R11_EAC
},
{
width: 8,
height: 8,
channels: 1,
data: img_8x8_signed_r11_eac,
format: ext.COMPRESSED_SIGNED_R11_EAC
},
{
width: 8,
height: 8,
channels: 2,
data: img_8x8_rg11_eac,
format: ext.COMPRESSED_RG11_EAC
},
{
width: 8,
height: 8,
channels: 2,
data: img_8x8_signed_rg11_eac,
format: ext.COMPRESSED_SIGNED_RG11_EAC
},
{
width: 8,
height: 8,
channels: 3,
data: img_8x8_rgb_etc2,
format: ext.COMPRESSED_RGB8_ETC2
},
{
width: 8,
height: 8,
channels: 3,
data: img_8x8_rgb_etc2,
format: ext.COMPRESSED_SRGB8_ETC2
},
{
width: 8,
height: 8,
channels: 4,
data: img_8x8_rgb_punchthrough_etc2,
format: ext.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
},
{
width: 8,
height: 8,
channels: 4,
data: img_8x8_rgb_punchthrough_etc2,
format: ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2
},
{
width: 8,
height: 8,
channels: 4,
data: img_8x8_rgba_etc2,
format: ext.COMPRESSED_RGBA8_ETC2_EAC
},
{
width: 8,
height: 8,
channels: 4,
data: img_8x8_rgba_etc2,
format: ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
},
{
width: 32,
height: 32,
channels: 1,
data: img_32x32_r11_eac,
format: ext.COMPRESSED_R11_EAC
},
{
width: 32,
height: 32,
channels: 1,
data: img_32x32_signed_r11_eac,
format: ext.COMPRESSED_SIGNED_R11_EAC
},
{
width: 32,
height: 32,
channels: 2,
data: img_32x32_rg11_eac,
format: ext.COMPRESSED_RG11_EAC
},
{
width: 32,
height: 32,
channels: 2,
data: img_32x32_signed_rg11_eac,
format: ext.COMPRESSED_SIGNED_RG11_EAC
},
{
width: 32,
height: 32,
channels: 3,
data: img_32x32_rgb_etc2,
format: ext.COMPRESSED_RGB8_ETC2
},
{
width: 32,
height: 32,
channels: 3,
data: img_32x32_rgb_etc2,
format: ext.COMPRESSED_SRGB8_ETC2
},
{
width: 32,
height: 32,
channels: 4,
data: img_32x32_rgb_punchthrough_etc2,
format: ext.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2
},
{
width: 32,
height: 32,
channels: 4,
data: img_32x32_rgb_punchthrough_etc2,
format: ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2
},
{
width: 32,
height: 32,
channels: 4,
data: img_32x32_rgba_etc2,
format: ext.COMPRESSED_RGBA8_ETC2_EAC
},
{
width: 32,
height: 32,
channels: 4,
data: img_32x32_rgba_etc2,
format: ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC
},
];
testETCTextures(tests);
}
function testETCTextures(tests) {
for (var ii = 0; ii < tests.length; ++ii) {
testETCTexture(tests[ii]);
}
}
/* Return the size of block in bytes */
function getBlockSize(format) {
switch (format) {
case ext.COMPRESSED_R11_EAC:
case ext.COMPRESSED_SIGNED_R11_EAC:
case ext.COMPRESSED_RGB8_ETC2:
case ext.COMPRESSED_SRGB8_ETC2:
case ext.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
return 8;
case ext.COMPRESSED_RG11_EAC:
case ext.COMPRESSED_SIGNED_RG11_EAC:
case ext.COMPRESSED_RGBA8_ETC2_EAC:
case ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
return 16
}
}
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 (var jj = height; jj > 0; --jj) {
for (var ii = 0; ii < bytesPerLine; ++ii) {
data[dstOffset + ii] = data[srcOffset + ii];
}
srcOffset += stride;
dstOffset += stride;
}
}
function testETCTexture(test) {
var data = new Uint8Array(test.data.compressed);
var width = test.width;
var height = test.height;
var format = test.format;
var uncompressedData = new Uint8Array(test.data.decompressed);
var glErrorShouldBe = (gl, glError, msg) => {
msg = msg || "";
var err = gl.getError();
var getGLErrorAsString = err => {
if (err === gl.NO_ERROR) {
return "NO_ERROR";
}
for (var name in gl) {
if (gl[name] === err) {
return name;
}
}
return err.toString();
}
if (err != glError) {
ok(false, "getError expected: " + getGLErrorAsString(glError) +
". Was " + getGLErrorAsString(err) + " : " + msg);
} else {
ok(true, "getError was expected value: " +
getGLErrorAsString(glError) + " : " + msg);
}
};
canvas.width = width;
canvas.height = height;
gl.viewport(0, 0, width, height);
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);
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
gl.generateMipmap(gl.TEXTURE_2D);
glErrorShouldBe(gl, gl.INVALID_OPERATION, "trying to generate mipmaps from compressed texture");
if (format == ext.COMPRESSED_SIGNED_R11_EAC) {
var program = WebGLUtil.createProgramByIds(gl, 'vshader', 'fshader-r');
} else if (format == ext.COMPRESSED_SIGNED_RG11_EAC) {
var program = WebGLUtil.createProgramByIds(gl, 'vshader', 'fshader-rg');
} else {
var program = WebGLUtil.createProgramByIds(gl, 'vshader', 'fshader');
}
gl.bindAttribLocation(program, 0, 'vPosition');
gl.bindAttribLocation(program, 1, 'texCoord0');
gl.useProgram(program);
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
compareRect(width, height, test.channels, width, height, uncompressedData, data, format);
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 1, data);
glErrorShouldBe(gl, gl.INVALID_VALUE, "non 0 border");
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width + 4, height, 0, data);
glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height + 4, 0, data);
glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 4, height, 0, data);
glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 4, 0, data);
glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 1, height, 0, data);
glErrorShouldBe(gl, gl.NO_ERROR, "non multiple-of-4 supported");
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width - 2, height, 0, data);
glErrorShouldBe(gl, gl.NO_ERROR, "non multiple-of-4 supported");
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 1, 0, data);
glErrorShouldBe(gl, gl.NO_ERROR, "non multiple-of-4 supported");
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height - 2, 0, data);
glErrorShouldBe(gl, gl.NO_ERROR, "non multiple-of-4 supported");
if (width == 4) {
gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 1, height, 0, data);
glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, 2, height, 0, data);
glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
}
if (height == 4) {
gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 1, 0, data);
glErrorShouldBe(gl, gl.NO_ERROR, "valid dimensions for level > 0");
gl.compressedTexImage2D(gl.TEXTURE_2D, 1, format, width, 2, 0, data);
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_R11_EAC:
wrongFormat = ext.COMPRESSED_SIGNED_R11_EAC;
break;
case ext.COMPRESSED_SIGNED_R11_EAC:
wrongFormat = ext.COMPRESSED_R11_EAC;
break;
case ext.COMPRESSED_RG11_EAC:
wrongFormat = ext.COMPRESSED_SIGNED_RG11_EAC;
break;
case ext.COMPRESSED_SIGNED_RG11_EAC:
wrongFormat = ext.COMPRESSED_RG11_EAC;
break;
case ext.COMPRESSED_RGB8_ETC2:
wrongFormat = ext.COMPRESSED_SRGB8_ETC2;
break;
case ext.COMPRESSED_SRGB8_ETC2:
wrongFormat = ext.COMPRESSED_RGB8_ETC2;
break;
case ext.COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
wrongFormat = ext.COMPRESSED_RGB8_ETC2;
break;
case ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
wrongFormat = ext.COMPRESSED_RGB8_ETC2;
break;
case ext.COMPRESSED_RGBA8_ETC2_EAC:
wrongFormat = ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC;
break;
case ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
wrongFormat = ext.COMPRESSED_RGBA8_ETC2_EAC;
break;
}
// Restore original texture.
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height, wrongFormat, data);
glErrorShouldBe(gl, gl.INVALID_OPERATION, "format does not match");
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width + 4, height, format, data);
glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height + 4, format, data);
glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 4, height, format, data);
glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 4, format, data);
glErrorShouldBe(gl, gl.INVALID_VALUE, "data size does not match dimensions");
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, format, width, height, 0, data);
glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 1, height, format, data);
glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width - 2, height, format, data);
glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 1, format, data);
glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid dimensions");
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 0, width, height - 2, format, data);
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);
glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset");
gl.compressedTexSubImage2D(gl.TEXTURE_2D, 0, 0, 1, 4, 4, format, subData);
glErrorShouldBe(gl, gl.INVALID_OPERATION, "invalid offset");
}
if (width < 32 && height < 32) {
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);
glErrorShouldBe(gl, gl.NO_ERROR, "uploading compressed texture");
gl.clearColor(1.0, 1.0, 1.0, 1.0);
gl.clear(gl.COLOR_BUFFER_BIT);
gl.drawArrays(gl.TRIANGLES, 0, 6);
compareRect(width, height, test.channels, width, height, uncompressedData, data, format);
}
}
}
}
function insertImg(element, caption, img) {
var div = document.createElement("div");
div.appendChild(img);
var label = document.createElement("div");
label.appendChild(document.createTextNode(caption));
div.appendChild(label);
element.appendChild(div);
}
function convertToSRGB(val) {
var norm = val / 255.0;
var res = 0;
if (norm <= 0.04045) {
res = norm / 12.92;
} else {
res = Math.pow(((norm + 0.055)/1.055), 2.4);
}
return res * 255.0;
}
function makeImage(imageWidth, imageHeight, dataWidth, data, alpha) {
var scale = 8;
var c = document.createElement("canvas");
c.width = imageWidth * scale;
c.height = imageHeight * scale;
var ctx = c.getContext("2d");
for (var yy = 0; yy < imageHeight; ++yy) {
for (var xx = 0; xx < imageWidth; ++xx) {
var 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);
}
}
var img = document.createElement("img");
img.src = c.toDataURL();
return img;
}
function compareRect(actualWidth, actualHeight, actualChannels,
dataWidth, dataHeight, expectedData,
testData, testFormat)
{
var actual = new Uint8Array(actualWidth * actualHeight * 4);
gl.readPixels(
0, 0, actualWidth, actualHeight, gl.RGBA, gl.UNSIGNED_BYTE, actual);
var div = document.createElement("div");
div.className = "testimages";
var hasAlpha = actualChannels == 4;
var imgExpected = makeImage(actualWidth, actualHeight, dataWidth, expectedData, hasAlpha);
var imgActual = makeImage(actualWidth, actualHeight, actualWidth, actual, hasAlpha);
insertImg(div, "expected", imgExpected);
insertImg(div, "actual", imgActual);
div.appendChild(document.createElement('br'));
document.getElementById("console").appendChild(div);
var failed = false;
for (var yy = 0; yy < actualHeight; ++yy) {
for (var xx = 0; xx < actualWidth; ++xx) {
var actualOffset = (yy * actualWidth + xx) * 4;
var expectedOffset = (yy * dataWidth + xx) * 4;
var expected = expectedData.slice(expectedOffset, expectedOffset + 4);
var maxDiffPixel = 0;
switch (testFormat) {
case ext.COMPRESSED_SRGB8_ETC2:
case ext.COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case ext.COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
// Alpha shouldn't do conversion.
for (var i = 0; i < 3; ++i) {
expected[i] = convertToSRGB(expected[i]);
}
//fallthrough
case ext.COMPRESSED_R11_EAC:
case ext.COMPRESSED_RG11_EAC:
case ext.COMPRESSED_SIGNED_R11_EAC:
case ext.COMPRESSED_SIGNED_RG11_EAC:
// Due to floating round error, we need fuzzy test here.
var maxDiffPixel = 1;
break;
default:
var maxDiffPixel = 0;
break;
}
for (var channel = 0; channel < actualChannels; ++channel) {
var diff = Math.abs(expected[channel] - actual[actualOffset + channel]);
if (diff > maxDiffPixel) {
failed = true;
var was = actual.slice(actualOffset, actualOffset + 4).join();
ok(false, 'at (' + xx + ', ' + yy +
') expected: ' + expected.join() + ' was ' + was);
break;
}
}
}
}
if (!failed) {
ok(true, "texture rendered correctly");
}
}
var prefArrArr = [
['webgl.enable-draft-extensions', true],
];
var prefEnv = {'set': prefArrArr};
SimpleTest.waitForExplicitFinish();
SpecialPowers.pushPrefEnv(prefEnv, runTest);
</script>
</body>
</html>

View File

@ -827,6 +827,21 @@ interface WEBGL_compressed_texture_atc
const GLenum COMPRESSED_RGBA_ATC_INTERPOLATED_ALPHA_WEBGL = 0x87EE;
};
[NoInterfaceObject]
interface WEBGL_compressed_texture_es3
{
const GLenum COMPRESSED_R11_EAC = 0x9270;
const GLenum COMPRESSED_SIGNED_R11_EAC = 0x9271;
const GLenum COMPRESSED_RG11_EAC = 0x9272;
const GLenum COMPRESSED_SIGNED_RG11_EAC = 0x9273;
const GLenum COMPRESSED_RGB8_ETC2 = 0x9274;
const GLenum COMPRESSED_SRGB8_ETC2 = 0x9275;
const GLenum COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9276;
const GLenum COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2 = 0x9277;
const GLenum COMPRESSED_RGBA8_ETC2_EAC = 0x9278;
const GLenum COMPRESSED_SRGB8_ALPHA8_ETC2_EAC = 0x9279;
};
[NoInterfaceObject]
interface WEBGL_compressed_texture_etc1
{

View File

@ -54,11 +54,21 @@ GetBitsPerTexel(GLenum format, GLenum type)
case LOCAL_GL_COMPRESSED_RGB_PVRTC_4BPPV1:
case LOCAL_GL_COMPRESSED_RGBA_PVRTC_4BPPV1:
case LOCAL_GL_ETC1_RGB8_OES:
case LOCAL_GL_COMPRESSED_RGB8_ETC2:
case LOCAL_GL_COMPRESSED_SRGB8_ETC2:
case LOCAL_GL_COMPRESSED_RGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case LOCAL_GL_COMPRESSED_SRGB8_PUNCHTHROUGH_ALPHA1_ETC2:
case LOCAL_GL_COMPRESSED_R11_EAC:
case LOCAL_GL_COMPRESSED_SIGNED_R11_EAC:
return 4;
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT3_EXT:
case LOCAL_GL_COMPRESSED_RGBA_S3TC_DXT5_EXT:
case LOCAL_GL_ATC_RGBA_EXPLICIT_ALPHA:
case LOCAL_GL_ATC_RGBA_INTERPOLATED_ALPHA:
case LOCAL_GL_COMPRESSED_RGBA8_ETC2_EAC:
case LOCAL_GL_COMPRESSED_SRGB8_ALPHA8_ETC2_EAC:
case LOCAL_GL_COMPRESSED_RG11_EAC:
case LOCAL_GL_COMPRESSED_SIGNED_RG11_EAC:
return 8;
default:
break;