blob: fbfd0ddb0a4ebbc6952ba36039e85b3482150860 [file] [edit]
// META: script=/webcodecs/videoFrame-rgbx-utils.js
// Uploads `frame` to a texture with texImage2D() and reads it back as RGBA.
// `format` is the format of the texture, gl.RGBA or gl.RGB. The alpha of a
// gl.RGB texture reads back as opaque.
function readTexturePixels(frame, premultiplyAlpha, format = 'RGBA') {
const canvas = document.createElement('canvas');
canvas.width = kRgbxWidth;
canvas.height = kRgbxHeight;
const gl = canvas.getContext(
'webgl', {alpha: true, premultipliedAlpha: false, antialias: false});
assert_not_equals(gl, null, 'WebGL is available');
const texture = gl.createTexture();
gl.bindTexture(gl.TEXTURE_2D, texture);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MIN_FILTER, gl.NEAREST);
gl.texParameteri(gl.TEXTURE_2D, gl.TEXTURE_MAG_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);
gl.pixelStorei(gl.UNPACK_PREMULTIPLY_ALPHA_WEBGL, premultiplyAlpha);
gl.pixelStorei(gl.UNPACK_FLIP_Y_WEBGL, false);
gl.texImage2D(
gl.TEXTURE_2D, 0, gl[format], gl[format], gl.UNSIGNED_BYTE, frame);
assert_equals(gl.getError(), gl.NO_ERROR, 'texImage2D');
// Read the texture through a framebuffer to see its exact RGBA content.
const framebuffer = gl.createFramebuffer();
gl.bindFramebuffer(gl.FRAMEBUFFER, framebuffer);
gl.framebufferTexture2D(
gl.FRAMEBUFFER, gl.COLOR_ATTACHMENT0, gl.TEXTURE_2D, texture, 0);
assert_equals(
gl.checkFramebufferStatus(gl.FRAMEBUFFER), gl.FRAMEBUFFER_COMPLETE,
'framebuffer');
const pixels = new Uint8Array(kRgbxWidth * kRgbxHeight * 4);
gl.readPixels(
0, 0, kRgbxWidth, kRgbxHeight, gl.RGBA, gl.UNSIGNED_BYTE, pixels);
assert_equals(gl.getError(), gl.NO_ERROR, 'readPixels');
gl.deleteFramebuffer(framebuffer);
gl.deleteTexture(texture);
return pixels;
}
for (const premultiplyAlpha of [false, true]) {
runRgbxTests(
`texImage2D() (premultiplyAlpha=${premultiplyAlpha})`,
(frame, description) => {
verifyOpaqueRgbxPixels(
readTexturePixels(frame, premultiplyAlpha), description);
});
}
// With a gl.RGB texture the alpha of the frame is not uploaded at all: the RGB
// values must be the same as with gl.RGBA, whatever the padding byte is.
for (const premultiplyAlpha of [false, true]) {
runRgbxTests(
`texImage2D() as RGB (premultiplyAlpha=${premultiplyAlpha})`,
(frame, description) => {
verifyOpaqueRgbxPixels(
readTexturePixels(frame, premultiplyAlpha, 'RGB'), description);
});
}
// A cloned frame is uploaded the same way.
promise_test(async t => {
const frame = makeRgbxFrame('RGBX', 0x00);
t.add_cleanup(() => frame.close());
const clone = frame.clone();
t.add_cleanup(() => clone.close());
verifyOpaqueRgbxPixels(readTexturePixels(clone, false), 'cloned frame');
}, 'texImage2D() of a cloned RGBX VideoFrame is opaque');