Skip to content

Commit c099cbc

Browse files
committed
vo_gpu_next: linearize sRGB as a pure 2.2 power function
sRGB reference display is defined a 2.2 gamma device. To preserve the look of the sRGB as mastered on such device, linearize it as such. Note that sRGB encoding is piecewise with linear segment, which creates mismatch to pure power 2.2 function, but this is intended to be viewed on such display. See: IEC 61966-2-1-1999 https://community.acescentral.com/t/srgb-piece-wise-eotf-vs-pure-gamma/4024 KhronosGroup/DataFormat#19 https://gitlab.freedesktop.org/pq/color-and-hdr/-/issues/12 https://github.com/dylanraga/win11hdr-srgb-to-gamma2.2-icm
1 parent 0a53407 commit c099cbc

File tree

1 file changed

+26
-1
lines changed

1 file changed

+26
-1
lines changed

video/out/vo_gpu_next.c

Lines changed: 26 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -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 (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 (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,20 @@ 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 (target.color.transfer == PL_COLOR_TRC_SRGB &&
1639+
mpi->params.color.transfer == PL_COLOR_TRC_SRGB)
1640+
{
1641+
target.color.transfer = PL_COLOR_TRC_GAMMA22;
1642+
}
16211643
} else if (args->native_csp) {
16221644
target.color = image.color;
16231645
} else {
1624-
target.color = pl_color_space_srgb;
1646+
target.color = (struct pl_color_space){
1647+
.primaries = PL_COLOR_PRIM_BT_709,
1648+
.transfer = PL_COLOR_TRC_GAMMA22,
1649+
};
16251650
}
16261651

16271652
apply_crop(&image, src, mpi->params.w, mpi->params.h);

0 commit comments

Comments
 (0)