Source code
Revision control
Copy as Markdown
Other Tools
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8"/>
<link rel="stylesheet" href="../../resources/js-test-style.css"/>
<script src="../../js/js-test-pre.js"></script>
<script src="../../js/webgl-test-utils.js"></script>
</head>
<body>
<div id="description"></div>
<div id="console"></div>
<canvas id="canvas" width="16" height="16" style="width: 50px; height: 50px; border: 1px solid black;"></canvas>
<!-- Shaders to test output -->
<script id="vertexShader" type="x-shader/x-vertex">
attribute vec4 aPosition;
void main() {
gl_Position = aPosition;
}
</script>
<script id="fragmentShader" type="x-shader/x-fragment">
precision mediump float;
uniform float uColor;
void main() {
gl_FragColor = vec4(uColor, uColor, uColor, 1);
}
</script>
<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_FragColor = texture2D(tex, texCoord);
}
</script>
<script>
"use strict";
var wtu = WebGLTestUtils;
var canvas;
var gl;
var ext = null;
var extConstants = {
"SRGB_EXT": 0x8C40,
"SRGB_ALPHA_EXT": 0x8C42,
"SRGB8_ALPHA8_EXT": 0x8C43,
"FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT": 0x8210
};
function getExtension() {
ext = gl.getExtension("EXT_sRGB");
}
function listsExtension() {
var supported = gl.getSupportedExtensions();
return (supported.indexOf("EXT_sRGB") >= 0);
}
function toVec3String(val) {
if (typeof(val) == 'number') {
return toVec3String([val, val, val]);
}
return '[' + val[0] + ', ' + val[1] + ', ' + val[2] + ']';
}
var e = 2; // Amount of variance to allow in result pixels - may need to be tweaked higher
function expectResult(target) {
wtu.checkCanvasRect(gl,
Math.floor(gl.drawingBufferWidth / 2),
Math.floor(gl.drawingBufferHeight / 2),
1,
1,
[target, target, target, 255],
undefined,
e);
}
function createGreysRGBTexture(gl, color, format) {
var numPixels = gl.drawingBufferWidth * gl.drawingBufferHeight;
var elements;
switch (format) {
case ext.SRGB_EXT: elements = 3; break;
case ext.SRGB_ALPHA_EXT: elements = 4; break;
default: return null;
}
var size = numPixels * elements;
var buf = new Uint8Array(size);
for (var ii = 0; ii < numPixels; ++ii) {
var off = ii * elements;
buf[off + 0] = color;
buf[off + 1] = color;
buf[off + 2] = color;
if (format == ext.SRGB_ALPHA_EXT) {
buf[off + 3] = 255;
}
}
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D,
0,
format,
gl.drawingBufferWidth,
gl.drawingBufferHeight,
0,
format,
gl.UNSIGNED_BYTE,
buf);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_FILTER, gl.LINEAR);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
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);
return tex;
}
function testValidFormat(fn, internalFormat, formatName, enabled) {
if (enabled) {
fn(internalFormat);
wtu.glErrorShouldBe(gl, gl.NO_ERROR, "was able to create type " + formatName);
} else {
testInvalidFormat(fn, internalFormat, formatName, enabled);
}
}
function testInvalidFormat(fn, internalFormat, formatName, enabled) {
fn(internalFormat);
var err = gl.getError();
if (err == gl.NO_ERROR) {
testFailed("should NOT be able to create type " + formatName);
} else if (err == gl.INVALID_ENUM || err == gl.INVALID_VALUE) {
testPassed("not able to create invalid format: " + formatName);
}
}
var textureFormatFixture = {
desc: "Checking texture formats",
create: function(format) {
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D,
0, // level
format, // internalFormat
gl.drawingBufferWidth, // width
gl.drawingBufferHeight, // height
0, // border
format, // format
gl.UNSIGNED_BYTE, // type
null); // data
},
tests: [
{
desc: "Checking valid formats",
fn: testValidFormat,
formats: [ 'SRGB_EXT', 'SRGB_ALPHA_EXT' ]
},
{
desc: "Checking invalid formats",
fn: testInvalidFormat,
formats: [ 'SRGB8_ALPHA8_EXT' ]
}
]
};
var renderbufferFormatFixture = {
desc: "Checking renderbuffer formats",
create: function(format) {
var rbo = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
gl.renderbufferStorage(gl.RENDERBUFFER,
format,
gl.drawingBufferWidth,
gl.drawingBufferHeight);
},
tests: [
{
desc: "Checking valid formats",
fn: testValidFormat,
formats: [ 'SRGB8_ALPHA8_EXT' ]
},
{
desc: "Checking invalid formats",
fn: testInvalidFormat,
formats: [ 'SRGB_EXT', 'SRGB_ALPHA_EXT' ]
}
]
};
description("Test sRGB texture support");
debug("");
debug("Canvas.getContext");
canvas = document.getElementById("canvas");
gl = wtu.create3DContext(canvas);
if (!gl) {
testFailed("context does not exist");
} else {
testPassed("context exists");
debug("");
debug("Checking sRGB texture support with extension disabled");
runFormatTest(textureFormatFixture, false);
runFormatTest(renderbufferFormatFixture, false);
{
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
debug("Checking getFramebufferAttachmentParameter with a renderbuffer");
{
var rbo = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
gl.renderbufferStorage(gl.RENDERBUFFER, gl.RGB565, 1, 1);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.RENDERBUFFER, rbo);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 0x8210 /* FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT */)');
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM);
gl.bindRenderbuffer(gl.RENDERBUFFER, null);
gl.deleteRenderbuffer(rbo);
}
debug("Checking getFramebufferAttachmentParameter with a texture");
{
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, gl.RGBA, 1, 1, 0, gl.RGBA, gl.UNSIGNED_BYTE, null);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
shouldBeNull('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, 0x8210 /* FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT */)');
wtu.glErrorShouldBe(gl, gl.INVALID_ENUM);
gl.bindTexture(gl.TEXTURE_2D, null);
gl.deleteTexture(tex);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
gl.deleteFramebuffer(fbo);
}
debug("");
debug("Checking sRGB texture support");
// Query the extension and store globally so shouldBe can access it
ext = gl.getExtension("EXT_sRGB");
if (!ext) {
testPassed("No EXT_sRGB support -- this is legal");
runSupportedTest(false);
finishTest();
} else {
testPassed("Successfully enabled EXT_sRGB extension");
runSupportedTest(true);
gl.viewport(0, 0, gl.drawingBufferWidth, gl.drawingBufferHeight);
runConstantsTest();
runFormatTest(textureFormatFixture, true);
runFormatTest(renderbufferFormatFixture, true);
runTextureReadConversionTest();
runFramebufferTextureConversionTest(ext.SRGB_EXT);
runFramebufferTextureConversionTest(ext.SRGB_ALPHA_EXT);
runFramebufferRenderbufferConversionTest();
runGenerateMipmapTest();
runLoadFromImageTest(function() {
finishTest();
});
}
}
function runConstantsTest() {
debug("");
debug("Checking extension constants values");
for (var constant in extConstants) {
if (constant in ext) {
if (extConstants[constant] != ext[constant]) {
testFailed("Value of " + constant + " should be: " + extConstants[constant] + ", was: " + ext[constant]);
} else {
testPassed("Value of " + constant + " was expected value: " + extConstants[constant]);
}
} else {
testFailed(constant + " not found in extension object");
}
}
}
function runSupportedTest(extensionEnabled) {
if (listsExtension()) {
if (extensionEnabled) {
testPassed("EXT_sRGB listed as supported and getExtension succeeded");
} else {
testFailed("EXT_sRGB listed as supported but getExtension failed");
}
} else {
if (extensionEnabled) {
testFailed("EXT_sRGB not listed as supported but getExtension succeeded");
} else {
testPassed("EXT_sRGB not listed as supported and getExtension failed -- this is legal");
}
}
}
function runFormatTest(fixture, enabled) {
debug("");
debug(fixture.desc);
for (var tt = 0; tt < fixture.tests.length; ++tt) {
var test = fixture.tests[tt];
debug(test.desc);
for (var ii = 0; ii < test.formats.length; ++ii) {
var formatName = test.formats[ii];
test.fn(fixture.create, extConstants[formatName], "ext." + formatName, enabled);
}
if (tt != fixture.tests.length - 1)
debug("");
}
}
function runTextureReadConversionTest() {
debug("");
debug("Test the conversion of colors from sRGB to linear on texture read");
// Draw
var conversions = [
[ 0, 0 ],
[ 63, 13 ],
[ 127, 54 ],
[ 191, 133 ],
[ 255, 255 ]
];
var program = wtu.setupTexturedQuad(gl);
gl.uniform1i(gl.getUniformLocation(program, "tex"), 0);
for (var ii = 0; ii < conversions.length; ii++) {
var tex = createGreysRGBTexture(gl, conversions[ii][0], ext.SRGB_EXT);
wtu.drawUnitQuad(gl);
expectResult(conversions[ii][1]);
}
}
function runFramebufferTextureConversionTest(format) {
var formatString;
var validFormat;
switch (format) {
case ext.SRGB_EXT: formatString = "sRGB"; validFormat = false; break;
case ext.SRGB_ALPHA_EXT: formatString = "sRGB_ALPHA"; validFormat = true; break;
default: return null;
}
debug("");
debug("Test " + formatString + " framebuffer attachments." + (validFormat ? "" : " (Invalid)"));
var program = wtu.setupProgram(gl, ['vertexShader', 'fragmentShader'], ['aPosition'], [0]);
var tex = createGreysRGBTexture(gl, 0, format);
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferTexture2D(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, tex, 0);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT)', 'ext.SRGB_EXT');
if (validFormat) {
shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
debug("");
debug("Test the conversion of colors from linear to " + formatString + " on framebuffer (texture) write");
// Draw
var conversions = [
[ 0, 0 ],
[ 13, 63 ],
[ 54, 127 ],
[ 133, 191 ],
[ 255, 255 ]
];
wtu.setupUnitQuad(gl, 0);
for (var ii = 0; ii < conversions.length; ii++) {
gl.uniform1f(gl.getUniformLocation(program, "uColor"), conversions[ii][0]/255.0);
wtu.drawUnitQuad(gl, [0, 0, 0, 0]);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
expectResult(conversions[ii][1]);
}
} else {
shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_INCOMPLETE_ATTACHMENT");
wtu.setupUnitQuad(gl, 0);
gl.uniform1f(gl.getUniformLocation(program, "uColor"), 0.5);
wtu.drawUnitQuad(gl, [0, 0, 0, 0]);
wtu.glErrorShouldBe(gl, gl.INVALID_FRAMEBUFFER_OPERATION);
}
gl.bindFramebuffer(gl.FRAMEBUFFER, null);
}
function runFramebufferRenderbufferConversionTest() {
debug("");
debug("Test the conversion of colors from linear to sRGB on framebuffer (renderbuffer) write");
function createsRGBFramebuffer(gl, width, height) {
var rbo = gl.createRenderbuffer();
gl.bindRenderbuffer(gl.RENDERBUFFER, rbo);
gl.renderbufferStorage(gl.RENDERBUFFER, ext.SRGB8_ALPHA8_EXT, width, height);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
var fbo = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, fbo);
gl.framebufferRenderbuffer(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0,
gl.RENDERBUFFER, rbo);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
shouldBe('gl.getFramebufferAttachmentParameter(gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, ext.FRAMEBUFFER_ATTACHMENT_COLOR_ENCODING_EXT)', 'ext.SRGB_EXT');
shouldBe("gl.checkFramebufferStatus(gl.FRAMEBUFFER)", "gl.FRAMEBUFFER_COMPLETE");
return fbo;
}
// Draw
var conversions = [
[ 0, 0 ],
[ 13, 63 ],
[ 54, 127 ],
[ 133, 191 ],
[ 255, 255 ]
];
var program = wtu.setupProgram(gl, ['vertexShader', 'fragmentShader'], ['aPosition'], [0]);
wtu.setupUnitQuad(gl, 0);
var fbo = createsRGBFramebuffer(gl, gl.drawingBufferWidth, gl.drawingBufferHeight);
for (var ii = 0; ii < conversions.length; ii++) {
gl.uniform1f(gl.getUniformLocation(program, "uColor"), conversions[ii][0]/255.0);
wtu.drawUnitQuad(gl, [0, 0, 0, 0]);
expectResult(conversions[ii][1]);
}
}
function runLoadFromImageTest(callback) {
debug("");
debug("Tests to ensure that SRGB textures can successfully use image elements as their source");
var img = wtu.makeImage("../../resources/gray-1024x1024.jpg", function() {
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, ext.SRGB_EXT, ext.SRGB_EXT, gl.UNSIGNED_BYTE, img);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
gl.texImage2D(gl.TEXTURE_2D, 0, ext.SRGB_ALPHA_EXT, ext.SRGB_ALPHA_EXT, gl.UNSIGNED_BYTE, img);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
callback();
}, function() {
testFailed("Image could not be loaded");
callback();
});
}
function runGenerateMipmapTest()
{
debug("");
debug("GenerateMipmaps for sRGB textures is forbidden");
var tex = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, tex);
gl.texImage2D(gl.TEXTURE_2D, 0, ext.SRGB_ALPHA_EXT, 2, 2, 0, ext.SRGB_ALPHA_EXT,
gl.UNSIGNED_BYTE, null);
wtu.glErrorShouldBe(gl, gl.NO_ERROR);
gl.generateMipmap(gl.TEXTURE_2D);
wtu.glErrorShouldBe(gl, gl.INVALID_OPERATION);
gl.deleteTexture(tex);
}
var successfullyParsed = true;
</script>
</body>
</html>