CanvasCompositing globalHDRHeadroom attribute
WebKittens
No response
Title of the proposal
CanvasCompositing globalHDRHeadroom attribute
URL to the spec
https://github.com/ccameron-chromium/ColorWeb-CG/blob/master/canvas2d_hdr_headroom.md
URL to the spec's repository
No response
Issue Tracker URL
https://github.com/whatwg/html/issues/11165
Explainer URL
No response
TAG Design Review URL
https://github.com/w3ctag/design-reviews/issues/917
Mozilla standards-positions issue URL
No response
WebKit Bugzilla URL
No response
Radar URL
No response
Description
This allows specifying the HDR headroom for drawing content to 2D canvas. There exist analogous APIs for WebGL and WebGPU when copying content to a 2D texture. See:
- https://github.com/gpuweb/gpuweb/issues/5236
- https://github.com/KhronosGroup/WebGL/issues/3735
Other CanvasCompositing properties globalAlpha and globalCompositeOperation have similar CSS properties. Should not CSS have a property for the headroom? For example this CSS
div { headroom: 4.5; }
will tone map all the drawing on the <div> element to this headroom. This will make sure all the pixels on this element are tone mapped to the same headroom regardless they came from images or from color-hdr.
After the div is tone mapped to headroom:4.5, what happens if the display only has headroom 2. Does it just clip then?
(There was some thought about allowing absolute headrooms to dynamic-range-limit, but so far we haven't seen a compelling need, and I think WebKit was arguing against it)
@ccameron-chromium I discussed with WebKit but it is unfortunate we are suggesting to use log2 encoding as opposed to linear encoding like CGContext uses with https://developer.apple.com/documentation/coregraphics/cgcontext/setedrtargetheadroom(_:)=objc for instance
The linear convention used by CG allows a 0 default to mean unconstrained whereas with log2 requires passing Infinity for the same behavior. It seems odd that an API surface would require passing Infinity for a common use case.
We would prefer linear encoding and a default of 0 with a similar meaning to the CG API header comment for CGContextSetEDRTargetHeadroom in CGContext.h:
Please note that the headroom value of 0.0f means "headroom unknown" which prevents tone mapping.
Re log vs linear, we'll have to do this consistently across all APIs, and we can defer deciding that. I have issues the value 0 being used in this way, but we can defer discussing that.
Let's focus on this issue, since it keeps coming up:
We would prefer [...] a default of 0 0 default to mean unconstrained
I want to make sure I understand this.
You are proposing that all images be rendered at their maximum HDR-ness, by default (as you were proposing over here as well).
The consequence of this would be that all HDR content rendered into a 2D context that has default initialization would be clipped to SDR.
In particular, consider this page: https://ccameron-chromium.github.io/ColorWeb-CG/canvas2d_hdr_headroom_example.html It does a trivial "load image and call drawImage on a canvas" for two images. The image on the left is a PQ PNG image and the image on the right is an ISO 21496-1 JPEG image.
Today, this is how it renders in Safari and all other browsers (with the exception of the image on the left in Firefox):
The behavior you are proposing is as follows:
Notice that all of the highlights are blown out.
Am I misunderstanding this?
I assume that CGContextSetEDRTargetHeadroom is for setting the content headroom?
Functionally, whether using linear values or log2 values, 0.0f for a content headroom never results in tonemapping (unless the display hypothetically had a headroom below 1.0 linear or 0.0f log2, but that would likely break all sorts of assumptions), so you always get clipping if it exceeds the display headroom - aside from documenting this fact I don't see any contention over the behavior of 0.0f in either linear or log2?
As for the linear vs log2 matter itself, I am strongly in favor of linear, with my main rationale being that there's no precedent for log2 values in any web specs (even WebGL/WebGPU have log2 only in context of mipmapping and that serves a different purpose and goes the opposite direction), and it is somewhat intuitive when specifying linear colors in CSS style syntax that you need to use RGB values less than the specified headroom that goes with them.
Edit: One thing to clarify - I am assuming a tonemapping function like Reinhard (equation 4 specifically) where the content headroom (the term Lw) being <= output headroom (which was assumed to be 1.0 in Reinhard but is easily made configurable) intuitively results in a no-op transfer function, and even if the content tonemapping function is active it's still possible for content pixels to exceed the specified content headroom and not directly break anything by doing so.
As for the linear vs log2 matter itself, I am strongly in favor of linear, with my main rationale being that there's no precedent for log2 values in any web specs
I'm pretty much the lone holdout thinking that log2 is maybe a good idea. So unless there's a huge push for log2 from somewhere, we'll probably go with linear.
I'll want to make sure to ventilate the issue in a forum that includes everyone from 2D/WebGL/GPU and CSS (ColorWeb-CG?) before giving up the issue completely.
the content headroom (the term Lw) being <= output headroom results in a no-op [tone mapping] function
Yes, that's correct. If "content headroom" <= "output headroom", then the tone mapping is a no-op[*]. Pixel values can be greater than the "content headroom" value, and they shouldn't get clamped to the "content headroom" (but they will get clamped to the "output headroom")
[*] Except if there exists an alternate representation at a higher headroom
I've moved the "linear versus log2" discussion to https://github.com/w3c/ColorWeb-CG/issues/129, which needs to decide it for CSS/2D/WebGL/WebGPU. The direction appears to be "linear is preferred", but I want to make sure all APIs cover this. (And I'm copy-pasting this message into a handful of different bugs on this issue, sorry for the spam if you see it twice).