Repository navigation
feat(macos): EDR and HDR PQ/HLG presentation modes for the Metal view - #69
Merged
Merged
Conversation
The Metal presentation path rendered into an RGBA16F FBO but copied every
frame into a 10-bit unorm IOSurface, clipping everything above SDR white,
so it was 10-bit SDR only despite the layer requesting EDR. The IOSurface
colorspace tag was also ineffective: it was set with IOSurfaceSetValue()
under kCVImageBufferCGColorSpaceKey, which stores a private "CGColorSpace"
key rather than the IOSurfaceColorSpace attachment Core Animation reads.
Add MetalPresentationFormat, a small Qt-free module describing each mode
(IOSurface pixel format, matching GL formats, colorspace) and creating
correctly tagged IOSurfaces through CoreVideo:
sdr 10-bit ARGB2101010, sRGB (default; unchanged behaviour)
edr 64RGBAHalf, extended sRGB: IPCore's unclamped sRGB-encoded output
passes through, values above 1.0 use the display's EDR headroom
pq 10-bit, ITU-R BT.2100 PQ (for SMPTE 2084 / OCIO PQ display output)
hlg 10-bit, ITU-R BT.2100 HLG
QTMetalVideoDevice's zero-copy ring and CPU fallback, and MetalView's
fallback upload, now use the selected format. The mode is chosen once per
process from UTV_MACOS_PRESENTATION or Preferences -> Rendering -> macOS
Presentation (Display/macosPresentation). MetalView logs the display's
current/potential EDR headroom when an HDR mode is active.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Signed-off-by: Michael Oliver <mcoliver@gmail.com>
- MetalPresentationTest (macOS, headless): checks each mode's IOSurface pixel format and colorspace tag, then blits an RGBA16F render FBO into the IOSurface as QTMetalVideoDevice does and reads it back: EDR keeps 4.0, SDR clips to 1.0, PQ/HLG keep 10-bit precision. - docs/testing/macos-edr.md: how to select a mode and a three-tile 1x/2x/4x check that works on built-in Apple displays. - README: describe the macOS SDR/EDR/HDR modes accurately. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Michael Oliver <mcoliver@gmail.com>
This was referenced Sep 30, 2026
# Conflicts: # src/test/CMakeLists.txt Signed-off-by: Michael Oliver <mcoliver@gmail.com>
CI builds the main_executable target, not ALL, so the test executable was never built there and ctest reported it as "Not Run". Stage it with RV_STAGE like FastMemcpyTest and QFontTest, which adds it to main_executable. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Signed-off-by: Michael Oliver <mcoliver@gmail.com>
mcoliver
marked this pull request as ready for review
September 30, 2026 17:37
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds EDR and HDR (PQ/HLG) presentation to the macOS Metal view. SDR stays the default.
What was wrong
RGBA16FFBO, then copies each frame into a 10-bit unorm IOSurface. So the output was 10-bit SDR, even though the layer setswantsExtendedDynamicRangeContentand the README claimed EDR.IOSurfaceSetValue(surf, kCVImageBufferCGColorSpaceKey, cs)stores a privateCGColorSpacekey, not theIOSurfaceColorSpaceattachment Core Animation reads.Changes
MetalPresentationFormat(new, Qt-free): defines each mode (IOSurface pixel format, matching GL formats, colorspace) and creates IOSurfaces tagged through CoreVideo (CVBufferSetAttachment), which writesIOSurfaceColorSpace/IOSurfaceColorSpaceID.sdr(default)edrpqhlgQTMetalVideoDevice/MetalView: the zero-copy ring, the CPU fallback and the fallback upload now use the selected format.Choosing a mode: it's read once at startup from
UTV_MACOS_PRESENTATIONor Preferences → Rendering → macOS Presentation (Display/macosPresentation). The control is added in code (macOS only), so the shared.uifiles don't change.Logging: when an HDR mode is active, the display's current/potential EDR headroom is logged.
README: now describes the macOS modes accurately.
docs/testing/macos-edr.mdhas test instructions.Verification (Apple Silicon, macOS 27)
MetalPresentationTest(headless, doctest, 41 assertions). For each mode it checks the IOSurface pixel format and colorspace tag. It then runs the same GL path as the zero-copy ring (RGBA16F FBO → blit → IOSurface-backed texture) and reads the IOSurface back:utviorenders linear 4.0 with-outsrgbas 1.825, exactly the extended-sRGB value.ctest: 119/119 pass.Not yet verified
cteststep lands. On GPU-less runners it falls back to the software renderer and skips the GL round trip if IOSurface binding is unavailable.Follow-ups
NSScreennotifications.HDRExtendedDisplayP3Linear/ scRGB / HDR10) behind the same format abstraction.🤖 Generated with Claude Code