-
Notifications
You must be signed in to change notification settings - Fork 19
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
Clarify lifetime of textures from layers #101
Comments
Marking the texture as deleted in WebGL but not deleting it in GL (because the texture may have been provided by the device) means introducing yet another place where WebGL state and GL state disagree. |
There was already some text in the spec but I attempted to clarify it in PR #100 |
Yeah, and I'm always reluctant to introduce deviations like that. Given that the texture is going to be consumed by the compositor I don't know a more elegant path, though. The only thing that functions that way in WebGL today is the default framebuffer, and I think that our opaque framebuffer concept for the Good news longer term is that it seems like WebGPU will give us tools to handle this kind of swapchain-like behavior much more directly. |
Marking the texture as deleted after the frame ends seems like a reasonable approach. |
This brings another issue: 'static' layers (mentioned in #49). There are certain layers which are not updated at all, or updated not every frame. What is our approach in terms of texture lifetime for such cases? |
I think, we may have the following categories of layers:
|
That is already covered by the spec. A layer is only updated if the author calls |
Uhm... I don't think it is covered enough. If we do not update the layer (i.e. don't call getSubImage or getViewSubImage) - what happens to the texture's content? The intent is to have it unchanged, right? |
It's the same as what happens with
That's really up to the compositor. Once the XR animation frame ends, the compositor takes control.
Yes, this seems to be a different issue. |
|
It's tempting to solve texture lifetime by having the WebGL texture act as if it has been destroyed. However, per the Deleted Object Behavior conformance test, a deleted texture can still be usable in a framebuffer even if the texture has been deleted. So if the underlying XR implementation recycled the texture for another purpose, we have to ensure the recycled (non-portable) contents do not appear when the framebuffer it was attached to is used outside of the XR rAF. One possible solution is to spec that WebGL textures created by the XR runtime act as if they've been cleared to black when used outside of the XR rAF. This is similar to how WebGL framebuffer contents behave after invalidation behaves. Of course, it would not be acceptable for the implementation to ignore the invalidation call in the XR case. I agree with @toji that WebGPU will handle texture destruction more elegantly. In WebGPU, destroying a texture will prevent you from submitting new work to the GPU which uses the texture. |
For Oculus implementation, the swapchain textures are not destroyed / reallocated every frame, they are reused. Rendering occurs directly into the swapchain textures and these textures are used by the VR compositor, i.e. I can't invalidate or clear them to black at all. |
FYI the spec currently defines that the same textures are returned for each rAF call. |
Well, it is also wrong, because a different texture may be returned for each rAF and for each view. |
Each view might have its own texture but it would still be the same in each rAF call. |
I think it could be left to implementation. You don't have to re-create WebGLTextures each frame, but an implementation may want to rotate some pre-allocated WebGLTexture objects. Or, may rotate the underlying GL textures inside the single WebGLTexture object. Not sure we should limit implementers to this way or another. |
Unless someone complains, I will leave the spec as-is :-) |
@RafaelCintron, would this suggestion from @Artyom17 work?
Would this stop authors from writing to this texture? We want to avoid changing the texture after the rAF as that will change the pixels that are drawn by the compositor. |
Good point. Opaque framebuffer did this by forcing itself to be incomplete outside of the rAF, thus preventing you from rendering to it. My understanding is that WebGL implementations (at least in Chromium) only keep references to objects, such as framebuffers, that are bound to the WebGL context. They do not keep references to unbound framebuffers who happen to have their attachments deleted out from under them. This is why you can still "use" (render to) a texture that has been deleted while it is attached to an unbound framebuffer. To solve our problem, WebGL will have to break this behavior (at least for WebXR textures) and forcibly detach deleted textures from framebuffers when those framebuffers become re-bound to the WebGL context. |
@RafaelCintron Yes, I think, you are right. The WebXR's WebGLTexture may have a list of all framebuffers it is attached to and forcefully detach it at the end of the rAF. Do you think, it should be discussed with WebGL WG? Or we can just do it under-the-hood ? |
@Artyom17 , from looking at the code in Chromium, WebGLTexture (via its base class) only knows how many objects it is attached to, not what they are. Doing things "under the hood" requires at least the code review of respective WebGL owners. Might as well add it to the working group's agenda and get their take ahead of time. What could go wrong? :-) @kenrussell, @jdashg and @grorg. |
Instead of detaching from framebuffers, just mark the resource as (temporarily?) unrenderable. We don't want to invalidate FB completeness if we can help it, so strong vote against actually detaching resources from framebuffers. |
This is already true IIRC, and TBH it's fine. Firefox (Gecko) defers the call to glDeleteTexture until the texture is actually unused: https://searchfox.org/mozilla-central/rev/dc4560dcaafd79375b9411fdbbaaebb0a59a93ac/dom/canvas/WebGLTexture.cpp#89 |
@jdashg, if we mark textures as unrenderable, does that make their corresponding framebuffers be incomplete? If so, I presume this would invalidate FB completeness. Your "temporarily?" comment is relevant. As currently speced, you get back a new partial interface XRWebGLBinding {
XRWebGLSubImage getSubImage(XRCompositionLayer layer, XRFrame frame);
XRWebGLSubImage getViewSubImage(XRCompositionLayer layer, XRView view);
};
interface XRWebGLSubImage : XRSubImage {
[SameObject] readonly attribute WebGLTexture colorTexture;
[SameObject] readonly attribute WebGLTexture? depthStencilTexture;
readonly attribute unsigned long? imageIndex;
}; Thus, developers will end up binding new WebGL textures to framebuffers on ever frame anyways. |
No, as currently defined (and in our implementation), you will get back the same |
Coming in cold here; unfamiliar with the WebXR spec. Does this mean that correctly written WebXR applications should bind the textures in the XRWebGLSubImage to a framebuffer object every frame, but applications that don't do that - and reuse their previously set up framebuffer object from frame to frame - will happen to work on Oculus' implementation? This sounds like behavior that should be tightly defined in the WebXR spec, and be covered by rigorous conformance tests. Coming back to the question of WebGLTexture objects, I think it would be fine to specify that the WebGLTextures are invalidated in some way outside the rendering callback, and that the same WebGLTexture object is resuscitated during the next rendering callback. It would be good to discuss this with the rest of the WebGL WG, or at least put together a concrete writeup that can be commented on. |
The current thinking is that we need to unbind all the framebuffer objects at the end of the frame because the state of the textures is undefined if you're not in a rAF call.
I agree. This is why we're having this conversation. :-)
Yes, that is the part we're trying to define. |
@kenrussell should we take this up with the WebGL group? |
One drawback of (3) is potential interop issues between browsers. Suppose one UA reuses the same WebGL texture every frame (like Oculus browser does) while another one returns new WebGL textures per frame. If developers only code and test on the former browser, their site will be broken on a browser which implements the latter behavior. This scenario played out with legacy Edge and the gamepad API. Since Edge returned new gamepad objects with copies of data, sites were broken because people assumed gamepad objects were "live" like they were in Chrome. In the end, we ended up matching Chrome's behavior. We also need to decide the behavior of XR WebGL textures when they're used outside of XR rAF calls. If they're backed by swapchain textures returned by the XR runtime, there will be correctness issues if developers write to them outside of the XR rAF, or write to the wrong one even inside of the XR rAF. Making textures be non-renderable by WebGL would eliminate this portability issue. |
Contact your WebGL rep! I would add it for you, but you'll want to chat it over with them outside this issue page regardless. |
These are real concerns, but they have good company: This isn't the only aspect that changes between browsers. I think we should avoid these pitfalls where we can, but that this is a case where the benefits outweigh the risks.
I think temporarily making them non-writable is a great way do deal with this. |
I don't see any benefit here.
No, you can't read from them. This topic has diverged a bit into a discussion on lifetime and the number of textures. |
I'm trying to figure out who our rep is. |
This requires the WebGL implementation to change pretty drastically, in that |
At @cabanier's request, moving the discussion in #141 here... tl;dr: currently the per-frame updating of texture and render state is done implicitly, e.g. https://immersive-web.github.io/layers/#xrwebglsubimagetype says "The colorTexture and depthStencilTexture objects MUST only be used during the XR animation frame of the current session and MUST be made invalid once the XR animation frame completes." We could use fame updates (https://immersive-web.github.io/webxr/#frame-update) to make this explicit. |
Is the idea that we would schedule an update for each call to |
We can use frame updates to update the render state (e.g. which textures are in each subimage) at the beginning of the rAF. Slightly annoyingly, there isn't a matching hook at the end of the rAF, but if there was one we could use it to invalidate/delete/whatever the textures. |
Maybe we can add a callback to end if the current list of animation frame callbacks. |
That might work, but seems a bit brittle - we'd have to get the timing just right, after any rAF callbacks got added by user code, but before the list of rAF callbacks is read in https://immersive-web.github.io/webxr/#xr-animation-frame. |
Since we add the callback at |
@cabanier @RafaelCintron @jdashg let's try to discuss this at the upcoming WebGL working group meeting this Thursday May 21. I'll contact you all via email to try to get this set up. |
@asajeffrey @jdashg one thought - some additional state could be added to the WebGLTexture objects themselves in Mozilla's implementation so that the WebXR impl could mark them as temporarily invalid, or valid again. Hopefully, without adding too much overhead, some additional WebGL-level validation could then be done for WebGLFramebuffer objects that attach those textures, and draw calls could be rejected to those framebuffers while the textures are invalid. This could certainly impact draw-call performance even further, so would have to be carefully tested before committing to a WebXR spec change in this direction. For full correctness it would have to also handle the case where the user attempts to sample one of these WebGLTextures. |
Good point, Jeff. The texture must not be able to be rendered to, sampled, blitted or readpixeled from. It's untouchable! :-) |
@jdashg thanks for the great conversation at today's WebGL meeting. Is this your recollection as well? |
Here are some conclusions from today's WebGL working group meeting. Please correct me if there are errors.
|
#174 will address the concerns raised in this issues. |
I'd like to reopen this issue until we have agreement from the WebGL WG about using the same WebGL texture object with different GL textures backing it. |
This was discussed in the WebGL face-to-face a while ago and it was agreed that it was ok to re-use the same texture but swap out the backing. |
@cabanier ah, this has been discussed since #101 (comment) ? Are there WebGL WG meeting notes we can point to? |
I have the google doc with the meeting minutes but it's only shared with the WebGL members. |
Sorry, the WebGL working group notes are only accessible to Khronos group members. |
Okay, I'll talk to our folks on the WebGL WG. |
OK, I read over the WebGL meeting notes, it sounds like the plan is to recycle the WebGL texture objects, and only build a new one if the texture is resized. We can close this issue again, and discuss how textures become invalid and valid over in #174. |
Similar to #96, we need to make it clear that textures that are returned from
getSubImage()/getViewSubImage()
are not accessible after the frame has ended. Seems like the most reasonable path to this is to mark the WebGL texture handle as deleted once the texture has been consumed by the compositor, but we'll also need to sanity check the behavior of cases where the texture is bound either as an active texture or as a framebuffer attachment.The text was updated successfully, but these errors were encountered: