Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

There is no way to initialize a compressed 2D or 3D texture with uninitialized contents #3686

Closed
juj opened this issue Aug 23, 2024 · 2 comments · Fixed by #3688
Closed

There is no way to initialize a compressed 2D or 3D texture with uninitialized contents #3686

juj opened this issue Aug 23, 2024 · 2 comments · Fixed by #3688

Comments

@juj
Copy link
Contributor

juj commented Aug 23, 2024

According to GLES 3.0 spec, when calling glCompressedTexImage2D or glCompressedTexImage3D, if one passes a null data pointer, then a texture with uninitialized contents should be allocated in GPU memory:

image

This behavior is the same as with glTexImage2D and glTexImage3D. E.g. to create a 2D texture in WebGL with uninitialized memory contents, one can call

GL.texImage2D(target, level, internalFormat, width, height, border, format, type, null);

However, it looks like creating an uninitialized compressed 2D texture is not possible in WebGL. Attempting to run

<!DOCTYPE html><html><body><script>
var gl = document.createElement("canvas").getContext('webgl');
gl.bindTexture(gl.TEXTURE_2D, gl.createTexture());
var dxt1 = gl.getExtension('WEBGL_compressed_texture_s3tc').COMPRESSED_RGB_S3TC_DXT1_EXT;
gl.compressedTexImage2D(gl.TEXTURE_2D, 0, dxt1, 4, 4, 0, null);
</script></body></html>

generates errors in both Chrome and Firefox:

image

image

Reading the spec, in case of texImage2D, the parameter pixels is marked with a ? to be optional:

image

However for compressedTexImage2D, this optionality is not present:

image

Reading section "Differences Between WebGL and OpenGL ES 2.0" on compressed textures, there is no mention of an intentional discrepancy between passing null to texImage2D() vs compressedTextImage2D():

image

suggesting that this may be an unintentional oversight? Or if there is a rationale, it might be good to note in the above section?

This was originally found in emscripten-core/emscripten#19300.

@kenrussell
Copy link
Member

There is a supported method in WebGL 2.0 to allocate an empty compressed texture: use texStorage2D or texStorage3D. WebGL 2.0 (and OpenGL ES 3.0) added the ability to specify textures' internal formats; but only the texStorage entry points were updated to support compressed textures. See this comment in Chromium's (older) WebGL implementation path:

https://source.chromium.org/chromium/chromium/src/+/main:gpu/command_buffer/service/gles2_cmd_decoder.cc;l=12378?q=GLES2DecoderImpl::ClearCompressedTextureLevel&ss=chromium

When WebGL 2.0 was underway I don't remember whether the working group noticed that glCompressedTexImage2D was changed in OpenGL ES 3.0 to allow NULL data. Either way it would have been difficult to support this in WebGL. Web IDL would not allow WebGL 2.0 to make the ArrayBufferView nullable while leaving it required in WebGL 1.0, in the undefined compressedTexImage2D(GLenum target, GLint level, GLenum internalformat, GLsizei width, GLsizei height, GLint border, [AllowShared] ArrayBufferView data); entry point. The WG probably determined that it was better to leave this argument required in the WebGL API rather than making it nullable and introducing a new INVALID_OPERATION or INVALID_VALUE error in WebGL 1.0 after the fact.

Does this address the question? I do not think a change to WebGL's entry points should be made, but a spec clarification could be added if you think it's warranted.

@juj
Copy link
Contributor Author

juj commented Aug 23, 2024

glCompressedTexImage2D was changed in OpenGL ES 3.0 to allow NULL data.

I am not so sure that in GLES2 -> GLES3 the spec was changed to allow null data, but rather, it seems to me that the GLES2 spec accidentally omitted mentioning what should happen on a null pointer.

The only mention about what data should mean in GLES2 spec for glCompressedTexImage2D I can find is this part:

image

I think there may just have been a casual use of speech ambiguity. I could see the wording to as well been written as

"The target, level, internalformat, width, height, border and data parameters have the same meaning as in TexImage2D, except that data points to compressed image data ..."

which would have implied that data can be null. But since data referred to compressed pixels instead of uncompressed pixels, they split out that one parameter to its own sentence, and then omitting declaring at all how data should be handled.

Reading through the whole part, it looks like the GLES2 spec does not state what would happen if null is passed to glCompressedTexImage2D at all, to positive or negative.

Anyhow, what was ambiguous/unspecified then is still unspecified now, so none of that really matters here.

I don't think it is worth the effort to consider changing spec or functional browser behavior, but probably good to address these kind of subtle gotchas in documentation in the spec.

E.g. maybe add in the differences between WebGL and OpenGL ES section about Compressed Textures a part

"In OpenGL ES 2.0 the specification omitted declaring whether it should be possible to create a compressed 2D texture with uninitialized data. In WebGL 1, this is explicitly disallowed.
In OpenGL ES 3.0 it is explicitly allowed to create a compressed 2D texture with uninitialized data by passing null to CompressedTexImage2D. In WebGL 2, this is however still explicitly disallowed. Users can call TexStorage2D to work around this functional difference."

or something along those lines.

Unfortunately Emscripten will not be able to transparently use TexStorage2D/3D as a workaround to allow users to specify uninitialized compressed 2D/3D textures. This is because there is a semantic difference between (Compressed)TexImage2D/3D and TexStorage2D/3D that TexStorage generates immutable-format textures (observable via glGetTexParameter of GL_TEXTURE_IMMUTABLE_FORMAT), so there is a functional difference and resulting semantical restrictions that follow.

Of course for any engine developers, migrating from (Compressed)TexImage2D/3D to TexStorage2D/3D in this manner may be possible.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging a pull request may close this issue.

2 participants