Skip to content

Commit c5066b3

Browse files
committed
wayland: switch to PQ when necessary
Signed-off-by: Julian Orth <[email protected]>
1 parent 5151955 commit c5066b3

File tree

9 files changed

+73
-19
lines changed

9 files changed

+73
-19
lines changed

video/out/d3d11/context.c

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,8 @@ static int d3d11_color_depth(struct ra_swapchain *sw)
203203
return MPMIN(ra_fmt->component_depth[0], desc1.BitsPerColor);
204204
}
205205

206-
static struct pl_color_space d3d11_target_color_space(struct ra_swapchain *sw)
206+
static struct pl_color_space d3d11_target_color_space(struct ra_swapchain *sw,
207+
float source_max_luma)
207208
{
208209
if (sw->ctx->opts.composition)
209210
return (struct pl_color_space){0};

video/out/gpu/context.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ struct ra_ctx_params {
7979
int (*color_depth)(struct ra_ctx *ctx);
8080

8181
// Preferred device color space. Optional.
82-
pl_color_space_t (*preferred_csp)(struct ra_ctx *ctx);
82+
pl_color_space_t (*preferred_csp)(struct ra_ctx *ctx, float source_max_luma);
8383

8484
// See ra_swapchain_fns.get_vsync.
8585
void (*get_vsync)(struct ra_ctx *ctx, struct vo_vsync_info *info);
@@ -114,7 +114,7 @@ struct ra_swapchain_fns {
114114
int (*color_depth)(struct ra_swapchain *sw);
115115

116116
// Target device color space. Optional.
117-
pl_color_space_t (*target_csp)(struct ra_swapchain *sw);
117+
pl_color_space_t (*target_csp)(struct ra_swapchain *sw, float source_max_luma);
118118

119119
// Called when rendering starts. Returns NULL on failure. This must be
120120
// followed by submit_frame, to submit the rendered frame. This function

video/out/opengl/context.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -305,11 +305,11 @@ static void ra_gl_ctx_get_vsync(struct ra_swapchain *sw,
305305
p->params.get_vsync(sw->ctx, info);
306306
}
307307

308-
static pl_color_space_t ra_gl_ctx_target_csp(struct ra_swapchain *sw)
308+
static pl_color_space_t ra_gl_ctx_target_csp(struct ra_swapchain *sw, float source_max_luma)
309309
{
310310
struct priv *p = sw->priv;
311311
if (p->params.preferred_csp)
312-
return p->params.preferred_csp(sw->ctx);
312+
return p->params.preferred_csp(sw->ctx, source_max_luma);
313313
return (pl_color_space_t){0};
314314
}
315315

video/out/vo_gpu_next.c

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1089,8 +1089,16 @@ static bool draw_frame(struct vo *vo, struct vo_frame *frame)
10891089
bool pass_colorspace = false;
10901090
struct pl_color_space target_csp = {0};
10911091
// TODO: Implement this for all backends
1092-
if (sw->fns->target_csp)
1093-
target_csp = sw->fns->target_csp(sw);
1092+
if (sw->fns->target_csp) {
1093+
float source_max_luma = 0.0f;
1094+
if (frame->current) {
1095+
source_max_luma = frame->current->params.color.hdr.max_luma;
1096+
if (opts->tone_map.inverse)
1097+
// Sentinel value to use the maximum luminance supported by the display.
1098+
source_max_luma = INFINITY;
1099+
}
1100+
target_csp = sw->fns->target_csp(sw, source_max_luma);
1101+
}
10941102
if (target_csp.primaries == PL_COLOR_PRIM_UNKNOWN)
10951103
target_csp.primaries = get_best_prim_container(&target_csp.hdr.prim);
10961104
if (!pl_color_transfer_is_hdr(target_csp.transfer)) {

video/out/vulkan/context.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -518,11 +518,11 @@ static void get_vsync(struct ra_swapchain *sw,
518518
p->params.get_vsync(sw->ctx, info);
519519
}
520520

521-
static pl_color_space_t target_csp(struct ra_swapchain *sw)
521+
static pl_color_space_t target_csp(struct ra_swapchain *sw, float soucre_max_luma)
522522
{
523523
struct priv *p = sw->priv;
524524
if (p->params.preferred_csp)
525-
return p->params.preferred_csp(sw->ctx);
525+
return p->params.preferred_csp(sw->ctx, soucre_max_luma);
526526
return (pl_color_space_t){0};
527527
}
528528

video/out/vulkan/context_wayland.c

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,9 +33,9 @@ static bool wayland_vk_check_visible(struct ra_ctx *ctx)
3333
return vo_wayland_check_visible(ctx->vo);
3434
}
3535

36-
static pl_color_space_t wayland_vk_preferred_csp(struct ra_ctx *ctx)
36+
static pl_color_space_t wayland_vk_preferred_csp(struct ra_ctx *ctx, float source_max_luma)
3737
{
38-
return vo_wayland_preferred_csp(ctx->vo);
38+
return vo_wayland_preferred_csp(ctx->vo, source_max_luma);
3939
}
4040

4141
static void wayland_vk_swap_buffers(struct ra_ctx *ctx)

video/out/vulkan/context_win.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ static int color_depth(struct ra_ctx *ctx)
5252
return -1;
5353
}
5454

55-
static struct pl_color_space preferred_csp(struct ra_ctx *ctx)
55+
static struct pl_color_space preferred_csp(struct ra_ctx *ctx, float source_max_luma)
5656
{
5757
struct priv *p = ctx->priv;
5858

video/out/wayland_common.c

Lines changed: 51 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2172,10 +2172,6 @@ static void info_done(void *data, struct wp_image_description_info_v1 *image_des
21722172
wd->csp.hdr.max_fall = MPMIN(wd->csp.hdr.max_fall, wd->csp.hdr.max_luma);
21732173
}
21742174
wl->preferred_csp = wd->csp;
2175-
if (wd->csp.hdr.max_luma > PL_COLOR_SDR_WHITE) {
2176-
MP_VERBOSE(wl, "Setting preferred transfer to PQ for HDR output.\n");
2177-
wl->preferred_csp.transfer = PL_COLOR_TRC_PQ;
2178-
}
21792175
} else {
21802176
if (wl->icc_size) {
21812177
munmap(wl->icc_file, wl->icc_size);
@@ -3982,10 +3978,59 @@ bool vo_wayland_check_visible(struct vo *vo)
39823978
return render;
39833979
}
39843980

3985-
struct pl_color_space vo_wayland_preferred_csp(struct vo *vo)
3981+
struct pl_color_space vo_wayland_preferred_csp(struct vo *vo, float source_max_luma)
39863982
{
39873983
struct vo_wayland_state *wl = vo->wl;
3988-
return wl->preferred_csp;
3984+
struct pl_color_space csp = wl->preferred_csp;
3985+
if (!pl_color_transfer_is_hdr(csp.transfer)) {
3986+
// For transfer functions for which pl_color_transfer_is_hdr returns false, mpv
3987+
// discards the HDR metadata and assumes a max_luma of PL_COLOR_SDR_WHITE.
3988+
// Similarly, mesa discards the HDR metadata for such transfer functions.
3989+
// Therefore, if there is any reason for us to preserve the HDR metadata, we need
3990+
// to switch to a transfer function for which pl_color_transfer_is_hdr returns
3991+
// true. PL_COLOR_TRC_PQ is the most widely supported transfer function of that
3992+
// kind. If VK_COLOR_SPACE_HDR10_ST2084_EXT is not available, then libplacebo will
3993+
// still try to fall back to another HDR transfer function so that mesa passes the
3994+
// metadata on to the compositor. (Therefore, using any HDR transfer function here
3995+
// would do since we cannot actually know which transfer function the compositor
3996+
// prefers.)
3997+
3998+
// The default assumption by all components in the pipeline is that the maximum
3999+
// luminance for non-HDR transfer functions is paper white. Therefore, we don't
4000+
// have to handle this case.
4001+
if (csp.hdr.max_luma != PL_COLOR_SDR_WHITE) {
4002+
// Otherwise, if we are doing inverse tone mapping, which is indicated by
4003+
// source_max_luma == INFINITY, then libplacebo always needs to know the exact
4004+
// max_luma of the display since that is the target we want to hit.
4005+
if (source_max_luma == INFINITY)
4006+
csp.transfer = PL_COLOR_TRC_PQ;
4007+
// Otherwise, if the max_luma of the source is brighter than paper white, then
4008+
// libplacebo will always perform tone mapping. To do this correctly, it will
4009+
// need to know the exact max_luma of the display.
4010+
if (source_max_luma > PL_COLOR_SDR_WHITE)
4011+
csp.transfer = PL_COLOR_TRC_PQ;
4012+
// Otherwise, if max_luma of the display is less than paper white, there are
4013+
// two cases:
4014+
// 1. source_max_luma > csp.hdr.max_luma: In this case, we want libplacebo
4015+
// to tone map to the max_luma of the display.
4016+
// 2. source_max_luma <= csp.hdr.max_luma: In this case, we still need to
4017+
// tell the compositor that the max_luma of our images is
4018+
// < csp.hdr.max_luma since otherwise it will assume that the max_luma of
4019+
// or images is paper white and might do its own tone mapping down to
4020+
// csp.hdr.max_luma.
4021+
// So in both cases we need to pass the actual max_luma of the display through
4022+
// the pipeline.
4023+
if (csp.hdr.max_luma < PL_COLOR_SDR_WHITE)
4024+
csp.transfer = PL_COLOR_TRC_PQ;
4025+
4026+
// NOTE: If source_max_luma > csp.hdr.max_luma, which seems to be missing from
4027+
// the conditions above, then either source_max_luma > PL_COLOR_SDR_WHITE, in
4028+
// which case we hit the second branch above, or
4029+
// csp.hdr.max_luma < source_max_luma <= PL_COLOR_WHITE in which case we hit
4030+
// the third branch above.
4031+
}
4032+
}
4033+
return csp;
39894034
}
39904035

39914036
int vo_wayland_control(struct vo *vo, int *events, int request, void *arg)

video/out/wayland_common.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -192,7 +192,7 @@ struct vo_wayland_state {
192192
};
193193

194194
bool vo_wayland_check_visible(struct vo *vo);
195-
struct pl_color_space vo_wayland_preferred_csp(struct vo *vo);
195+
struct pl_color_space vo_wayland_preferred_csp(struct vo *vo, float source_max_luma);
196196
bool vo_wayland_valid_format(struct vo_wayland_state *wl, uint32_t drm_format, uint64_t modifier);
197197
bool vo_wayland_init(struct vo *vo);
198198
bool vo_wayland_reconfig(struct vo *vo);

0 commit comments

Comments
 (0)