@@ -675,6 +675,13 @@ static bool map_frame(pl_gpu gpu, pl_tex *tex, const struct pl_source_frame *src
675675 if (opts -> hdr_reference_white && !pl_color_transfer_is_hdr (frame -> color .transfer ))
676676 frame -> color .hdr .max_luma = opts -> hdr_reference_white ;
677677
678+
679+ if (opts -> treat_srgb_as_power22 & 1 && frame -> color .transfer == PL_COLOR_TRC_SRGB ) {
680+ // The sRGB EOTF is a pure gamma 2.2 function. See reference display in
681+ // IEC 61966-2-1-1999. Linearize sRGB to display light.
682+ frame -> color .transfer = PL_COLOR_TRC_GAMMA22 ;
683+ }
684+
678685 if (fp -> hwdec ) {
679686
680687 struct mp_imgfmt_desc desc = mp_imgfmt_get_desc (par .imgfmt );
@@ -1213,6 +1220,11 @@ static bool draw_frame(struct vo *vo, struct vo_frame *frame)
12131220 // Update again after possible max_luma change
12141221 if (p -> icc_profile )
12151222 hint = p -> icc_profile -> csp ;
1223+ // If preferred transfer is gamma 2.2, which is not defined as Vulkan
1224+ // swapchain colorspace, use sRGB instead. It has reference display with
1225+ // gamma 2.2 so it's the same target in practice.
1226+ if (hint .transfer == PL_COLOR_TRC_GAMMA22 )
1227+ hint .transfer = PL_COLOR_TRC_SRGB ;
12161228 if (!pass_colorspace )
12171229 pl_swapchain_colorspace_hint (p -> sw , & hint );
12181230 } else if (!target_hint ) {
@@ -1247,6 +1259,9 @@ static bool draw_frame(struct vo *vo, struct vo_frame *frame)
12471259 pl_frame_from_swapchain (& target , & swframe );
12481260 bool strict_sw_params = target_hint && !pass_colorspace && p -> next_opts -> target_hint_strict ;
12491261 apply_target_options (p , & target , hint .hdr .min_luma , strict_sw_params );
1262+ // sRGB reference display is pure 2.2 power function, see IEC 61966-2-1-1999.
1263+ if (opts -> treat_srgb_as_power22 & 3 && target .color .transfer == PL_COLOR_TRC_SRGB )
1264+ target .color .transfer = PL_COLOR_TRC_GAMMA22 ;
12501265 update_overlays (vo , p -> osd_res ,
12511266 (frame -> current && opts -> blend_subs ) ? OSD_DRAW_OSD_ONLY : 0 ,
12521267 PL_OVERLAY_COORDS_DST_FRAME , & p -> osd_state , & target , frame -> current );
@@ -1618,10 +1633,22 @@ static void video_screenshot(struct vo *vo, struct voctrl_screenshot *args)
16181633 if (args -> scaled ) {
16191634 // Apply target LUT, ICC profile and CSP override only in window mode
16201635 apply_target_options (p , & target , 0 , false);
1636+ // sRGB reference display is pure 2.2 power function, see IEC 61966-2-1-1999.
1637+ // Round-trip back to sRGB if the source is also sRGB.
1638+ if (opts -> treat_srgb_as_power22 & 1 &&
1639+ target .color .transfer == PL_COLOR_TRC_SRGB &&
1640+ mpi -> params .color .transfer == PL_COLOR_TRC_SRGB )
1641+ {
1642+ target .color .transfer = PL_COLOR_TRC_GAMMA22 ;
1643+ }
16211644 } else if (args -> native_csp ) {
16221645 target .color = image .color ;
16231646 } else {
1624- target .color = pl_color_space_srgb ;
1647+ target .color = (struct pl_color_space ){
1648+ .primaries = PL_COLOR_PRIM_BT_709 ,
1649+ .transfer = opts -> treat_srgb_as_power22 & 2 ? PL_COLOR_TRC_GAMMA22
1650+ : PL_COLOR_TRC_SRGB ,
1651+ };
16251652 }
16261653
16271654 apply_crop (& image , src , mpi -> params .w , mpi -> params .h );
0 commit comments