vo_gpu_next: add target-colorspace-hint=auto

This commit is contained in:
Kacper Michajłow
2024-11-09 15:00:35 +01:00
parent d53dae1fd6
commit 2c2ac3cb36
3 changed files with 35 additions and 19 deletions

View File

@@ -1 +1 @@
change `target-colorspace-hint` default to `yes` change `target-colorspace-hint` default to `auto`

View File

@@ -6826,11 +6826,12 @@ them.
Fully replaces the color decoding. A LUT of this type should ingest the Fully replaces the color decoding. A LUT of this type should ingest the
image's native colorspace and output normalized non-linear RGB. image's native colorspace and output normalized non-linear RGB.
``--target-colorspace-hint`` ``--target-colorspace-hint=<auto|yes|no>``
Automatically configure the output colorspace of the display to pass Automatically configure the output colorspace of the display to pass
through the input values of the stream (e.g. for HDR passthrough), if through the input values of the stream (e.g. for HDR passthrough), if
possible. Requires a supporting driver and ``--vo=gpu-next``. possible. In ``auto`` mode (the default), the target colorspace is only set,
(Default: ``yes``) if the display signals support for HDR colorspace.
Requires a supporting driver and ``--vo=gpu-next``. (Default: ``auto``)
``--target-prim=<value>`` ``--target-prim=<value>``
Specifies the primaries of the display. Video colors will be adapted to Specifies the primaries of the display. Video colors will be adapted to
@@ -6928,7 +6929,8 @@ them.
In ``auto`` mode (the default), the chosen peak is an appropriate value In ``auto`` mode (the default), the chosen peak is an appropriate value
based on the TRC in use. For SDR curves, it uses 203. For HDR curves, it based on the TRC in use. For SDR curves, it uses 203. For HDR curves, it
uses 203 * the transfer function's nominal peak. uses 203 * the transfer function's nominal peak. If available, it will use
the target display's peak brightness as reported by the display.
.. note:: .. note::

View File

@@ -170,7 +170,7 @@ struct gl_next_opts {
struct user_lut lut; struct user_lut lut;
struct user_lut image_lut; struct user_lut image_lut;
struct user_lut target_lut; struct user_lut target_lut;
bool target_hint; int target_hint;
char **raw_opts; char **raw_opts;
}; };
@@ -197,7 +197,7 @@ const struct m_sub_options gl_next_conf = {
{"image-lut", OPT_STRING(image_lut.opt), .flags = M_OPT_FILE}, {"image-lut", OPT_STRING(image_lut.opt), .flags = M_OPT_FILE},
{"image-lut-type", OPT_CHOICE_C(image_lut.type, lut_types)}, {"image-lut-type", OPT_CHOICE_C(image_lut.type, lut_types)},
{"target-lut", OPT_STRING(target_lut.opt), .flags = M_OPT_FILE}, {"target-lut", OPT_STRING(target_lut.opt), .flags = M_OPT_FILE},
{"target-colorspace-hint", OPT_BOOL(target_hint)}, {"target-colorspace-hint", OPT_CHOICE(target_hint, {"auto", -1}, {"no", 0}, {"yes", 1})},
// No `target-lut-type` because we don't support non-RGB targets // No `target-lut-type` because we don't support non-RGB targets
{"libplacebo-opts", OPT_KEYVALUELIST(raw_opts)}, {"libplacebo-opts", OPT_KEYVALUELIST(raw_opts)},
{0}, {0},
@@ -205,7 +205,7 @@ const struct m_sub_options gl_next_conf = {
.defaults = &(struct gl_next_opts) { .defaults = &(struct gl_next_opts) {
.border_background = BACKGROUND_COLOR, .border_background = BACKGROUND_COLOR,
.inter_preserve = true, .inter_preserve = true,
.target_hint = true, .target_hint = -1,
}, },
.size = sizeof(struct gl_next_opts), .size = sizeof(struct gl_next_opts),
.change_flags = UPDATE_VIDEO, .change_flags = UPDATE_VIDEO,
@@ -798,7 +798,7 @@ static void apply_target_contrast(struct priv *p, struct pl_color_space *color)
color->hdr.min_luma = color->hdr.max_luma / opts->target_contrast; color->hdr.min_luma = color->hdr.max_luma / opts->target_contrast;
} }
static void apply_target_options(struct priv *p, struct pl_frame *target) static void apply_target_options(struct priv *p, struct pl_frame *target, float target_peak)
{ {
update_lut(p, &p->next_opts->target_lut); update_lut(p, &p->next_opts->target_lut);
target->lut = p->next_opts->target_lut.lut; target->lut = p->next_opts->target_lut.lut;
@@ -813,8 +813,8 @@ static void apply_target_options(struct priv *p, struct pl_frame *target)
if (opts->target_trc) if (opts->target_trc)
target->color.transfer = opts->target_trc; target->color.transfer = opts->target_trc;
// If swapchain returned a value use this, override is used in hint // If swapchain returned a value use this, override is used in hint
if (opts->target_peak && !target->color.hdr.max_luma) if (target_peak && !target->color.hdr.max_luma)
target->color.hdr.max_luma = opts->target_peak; target->color.hdr.max_luma = target_peak;
if (!target->color.hdr.min_luma) if (!target->color.hdr.min_luma)
apply_target_contrast(p, &target->color); apply_target_contrast(p, &target->color);
if (opts->target_gamut) { if (opts->target_gamut) {
@@ -975,9 +975,24 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
p->last_id = id; p->last_id = id;
} }
struct ra_swapchain *sw = p->ra_ctx->swapchain;
bool pass_colorspace = false; bool pass_colorspace = false;
struct pl_color_space target_csp;
// Assume HDR is supported, if query is not available
// TODO: Implement this for all backends
target_csp = sw->fns->target_csp
? sw->fns->target_csp(sw)
: (struct pl_color_space){ .transfer = PL_COLOR_TRC_PQ };
if (!pl_color_transfer_is_hdr(target_csp.transfer))
target_csp.hdr.max_luma = 0;
float target_peak = opts->target_peak ? opts->target_peak : target_csp.hdr.max_luma;
struct pl_color_space hint; struct pl_color_space hint;
if (p->next_opts->target_hint && frame->current) { bool target_hint = p->next_opts->target_hint == 1 ||
(p->next_opts->target_hint == -1 &&
pl_color_transfer_is_hdr(target_csp.transfer));
if (target_hint && frame->current) {
hint = frame->current->params.color; hint = frame->current->params.color;
if (p->ra_ctx->fns->pass_colorspace && p->ra_ctx->fns->pass_colorspace(p->ra_ctx)) if (p->ra_ctx->fns->pass_colorspace && p->ra_ctx->fns->pass_colorspace(p->ra_ctx))
pass_colorspace = true; pass_colorspace = true;
@@ -985,17 +1000,16 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
hint.primaries = opts->target_prim; hint.primaries = opts->target_prim;
if (opts->target_trc) if (opts->target_trc)
hint.transfer = opts->target_trc; hint.transfer = opts->target_trc;
if (opts->target_peak) if (target_peak)
hint.hdr.max_luma = opts->target_peak; hint.hdr.max_luma = target_peak;
apply_target_contrast(p, &hint); apply_target_contrast(p, &hint);
if (!pass_colorspace) if (!pass_colorspace)
pl_swapchain_colorspace_hint(p->sw, &hint); pl_swapchain_colorspace_hint(p->sw, &hint);
} else if (!p->next_opts->target_hint) { } else if (!target_hint) {
pl_swapchain_colorspace_hint(p->sw, NULL); pl_swapchain_colorspace_hint(p->sw, NULL);
} }
struct pl_swapchain_frame swframe; struct pl_swapchain_frame swframe;
struct ra_swapchain *sw = p->ra_ctx->swapchain;
bool should_draw = sw->fns->start_frame(sw, NULL); // for wayland logic bool should_draw = sw->fns->start_frame(sw, NULL); // for wayland logic
if (!should_draw || !pl_swapchain_start_frame(p->sw, &swframe)) { if (!should_draw || !pl_swapchain_start_frame(p->sw, &swframe)) {
if (frame->current) { if (frame->current) {
@@ -1019,7 +1033,7 @@ static void draw_frame(struct vo *vo, struct vo_frame *frame)
// Calculate target // Calculate target
struct pl_frame target; struct pl_frame target;
pl_frame_from_swapchain(&target, &swframe); pl_frame_from_swapchain(&target, &swframe);
apply_target_options(p, &target); apply_target_options(p, &target, target_peak);
update_overlays(vo, p->osd_res, update_overlays(vo, p->osd_res,
(frame->current && opts->blend_subs) ? OSD_DRAW_OSD_ONLY : 0, (frame->current && opts->blend_subs) ? OSD_DRAW_OSD_ONLY : 0,
PL_OVERLAY_COORDS_DST_FRAME, &p->osd_state, &target, frame->current); PL_OVERLAY_COORDS_DST_FRAME, &p->osd_state, &target, frame->current);
@@ -1391,9 +1405,10 @@ static void video_screenshot(struct vo *vo, struct voctrl_screenshot *args)
}, },
}; };
const struct gl_video_opts *opts = p->opts_cache->opts;
if (args->scaled) { if (args->scaled) {
// Apply target LUT, ICC profile and CSP override only in window mode // Apply target LUT, ICC profile and CSP override only in window mode
apply_target_options(p, &target); apply_target_options(p, &target, opts->target_peak);
} else if (args->native_csp) { } else if (args->native_csp) {
target.color = image.color; target.color = image.color;
} else { } else {
@@ -1410,7 +1425,6 @@ static void video_screenshot(struct vo *vo, struct voctrl_screenshot *args)
if (!args->osd) if (!args->osd)
osd_flags |= OSD_DRAW_SUB_ONLY; osd_flags |= OSD_DRAW_SUB_ONLY;
const struct gl_video_opts *opts = p->opts_cache->opts;
struct frame_priv *fp = mpi->priv; struct frame_priv *fp = mpi->priv;
if (opts->blend_subs) { if (opts->blend_subs) {
float rx = pl_rect_w(dst) / pl_rect_w(image.crop); float rx = pl_rect_w(dst) / pl_rect_w(image.crop);