Something of a continuation of a comment thread from #14. For the sake of simplification, I'd like to examine whether or not it's possible for us to only use the current opaque framebuffer surfaces for projection layers, and force everything else to use textures in their respective APIs.
The primary benefit of doing so would be allowing the layer creation implementation and use to be significantly simpler and reduce the amount of layer factories needed.
The primary downside would be that any non-projection layers in WebGL 1.0 would not have antialiasing, and in WebGL 2.0 they would need to rely on blitting from multisampled framebuffers for antialiasing until multisample render to texture extensions are available. (WebGPU will have multisampled textures as a core feature.)
If this was an acceptable compromise, the way I see it working is like this: Either we'd drop the XRWebGLFramebufferLayerFactory
entirely, and rely solely on the current XRWebGLLayer
interface to provide framebuffer-backed projection layers OR we'd add a special-case framebuffer projection layer creation function to the XRWebGLTextureLayerFactory
(which could probably be renamed to something simpler because we no longer have to differentiate.) Then the remaining factory would take a GLenum for the texture type desired in the Projection, Quad, Cylinder, and Equirect factory methods. This would allow the developer to choose between gl.TEXTURE_2D or (if they created the factory with a WebGL 2.0 context) gl.TEXTURE_2D_ARRAY as the backing texture type. (Cube layers would always return gl.TEXTURE_CUBE_MAP textures) The fact that the user specifies it means that there's less confusion about the internal format and what framebuffer binding methods they need to use.
Possible IDL:
interface XRWebGLLayerFactory {
constructor(XRSession session, XRWebGLRenderingContext context);
double getNativeProjectionScaleFactor();
Promise<XRProjectionLayer> requestProjectionLayer(GLenum textureTarget, XRProjectionLayerInit init); // Note different dictionary
Promise<XRQuadLayer> requestQuadLayer(GLenum textureTarget, XRLayerInit init);
Promise<XRCylinderLayer> requestCylinderLayer(GLenum textureTarget, XRLayerInit init);
Promise<XREquirectLayer> requestEquirectLayer(GLenum textureTarget, XRLayerInit init);
Promise<XRCubeLayer> requestCubeLayer(XRLayerInit init);
XRWebGLTextureSubImage? getViewSubImage(XRLayer layer); // for mono layers
XRWebGLTextureSubImage? getViewSubImage(XRLayer layer, XRView view); // for stereo layers
}
The XRLayer
types don't need to change to accommodate this, but we do get to drop the XRWebGLFramebufferSubImage
interface. We'd also maybe want a new XRProjectionLayerInit
dictionary because the existing XRWebGLLayerInit
dictionary explicitly mentions framebuffer scale, which would no longer be an accurate term, and antialiasing, which is not applicable to the texture layers.
Whether or not this works for us is largely based on what kind of content we expect developers to put into non-projection layers and how willing we believe them to be to use WebGL 2.0 when antialiasing is a must. In my experience quad and cylinder layers are frequently populated with pre-rendered images or videos, for which hardware multisampling won't matter. (Equirect/Cube layers seem to be almost exclusively used with prerendered content.) UIs seem to be the other primary use, and so that would hit some limitations, but they may be largely mitigated by finding a way to enable DOM content in layers, at which point the browser's renderer is expected to do any antialiasing for us. The remaining cases can treat antialiasing of those layers as a quality enhancement that can be provided by using WebGL 2.0.
Thoughts?