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

Propose WEBGL_present, allowing for early Present. #2564

Open
wants to merge 3 commits into
base: main
Choose a base branch
from

Conversation

kdashg
Copy link
Contributor

@kdashg kdashg commented Dec 19, 2017

No description provided.

@greggman
Copy link
Contributor

Can the same thing effectively be accomplished with OffscreenCanvas?

@kdashg
Copy link
Contributor Author

kdashg commented Dec 19, 2017

OffscreenCanvas support isn't imminent, and this is actually a subset of what OffscreenCanvas does with respect to Present. OffscreenCanvas bypasses the Present-to-compositor completely, whereas this just Presents early.

@toji
Copy link
Member

toji commented Dec 19, 2017

Interesting idea for an extension, I can see how it may be useful. The concept could benefit VR. I feel like it needs some more detail around various edge cases, though:

  • What's the behavior when you present multiple times before returning control to the browser
  • What's the behavior when you present without dirtying the context
  • Is there any guarantee around when the presented content is shown on screen? (I could see some browsers accidentally showing it later than normal if they're not careful.)
  • Related: does calling present on multiple contexts in the same callback ensure synchronous display? (This would be easy behavior for browsers to diverge on)

Most of these feel like they have unsurprising answers, but it's probably worth documenting the behavior in the extension text regardless.

Finally, exposing autoPresent as an attribute feels a little odd. Do any other extensions have similar behavior? It should work, since the WebGL spec dictates that the same object is returned from the getExtension call, just seems like a break in convention. (That's a pretty minor nit, though.)

@kdashg
Copy link
Contributor Author

kdashg commented Dec 19, 2017

The intent is that present() triggers our html-Present code early:

  • swap backbuffer to front
  • clear the dirty bit on the context
  • if !preserveDrawingBuffer, invalidate/clear the backbuffer

Since we're reusing this concept of html-Present, all of your edge cases have clear answers to me. We're just Presenting to the conceptual html compositor early, so we have the same frame atomicity rules as usual, as well as the same logic around dirtying. This all (to me) falls directly out of invoking the html-Present concept.

autoPresent is a little of an experiment. The painfully traditional approach would be to add an enum to the ext for use with enable/disable/isEnabled. It would be nice if we could just use js getters and setters, particularly since this API has no mirror in native APIs.

@kdashg
Copy link
Contributor Author

kdashg commented Dec 19, 2017

I suppose what's not clear is that this call doesn't immediately invoke html-composition, but instead waits for end-of-frame like normal.

@toji
Copy link
Member

toji commented Dec 19, 2017

Thanks! That does help clarify. A couple more questions:

If you draw, call present, then draw again before the control is returned to the browser and autoPresent is still true, my reading of this is that the second draw would be the one composited to the screen, correct?

Finally, if this does not immediately trigger page composition then it seems you could largely get the same behavior with a flush call. What scenarios do you envision this assisting? (I mentioned VR earlier, but that would mostly benefit from an early composite.) The main thing that jumps out at me is beginning work for subsequent frames early, but I'm curious what you had in mind.

@kdashg
Copy link
Contributor Author

kdashg commented Dec 19, 2017

If you draw after present(), with autoPresent=true, the second draw is composited that frame.

This is a stronger statement than a flush(). In particular, we can't tell whether a flush is indicating the end of frame or not. This means that if we assume flush() indicates the end of a frame, multiple flushes in a frame would cause multiple multisample-resolve-and-fence steps. We definitely flush on present(), but it's not all we do.

@RafaelCintron
Copy link
Member

RafaelCintron commented Dec 20, 2017

I am confused by the purpose of this extension. Is it for performance so we can trigger page composition early? If so, then this will break the existing frame rules because the WebGL frame is meant to appear as one unit with all of the other DOM manipulations you do as part of the rAF and other event handlers that fire after it. Is that by design?

Similarly, what happens in the case where there are multiple WebGL contexts on the page at once? Is the browser meant to wait until all of them have had a chance to present before starting to draw the page?

If we were to adopt this extension, I think we should prevent more than one present call per rAF callback. For Edge, we throttle rAF callbacks with the amount of work the GPU is able to retire in order to create a smooth experience. We skip VSyncs if there are more than 2 frames outstanding. I fear that enabling developers to draw more than one frame per rAF callback will lead to content that appears to work well on some machines but bogs down machines with limited GPU capabilities and end up triggering our hang resistance logic.

@kdashg
Copy link
Contributor Author

kdashg commented Dec 20, 2017

In Present, if the backbuffer is dirty, we resolve from the multisampled backbuffer to the single-sampled compositable surface, enqueue a fence/release a KeyedMutex that will tell us when the single-sampled resource is ready, and flush the driver.
Without this extension, this all happens at the end of a frame, and then the compositor is immediately waiting on that fence/KeyedMutex in order to render the page.
With this extension, we can move the Present of the backbuffer earlier in the frame, allowing for reduced latency.

Copy link
Member

@kenrussell kenrussell left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Small comment not addressing the higher-level questions raised by others.

<code>autoPresent</code> disables (or re-enables) the default backbuffer-dirty auto-Present.
When disabled, the context will not automatically Present its backbuffer to the compositor
even if the backbuffer has been drawn into.
In this case, <code>present()</code> is the only way trigger Presentation of the backbuffer
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

way trigger -> way to trigger

@kenrussell
Copy link
Member

Per discussions in the working group: @jdashg will prototype the OffscreenCanvas's transferToImageBitmap API, which should allow this present() API to be polyfilled from JavaScript for experimentation purposes.

@kdashg
Copy link
Contributor Author

kdashg commented Jan 6, 2018

I'd like to explicitly credit @toji with the transferToImageBitmap idea.

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 this pull request may close these issues.

5 participants