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

[Impeller] Use MTLPixelFormatBGRA10_XR for wide gamut. #51748

Closed

Conversation

jonahwilliams
Copy link
Member

@jonahwilliams jonahwilliams commented Mar 28, 2024

Fixes flutter/flutter#142549

MTLPixelFormatBGRA10_XR is a clamped alpha format. While Skia can't decode images to this format, that doesn't matter since we're only ever sampling images and never attaching them as render targets.

@flutter-dashboard
Copy link

It looks like this pull request may not have tests. Please make sure to add tests before merging. If you need an exemption to this rule, contact "@test-exemption-reviewer" in the #hackers channel in Chat (don't just cc them here, they won't see it! Use Discord!).

If you are not sure if you need tests, consider this rule of thumb: the purpose of a test is to make sure someone doesn't accidentally revert the fix. Ask yourself, is there anything in your PR that you feel it is important we not accidentally revert back to how it was before your fix?

Reviewers: Read the Tree Hygiene page and make sure this patch meets those guidelines before LGTMing.

@jonahwilliams jonahwilliams changed the title [Impeller] Use MTLPixelFormatBGR10_XR for wide gamut. [Impeller] Use MTLPixelFormatBGRA10_XR for wide gamut. Mar 28, 2024
layer.pixelFormat = MTLPixelFormatRGBA16Float;
// MTLPixelFormatBGR10_XR was chosen since it is compatible with
// impeller's offscreen buffers which need to have transparency.
layer.pixelFormat = MTLPixelFormatBGR10_XR;
Copy link
Member

Choose a reason for hiding this comment

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

Notes from chat: We need an alpha channel, so bgra10_xr.

Comment on lines 65 to 66
} else if (pixelFormat == MTLPixelFormatBGR10_XR) {
self->_colorSpaceRef = fml::CFRef(CGColorSpaceCreateWithName(kCGColorSpaceExtendedSRGB));
Copy link
Member

@gaaclarke gaaclarke Mar 28, 2024

Choose a reason for hiding this comment

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

Notes from chat: I'm not sure how Metal interprets this combination, extended srgb with BGRA_XR. Specifically what does a red channel with the 0x3ff value interpret as? If it is 1.0, we can't represent wide gamut colors. If it's 1.0931, it will work since it's the max for displayp3, but does that mean all channels are clamped to that value? That would be a problem, or are they all interpreted different for each channel?

What we'd need for this to work is for 0x3ff to be interpreted as the maximum value for displayp3 for each channel (it's different for each one [1.09, 1.01, 1.04, 1.0]). We aren't communicating displayp3 anywhere so that's unlikely the case.

If I had to guess they have specified some arbitrary cut off of 0x3ff to represent that can handle most (all?) possible colorspaces, same thing for interpreting zero.

Copy link
Member

Choose a reason for hiding this comment

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

Something like, [0x200, 0x20, 0x20, 0x3ff] = srgb(1, 0, 0, 1)? Do they treat alpha different, where 0x3ff is one?

We also have to consider that BGRA10XR isn't available on android. We'll need f16 support at some point anyway.

Copy link
Member Author

Choose a reason for hiding this comment

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

We're not going to do wide gamut on Android this year at least, it shouldn't be a consideration.

@jonahwilliams
Copy link
Member Author

According to the docs:

The blue, green, and red components are linearly encoded in a transform from [0,2^10) to [-0.752941, 1.25098]. The formula used in this linear encoding is shader_float = (xr10_value - 384) / 510.0f.

The alpha component is always clamped to a [0.0, 1.0] range in sampling, rendering, and writing operations, despite supporting values outside this range.

@jonahwilliams
Copy link
Member Author

The missing capability in this PR is that we use Skias image codecs on iOS, which can't encode to/from MTLPixelFormatBGRA10_XR, so as is this breaks layer.toImage.

The easiest short term solution is to blit the wide gamut texture to a skia supported format, and then clean that up when we remove the skia image codecs for slimpeller.

@gaaclarke
Copy link
Member

According to the docs:

The blue, green, and red components are linearly encoded in a transform from [0,2^10) to [-0.752941, 1.25098]. The formula used in this linear encoding is shader_float = (xr10_value - 384) / 510.0f.

The alpha component is always clamped to a [0.0, 1.0] range in sampling, rendering, and writing operations, despite supporting values outside this range.

Oh, regardless of the colorspace? Interesting.

That sounds like it would solve our alpha channel problems, which is our biggest issue. In the advanced blend plus implementation I ended up clamping all channels to 1 out of caution. That means we don't get displayp3(1,0,0) drawn when plusing srgb(1,0,0) and srgb(1,0,0). We'd instead be clamping to 1.25 which is outside of the visible range for displays. I think that's good.

@gaaclarke
Copy link
Member

The missing capability in this PR is that we use Skias image codecs on iOS, which can't encode to/from MTLPixelFormatBGRA10_XR, so as is this breaks layer.toImage.

The easiest short term solution is to blit the wide gamut texture to a skia supported format, and then clean that up when we remove the skia image codecs for slimpeller.

Skia is open to PR's that expand this. I already added BGR10_XR support. BGRA10_XR shouldn't be that much different.

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