Commit 42f3a3c
committed
Metal: add SDR offscreen for menu composite in HDR mode
Fixes menu / overlay / OSD appearing incorrectly on the HDR backbuffer —
elevated blacks on scRGB, dim on HDR10 — caused by stock SDR pipelines
writing sRGB-encoded bytes directly into a PQ or linear-FP16 drawable.
Architecture mirrors Vulkan's equivalent fix (12d188e, Jan 2026):
menu / overlay / OSD / widgets render into a BGRA8 SDR offscreen; at
end of frame, two sequential composite passes fold the core video and
the SDR UI into the HDR drawable.
Render pipeline (HDR mode)
shader chain final pass / frame texture (core source)
|
v hdrComposite pass 1 (core, blending off, clear)
|
+ hdrComposite pass 2 (menu, alpha blend, load):
| sample _sdrOverlayTex
|
v
CAMetalLayer drawable (HDR10 / scRGB)
menu / overlay / OSD draws -> _sdrOverlayTex (BGRA8, drawable-
sized, cleared to transparent
black at rce acquire)
Key changes
* Stock / clear / menu / font pipelines now compile against
BGRA8Unorm unconditionally. Matches drawable format in SDR mode
(identical behaviour) and matches _sdrOverlayTex in HDR mode.
* Context rce getter is HDR-aware: in HDR mode it lazily opens a
render encoder on _sdrOverlayTex cleared to transparent black and
sets an _sdrOverlayDirty flag; SDR mode unchanged.
* hdrComposite does two sequential passes on the drawable:
- Core pass: blending off, load=Clear. Composite fragment
emits alpha=0 outside CoreViewport so the clear colour is
preserved in letterbox / pillarbox areas. When the caller
has no core source (fresh driver init, pre-first-frame),
degenerates to a clear-only pass so the drawable is never
presented with uninitialised memory.
- Menu pass: blending on (SRC_ALPHA / ONE_MINUS_SRC_ALPHA),
load=Load. Runs only when _sdrOverlayDirty is set (skipped
if no UI was drawn this frame). Samples _sdrOverlayTex with
SDR-source semantics and menu-specific uniforms
(BrightnessNits <- PaperWhiteNits, InverseTonemap forced on
in both HDR modes so the sRGB-decode path runs and the
scRGB passthrough shortcut is bypassed, Scanlines cleared).
Metal's blend unit alpha-composites the encoded result over
the core.
* Composite fragment reworked:
- Takes a CoreViewport (float4: xy=origin, zw=size in pixels)
uniform and covers the full drawable. Inside the rect the
mode branches run against remapped UVs; outside the rect
it emits float4(0,0,0,0).
- Re-shaped but logically equivalent mode-1/2/3 branches
preserve shader-emitted-HDR passthrough for core content.
* New HDRUniforms field PaperWhiteNits drives UI paper-white
independently of core paper-white (BrightnessNits). setHDRMenuNits
now populates it (previously a no-op — the dropped _pad0 slot is
replaced).
* Two new pipeline variants per HDR output mode — menu-composite
pipelines with blending enabled — created through a shared
makeComposite block. Readiness check at HDR enable updated.
* Context ivars: _sdrOverlayTex (BGRA8, Private, drawable-sized),
_sdrOverlayW, _sdrOverlayH, _sdrOverlayDirty. Allocated in
resizeHDRResourcesForWidth:height: alongside _hdrReadbackTex,
freed when HDR is disabled.
* MetalDriver.setViewportWidth:height: propagates to
Context.resizeHDRResourcesForWidth:height: so the SDR overlay
tracks window resizes. _resizeHDRResourcesForWidth:height:
renamed to the public resizeHDRResourcesForWidth:height: and
declared in metal_common.h.
* renderFrame refactored: single lazy rce acquisition at top
(routes correctly by mode); menu / overlay / OSD / widgets /
message all draw via this rce (into SDR overlay in HDR, into
drawable in SDR); hdrComposite fires at end-of-frame just
before _endFrame. The mid-frame composite + follow-on drawable
rce dance is gone.
Result
scRGB menu no longer shows elevated blacks / medium-gray backgrounds —
the overlay now decodes as sRGB, scales against menu paper-white, and
blends standardly. HDR10 menu remains visually correct. HDR-to-HDR
mode switches (HDR10 <-> scRGB) no longer flash the drawable green or
blue on the first post-reinit frame. No SDR-mode behaviour change.
Files
gfx/common/metal/metal_shader_types.h : +PaperWhiteNits,
+CoreViewport.
gfx/common/metal/Shaders.metal : hdr_composite_fragment
rewritten for full-drawable
coverage with CoreViewport
clip; mode branches
preserved.
gfx/common/metal_common.h : resizeHDRResourcesForWidth
is public.
gfx/drivers/metal.m : SDR overlay ivars + alloc /
free; HDR-aware rce getter;
two-pass hdrComposite with
clear-only fallback; BGRA8
pipelines; resize
propagation; setHDRMenuNits
wires PaperWhiteNits.1 parent 6040eac commit 42f3a3c
4 files changed
Lines changed: 426 additions & 196 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
802 | 802 | | |
803 | 803 | | |
804 | 804 | | |
805 | | - | |
806 | | - | |
807 | | - | |
808 | | - | |
809 | | - | |
| 805 | + | |
| 806 | + | |
| 807 | + | |
| 808 | + | |
| 809 | + | |
| 810 | + | |
| 811 | + | |
| 812 | + | |
| 813 | + | |
| 814 | + | |
| 815 | + | |
| 816 | + | |
| 817 | + | |
| 818 | + | |
| 819 | + | |
| 820 | + | |
| 821 | + | |
| 822 | + | |
| 823 | + | |
| 824 | + | |
| 825 | + | |
| 826 | + | |
| 827 | + | |
| 828 | + | |
| 829 | + | |
| 830 | + | |
| 831 | + | |
| 832 | + | |
| 833 | + | |
| 834 | + | |
| 835 | + | |
| 836 | + | |
| 837 | + | |
| 838 | + | |
| 839 | + | |
810 | 840 | | |
811 | 841 | | |
812 | 842 | | |
813 | 843 | | |
814 | 844 | | |
815 | 845 | | |
| 846 | + | |
| 847 | + | |
| 848 | + | |
| 849 | + | |
| 850 | + | |
| 851 | + | |
| 852 | + | |
| 853 | + | |
| 854 | + | |
| 855 | + | |
| 856 | + | |
| 857 | + | |
| 858 | + | |
| 859 | + | |
816 | 860 | | |
817 | 861 | | |
818 | 862 | | |
819 | | - | |
| 863 | + | |
820 | 864 | | |
821 | 865 | | |
822 | 866 | | |
823 | 867 | | |
824 | 868 | | |
825 | | - | |
826 | | - | |
827 | | - | |
828 | | - | |
| 869 | + | |
| 870 | + | |
| 871 | + | |
829 | 872 | | |
830 | | - | |
831 | | - | |
832 | | - | |
833 | | - | |
834 | | - | |
| 873 | + | |
835 | 874 | | |
836 | | - | |
837 | | - | |
838 | | - | |
839 | 875 | | |
840 | 876 | | |
841 | | - | |
842 | | - | |
| 877 | + | |
| 878 | + | |
| 879 | + | |
843 | 880 | | |
844 | 881 | | |
845 | | - | |
846 | | - | |
847 | | - | |
848 | | - | |
849 | | - | |
850 | | - | |
851 | | - | |
| 882 | + | |
| 883 | + | |
| 884 | + | |
| 885 | + | |
| 886 | + | |
852 | 887 | | |
853 | 888 | | |
854 | 889 | | |
855 | 890 | | |
856 | | - | |
857 | | - | |
858 | | - | |
| 891 | + | |
859 | 892 | | |
860 | | - | |
| 893 | + | |
861 | 894 | | |
862 | | - | |
863 | 895 | | |
864 | 896 | | |
865 | 897 | | |
866 | 898 | | |
867 | 899 | | |
868 | 900 | | |
869 | | - | |
| 901 | + | |
870 | 902 | | |
871 | 903 | | |
872 | 904 | | |
873 | 905 | | |
874 | | - | |
875 | | - | |
876 | | - | |
| 906 | + | |
| 907 | + | |
| 908 | + | |
877 | 909 | | |
878 | 910 | | |
879 | | - | |
880 | | - | |
| 911 | + | |
| 912 | + | |
881 | 913 | | |
882 | 914 | | |
| 915 | + | |
883 | 916 | | |
884 | 917 | | |
885 | | - | |
886 | | - | |
887 | | - | |
888 | | - | |
889 | | - | |
890 | | - | |
| 918 | + | |
| 919 | + | |
| 920 | + | |
| 921 | + | |
| 922 | + | |
| 923 | + | |
891 | 924 | | |
892 | 925 | | |
893 | | - | |
894 | | - | |
895 | | - | |
896 | | - | |
897 | | - | |
| 926 | + | |
| 927 | + | |
| 928 | + | |
| 929 | + | |
| 930 | + | |
898 | 931 | | |
899 | 932 | | |
900 | 933 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
113 | 113 | | |
114 | 114 | | |
115 | 115 | | |
116 | | - | |
| 116 | + | |
| 117 | + | |
117 | 118 | | |
118 | 119 | | |
119 | 120 | | |
120 | 121 | | |
121 | 122 | | |
122 | 123 | | |
123 | | - | |
| 124 | + | |
124 | 125 | | |
125 | 126 | | |
126 | 127 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
225 | 225 | | |
226 | 226 | | |
227 | 227 | | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
228 | 234 | | |
229 | 235 | | |
230 | 236 | | |
| |||
0 commit comments