summaryrefslogtreecommitdiffstats
path: root/video/out/gpu/video.c
diff options
context:
space:
mode:
authorDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:13:14 +0000
committerDaniel Baumann <daniel.baumann@progress-linux.org>2024-05-04 01:13:14 +0000
commit60e8a3d404f0640fa5a3f834eae54b4f1fb9127d (patch)
tree1da89a218d0ecf010c67a87cb2f625c4cb18e7d7 /video/out/gpu/video.c
parentAdding upstream version 0.37.0. (diff)
downloadmpv-60e8a3d404f0640fa5a3f834eae54b4f1fb9127d.tar.xz
mpv-60e8a3d404f0640fa5a3f834eae54b4f1fb9127d.zip
Adding upstream version 0.38.0.upstream/0.38.0upstream
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'video/out/gpu/video.c')
-rw-r--r--video/out/gpu/video.c358
1 files changed, 196 insertions, 162 deletions
diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c
index 852ee78..1478ec4 100644
--- a/video/out/gpu/video.c
+++ b/video/out/gpu/video.c
@@ -183,6 +183,7 @@ struct gl_video {
struct mp_image_params real_image_params; // configured format
struct mp_image_params image_params; // texture format (mind hwdec case)
+ struct mp_image_params target_params; // target format
struct ra_imgfmt_desc ra_format; // texture format
int plane_count;
@@ -212,6 +213,7 @@ struct gl_video {
struct ra_tex *merge_tex[4];
struct ra_tex *scale_tex[4];
struct ra_tex *integer_tex[4];
+ struct ra_tex *chroma_tex[4];
struct ra_tex *indirect_tex;
struct ra_tex *blend_subs_tex;
struct ra_tex *error_diffusion_tex[2];
@@ -312,8 +314,8 @@ static const struct gl_video_opts gl_video_opts_def = {
.linear_downscaling = true,
.sigmoid_upscaling = true,
.interpolation_threshold = 0.01,
- .alpha_mode = ALPHA_BLEND_TILES,
- .background = {0, 0, 0, 255},
+ .background = BACKGROUND_TILES,
+ .background_color = {0, 0, 0, 255},
.gamma = 1.0f,
.tone_map = {
.curve = TONE_MAPPING_AUTO,
@@ -329,14 +331,9 @@ static const struct gl_video_opts gl_video_opts_def = {
.hwdec_interop = "auto",
};
-static int validate_scaler_opt(struct mp_log *log, const m_option_t *opt,
- struct bstr name, const char **value);
-
-static int validate_window_opt(struct mp_log *log, const m_option_t *opt,
- struct bstr name, const char **value);
-
-static int validate_error_diffusion_opt(struct mp_log *log, const m_option_t *opt,
- struct bstr name, const char **value);
+static OPT_STRING_VALIDATE_FUNC(validate_scaler_opt);
+static OPT_STRING_VALIDATE_FUNC(validate_window_opt);
+static OPT_STRING_VALIDATE_FUNC(validate_error_diffusion_opt);
#define OPT_BASE_STRUCT struct gl_video_opts
@@ -368,13 +365,13 @@ const struct m_sub_options gl_video_conf = {
.deprecation_message = "no replacement"},
{"gamma-auto", OPT_BOOL(gamma_auto),
.deprecation_message = "no replacement"},
- {"target-prim", OPT_CHOICE_C(target_prim, mp_csp_prim_names)},
- {"target-trc", OPT_CHOICE_C(target_trc, mp_csp_trc_names)},
+ {"target-prim", OPT_CHOICE_C(target_prim, pl_csp_prim_names)},
+ {"target-trc", OPT_CHOICE_C(target_trc, pl_csp_trc_names)},
{"target-peak", OPT_CHOICE(target_peak, {"auto", 0}),
M_RANGE(10, 10000)},
{"target-contrast", OPT_CHOICE(target_contrast, {"auto", 0}, {"inf", -1}),
M_RANGE(10, 1000000)},
- {"target-gamut", OPT_CHOICE_C(target_gamut, mp_csp_prim_names)},
+ {"target-gamut", OPT_CHOICE_C(target_gamut, pl_csp_prim_names)},
{"tone-mapping", OPT_CHOICE(tone_map.curve,
{"auto", TONE_MAPPING_AUTO},
{"clip", TONE_MAPPING_CLIP},
@@ -447,13 +444,12 @@ const struct m_sub_options gl_video_conf = {
M_RANGE(1, 128)},
{"error-diffusion",
OPT_STRING_VALIDATE(error_diffusion, validate_error_diffusion_opt)},
- {"alpha", OPT_CHOICE(alpha_mode,
- {"no", ALPHA_NO},
- {"yes", ALPHA_YES},
- {"blend", ALPHA_BLEND},
- {"blend-tiles", ALPHA_BLEND_TILES})},
+ {"background", OPT_CHOICE(background,
+ {"none", BACKGROUND_NONE},
+ {"color", BACKGROUND_COLOR},
+ {"tiles", BACKGROUND_TILES})},
{"opengl-rectangle-textures", OPT_BOOL(use_rectangle)},
- {"background", OPT_COLOR(background)},
+ {"background-color", OPT_COLOR(background_color)},
{"interpolation", OPT_BOOL(interpolation)},
{"interpolation-threshold", OPT_FLOAT(interpolation_threshold)},
{"blend-subtitles", OPT_CHOICE(blend_subs,
@@ -483,6 +479,7 @@ const struct m_sub_options gl_video_conf = {
},
.size = sizeof(struct gl_video_opts),
.defaults = &gl_video_opts_def,
+ .change_flags = UPDATE_VIDEO,
};
static void uninit_rendering(struct gl_video *p);
@@ -578,6 +575,7 @@ static void uninit_rendering(struct gl_video *p)
ra_tex_free(p->ra, &p->merge_tex[n]);
ra_tex_free(p->ra, &p->scale_tex[n]);
ra_tex_free(p->ra, &p->integer_tex[n]);
+ ra_tex_free(p->ra, &p->chroma_tex[n]);
}
ra_tex_free(p->ra, &p->indirect_tex);
@@ -605,15 +603,6 @@ bool gl_video_gamma_auto_enabled(struct gl_video *p)
return p->opts.gamma_auto;
}
-struct mp_colorspace gl_video_get_output_colorspace(struct gl_video *p)
-{
- return (struct mp_colorspace) {
- .primaries = p->opts.target_prim,
- .gamma = p->opts.target_trc,
- .hdr.max_luma = p->opts.target_peak,
- };
-}
-
// Warning: profile.start must point to a ta allocation, and the function
// takes over ownership.
void gl_video_set_icc_profile(struct gl_video *p, bstr icc_data)
@@ -627,8 +616,8 @@ bool gl_video_icc_auto_enabled(struct gl_video *p)
return p->opts.icc_opts ? p->opts.icc_opts->profile_auto : false;
}
-static bool gl_video_get_lut3d(struct gl_video *p, enum mp_csp_prim prim,
- enum mp_csp_trc trc)
+static bool gl_video_get_lut3d(struct gl_video *p, enum pl_color_primaries prim,
+ enum pl_color_transfer trc)
{
if (!p->use_lut_3d)
return false;
@@ -771,16 +760,16 @@ static void pass_get_images(struct gl_video *p, struct video_image *vimg,
struct gl_transform chroma = {{{ls_w, 0.0}, {0.0, ls_h}}};
- if (p->image_params.chroma_location != MP_CHROMA_CENTER) {
- int cx, cy;
- mp_get_chroma_location(p->image_params.chroma_location, &cx, &cy);
+ if (p->image_params.chroma_location != PL_CHROMA_CENTER) {
+ float cx, cy;
+ pl_chroma_location_offset(p->image_params.chroma_location, &cx, &cy);
// By default texture coordinates are such that chroma is centered with
// any chroma subsampling. If a specific direction is given, make it
// so that the luma and chroma sample line up exactly.
// For 4:4:4, setting chroma location should have no effect at all.
// luma sample size (in chroma coord. space)
- chroma.t[0] = ls_w < 1 ? ls_w * -cx / 2 : 0;
- chroma.t[1] = ls_h < 1 ? ls_h * -cy / 2 : 0;
+ chroma.t[0] = ls_w < 1 ? ls_w * -cx : 0;
+ chroma.t[1] = ls_h < 1 ? ls_h * -cy : 0;
}
memset(img, 0, 4 * sizeof(img[0]));
@@ -796,9 +785,9 @@ static void pass_get_images(struct gl_video *p, struct video_image *vimg,
ctype = PLANE_NONE;
} else if (c == 4) {
ctype = PLANE_ALPHA;
- } else if (p->image_params.color.space == MP_CSP_RGB) {
+ } else if (p->image_params.repr.sys == PL_COLOR_SYSTEM_RGB) {
ctype = PLANE_RGB;
- } else if (p->image_params.color.space == MP_CSP_XYZ) {
+ } else if (p->image_params.repr.sys == PL_COLOR_SYSTEM_XYZ) {
ctype = PLANE_XYZ;
} else {
ctype = c == 1 ? PLANE_LUMA : PLANE_CHROMA;
@@ -810,7 +799,7 @@ static void pass_get_images(struct gl_video *p, struct video_image *vimg,
int msb_valid_bits =
p->ra_format.component_bits + MPMIN(p->ra_format.component_pad, 0);
- int csp = type == PLANE_ALPHA ? MP_CSP_RGB : p->image_params.color.space;
+ int csp = type == PLANE_ALPHA ? PL_COLOR_SYSTEM_RGB : p->image_params.repr.sys;
float tex_mul =
1.0 / mp_get_csp_mul(csp, msb_valid_bits, p->ra_format.component_bits);
if (p->ra_format.component_type == RA_CTYPE_FLOAT)
@@ -1065,13 +1054,13 @@ static void uninit_video(struct gl_video *p)
ra_hwdec_mapper_free(&p->hwdec_mapper);
}
-static void pass_record(struct gl_video *p, struct mp_pass_perf perf)
+static void pass_record(struct gl_video *p, const struct mp_pass_perf *perf)
{
if (!p->pass || p->pass_idx == VO_PASS_PERF_MAX)
return;
struct pass_info *pass = &p->pass[p->pass_idx];
- pass->perf = perf;
+ pass->perf = *perf;
if (pass->desc.len == 0)
bstr_xappend(p, &pass->desc, bstr0("(unknown)"));
@@ -1211,12 +1200,13 @@ static void dispatch_compute(struct gl_video *p, int w, int h,
if (!(p->ra->caps & RA_CAP_NUM_GROUPS))
PRELUDE("#define gl_NumWorkGroups uvec3(%d, %d, 1)\n", num_x, num_y);
- pass_record(p, gl_sc_dispatch_compute(p->sc, num_x, num_y, 1));
+ struct mp_pass_perf perf = gl_sc_dispatch_compute(p->sc, num_x, num_y, 1);
+ pass_record(p, &perf);
cleanup_binds(p);
}
static struct mp_pass_perf render_pass_quad(struct gl_video *p,
- struct ra_fbo fbo, bool discard,
+ const struct ra_fbo *fbo, bool discard,
const struct mp_rect *dst)
{
// The first element is reserved for `vec2 position`
@@ -1274,15 +1264,16 @@ static struct mp_pass_perf render_pass_quad(struct gl_video *p,
&p->tmp_vertex[num_vertex_attribs * 1],
vertex_stride);
- return gl_sc_dispatch_draw(p->sc, fbo.tex, discard, p->vao, num_vertex_attribs,
+ return gl_sc_dispatch_draw(p->sc, fbo->tex, discard, p->vao, num_vertex_attribs,
vertex_stride, p->tmp_vertex, num_vertices);
}
-static void finish_pass_fbo(struct gl_video *p, struct ra_fbo fbo,
+static void finish_pass_fbo(struct gl_video *p, const struct ra_fbo *fbo,
bool discard, const struct mp_rect *dst)
{
pass_prepare_src_tex(p);
- pass_record(p, render_pass_quad(p, fbo, discard, dst));
+ struct mp_pass_perf perf = render_pass_quad(p, fbo, discard, dst);
+ pass_record(p, &perf);
debug_check_gl(p, "after rendering");
cleanup_binds(p);
}
@@ -1319,7 +1310,7 @@ static void finish_pass_tex(struct gl_video *p, struct ra_tex **dst_tex,
debug_check_gl(p, "after dispatching compute shader");
} else {
struct ra_fbo fbo = { .tex = *dst_tex, };
- finish_pass_fbo(p, fbo, true, &(struct mp_rect){0, 0, w, h});
+ finish_pass_fbo(p, &fbo, true, &(struct mp_rect){0, 0, w, h});
}
}
@@ -1955,7 +1946,7 @@ static void deband_hook(struct gl_video *p, struct image img,
{
pass_describe(p, "debanding (%s)", plane_names[img.type]);
pass_sample_deband(p->sc, p->opts.deband_opts, &p->lfg,
- p->image_params.color.gamma);
+ p->image_params.color.transfer);
}
static void unsharp_hook(struct gl_video *p, struct image img,
@@ -2046,25 +2037,23 @@ static void user_hook(struct gl_video *p, struct image img,
gl_transform_trans(shader->offset, trans);
}
-static bool add_user_hook(void *priv, struct gl_user_shader_hook hook)
+static bool add_user_hook(void *priv, const struct gl_user_shader_hook *hook)
{
struct gl_video *p = priv;
- struct gl_user_shader_hook *copy = talloc_ptrtype(p, copy);
- *copy = hook;
-
+ struct gl_user_shader_hook *copy = talloc_dup(p, (struct gl_user_shader_hook *)hook);
struct tex_hook texhook = {
- .save_tex = bstrdup0(copy, hook.save_tex),
- .components = hook.components,
- .align_offset = hook.align_offset,
+ .save_tex = bstrdup0(copy, copy->save_tex),
+ .components = copy->components,
+ .align_offset = copy->align_offset,
.hook = user_hook,
.cond = user_hook_cond,
.priv = copy,
};
for (int h = 0; h < SHADER_MAX_HOOKS; h++)
- texhook.hook_tex[h] = bstrdup0(copy, hook.hook_tex[h]);
+ texhook.hook_tex[h] = bstrdup0(copy, copy->hook_tex[h]);
for (int h = 0; h < SHADER_MAX_BINDS; h++)
- texhook.bind_tex[h] = bstrdup0(copy, hook.bind_tex[h]);
+ texhook.bind_tex[h] = bstrdup0(copy, copy->bind_tex[h]);
MP_TARRAY_APPEND(p, p->tex_hooks, p->num_tex_hooks, texhook);
return true;
@@ -2213,6 +2202,23 @@ static void pass_read_video(struct gl_video *p)
}
}
+ // If chroma textures are in a subsampled semi-planar format and rotated,
+ // introduce an explicit conversion pass to avoid breaking chroma scalers.
+ for (int n = 0; n < 4; n++) {
+ if (img[n].tex && img[n].type == PLANE_CHROMA &&
+ img[n].tex->params.format->num_components == 2 &&
+ p->image_params.rotate % 180 == 90 &&
+ p->ra_format.chroma_w != 1)
+ {
+ GLSLF("// chroma fix for rotated plane %d\n", n);
+ copy_image(p, &(int){0}, img[n]);
+ pass_describe(p, "chroma fix for rotated plane");
+ finish_pass_tex(p, &p->chroma_tex[n], img[n].w, img[n].h);
+ img[n] = image_wrap(p->chroma_tex[n], img[n].type,
+ img[n].components);
+ }
+ }
+
// At this point all planes are finalized but they may not be at the
// required size yet. Furthermore, they may have texture offsets that
// require realignment.
@@ -2345,29 +2351,29 @@ static void pass_convert_yuv(struct gl_video *p)
GLSLF("color = color.%s;\n", p->color_swizzle);
// Pre-colormatrix input gamma correction
- if (cparams.color.space == MP_CSP_XYZ)
- pass_linearize(p->sc, p->image_params.color.gamma);
+ if (cparams.repr.sys == PL_COLOR_SYSTEM_XYZ)
+ pass_linearize(p->sc, p->image_params.color.transfer);
// We always explicitly normalize the range in pass_read_video
cparams.input_bits = cparams.texture_bits = 0;
// Conversion to RGB. For RGB itself, this still applies e.g. brightness
// and contrast controls, or expansion of e.g. LSB-packed 10 bit data.
- struct mp_cmat m = {{{0}}};
+ struct pl_transform3x3 m = {0};
mp_get_csp_matrix(&cparams, &m);
- gl_sc_uniform_mat3(sc, "colormatrix", true, &m.m[0][0]);
+ gl_sc_uniform_mat3(sc, "colormatrix", true, &m.mat.m[0][0]);
gl_sc_uniform_vec3(sc, "colormatrix_c", m.c);
GLSL(color.rgb = mat3(colormatrix) * color.rgb + colormatrix_c;)
- if (cparams.color.space == MP_CSP_XYZ) {
- pass_delinearize(p->sc, p->image_params.color.gamma);
+ if (cparams.repr.sys == PL_COLOR_SYSTEM_XYZ) {
+ pass_delinearize(p->sc, p->image_params.color.transfer);
// mp_get_csp_matrix implicitly converts XYZ to DCI-P3
- p->image_params.color.space = MP_CSP_RGB;
- p->image_params.color.primaries = MP_CSP_PRIM_DCI_P3;
+ p->image_params.repr.sys = PL_COLOR_SYSTEM_RGB;
+ p->image_params.color.primaries = PL_COLOR_PRIM_DCI_P3;
}
- if (p->image_params.color.space == MP_CSP_BT_2020_C) {
+ if (p->image_params.repr.sys == PL_COLOR_SYSTEM_BT_2020_C) {
// Conversion for C'rcY'cC'bc via the BT.2020 CL system:
// C'bc = (B'-Y'c) / 1.9404 | C'bc <= 0
// = (B'-Y'c) / 1.5816 | C'bc > 0
@@ -2404,9 +2410,9 @@ static void pass_convert_yuv(struct gl_video *p)
}
p->components = 3;
- if (!p->has_alpha || p->opts.alpha_mode == ALPHA_NO) {
+ if (!p->has_alpha) {
GLSL(color.a = 1.0;)
- } else if (p->image_params.alpha == MP_ALPHA_PREMUL) {
+ } else if (p->image_params.repr.alpha == PL_ALPHA_PREMULTIPLIED) {
p->components = 4;
} else {
p->components = 4;
@@ -2491,7 +2497,7 @@ static void pass_scale_main(struct gl_video *p)
// Linear light downscaling results in nasty artifacts for HDR curves
// due to the potentially extreme brightness differences severely
// compounding any ringing. So just scale in gamma light instead.
- if (mp_trc_is_hdr(p->image_params.color.gamma))
+ if (pl_color_space_is_hdr(&p->image_params.color))
use_linear = false;
} else if (upscaling) {
use_linear = p->opts.linear_upscaling || p->opts.sigmoid_upscaling;
@@ -2499,7 +2505,7 @@ static void pass_scale_main(struct gl_video *p)
if (use_linear) {
p->use_linear = true;
- pass_linearize(p->sc, p->image_params.color.gamma);
+ pass_linearize(p->sc, p->image_params.color.transfer);
pass_opt_hook_point(p, "LINEAR", NULL);
}
@@ -2552,8 +2558,9 @@ static void pass_scale_main(struct gl_video *p)
// rendering)
// If OSD is true, ignore any changes that may have been made to the video
// by previous passes (i.e. linear scaling)
-static void pass_colormanage(struct gl_video *p, struct mp_colorspace src,
- struct mp_colorspace fbo_csp, int flags, bool osd)
+static void pass_colormanage(struct gl_video *p, struct pl_color_space src,
+ enum mp_csp_light src_light,
+ struct pl_color_space fbo_csp, int flags, bool osd)
{
struct ra *ra = p->ra;
@@ -2561,18 +2568,17 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src,
// unless specific transfer function, primaries or target peak
// is set. If values are set to _AUTO, the most likely intended
// values are guesstimated later in this function.
- struct mp_colorspace dst = {
- .gamma = p->opts.target_trc == MP_CSP_TRC_AUTO ?
- fbo_csp.gamma : p->opts.target_trc,
- .primaries = p->opts.target_prim == MP_CSP_PRIM_AUTO ?
+ struct pl_color_space dst = {
+ .transfer = p->opts.target_trc == PL_COLOR_TRC_UNKNOWN ?
+ fbo_csp.transfer : p->opts.target_trc,
+ .primaries = p->opts.target_prim == PL_COLOR_PRIM_UNKNOWN ?
fbo_csp.primaries : p->opts.target_prim,
- .light = MP_CSP_LIGHT_DISPLAY,
.hdr.max_luma = !p->opts.target_peak ?
fbo_csp.hdr.max_luma : p->opts.target_peak,
};
if (!p->colorspace_override_warned &&
- ((fbo_csp.gamma && dst.gamma != fbo_csp.gamma) ||
+ ((fbo_csp.transfer && dst.transfer != fbo_csp.transfer) ||
(fbo_csp.primaries && dst.primaries != fbo_csp.primaries)))
{
MP_WARN(p, "One or more colorspace value is being overridden "
@@ -2580,44 +2586,44 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src,
"transfer function: (dst: %s, fbo: %s), "
"primaries: (dst: %s, fbo: %s). "
"Rendering can lead to incorrect results!\n",
- m_opt_choice_str(mp_csp_trc_names, dst.gamma),
- m_opt_choice_str(mp_csp_trc_names, fbo_csp.gamma),
- m_opt_choice_str(mp_csp_prim_names, dst.primaries),
- m_opt_choice_str(mp_csp_prim_names, fbo_csp.primaries));
+ m_opt_choice_str(pl_csp_trc_names, dst.transfer),
+ m_opt_choice_str(pl_csp_trc_names, fbo_csp.transfer),
+ m_opt_choice_str(pl_csp_prim_names, dst.primaries),
+ m_opt_choice_str(pl_csp_prim_names, fbo_csp.primaries));
p->colorspace_override_warned = true;
}
- if (dst.gamma == MP_CSP_TRC_HLG)
- dst.light = MP_CSP_LIGHT_SCENE_HLG;
+ enum mp_csp_light dst_light = dst.transfer == PL_COLOR_TRC_HLG ?
+ MP_CSP_LIGHT_SCENE_HLG : MP_CSP_LIGHT_DISPLAY;
if (p->use_lut_3d && (flags & RENDER_SCREEN_COLOR)) {
// The 3DLUT is always generated against the video's original source
// space, *not* the reference space. (To avoid having to regenerate
// the 3DLUT for the OSD on every frame)
- enum mp_csp_prim prim_orig = p->image_params.color.primaries;
- enum mp_csp_trc trc_orig = p->image_params.color.gamma;
+ enum pl_color_primaries prim_orig = p->image_params.color.primaries;
+ enum pl_color_transfer trc_orig = p->image_params.color.transfer;
// One exception: HDR is not implemented by LittleCMS for technical
// limitation reasons, so we use a gamma 2.2 input curve here instead.
// We could pick any value we want here, the difference is just coding
// efficiency.
- if (mp_trc_is_hdr(trc_orig))
- trc_orig = MP_CSP_TRC_GAMMA22;
+ if (pl_color_space_is_hdr(&p->image_params.color))
+ trc_orig = PL_COLOR_TRC_GAMMA22;
if (gl_video_get_lut3d(p, prim_orig, trc_orig)) {
dst.primaries = prim_orig;
- dst.gamma = trc_orig;
- assert(dst.primaries && dst.gamma);
+ dst.transfer = trc_orig;
+ assert(dst.primaries && dst.transfer);
}
}
- if (dst.primaries == MP_CSP_PRIM_AUTO) {
+ if (dst.primaries == PL_COLOR_PRIM_UNKNOWN) {
// The vast majority of people are on sRGB or BT.709 displays, so pick
// this as the default output color space.
- dst.primaries = MP_CSP_PRIM_BT_709;
+ dst.primaries = PL_COLOR_PRIM_BT_709;
- if (src.primaries == MP_CSP_PRIM_BT_601_525 ||
- src.primaries == MP_CSP_PRIM_BT_601_625)
+ if (src.primaries == PL_COLOR_PRIM_BT_601_525 ||
+ src.primaries == PL_COLOR_PRIM_BT_601_625)
{
// Since we auto-pick BT.601 and BT.709 based on the dimensions,
// combined with the fact that they're very similar to begin with,
@@ -2627,28 +2633,28 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src,
}
}
- if (dst.gamma == MP_CSP_TRC_AUTO) {
+ if (dst.transfer == PL_COLOR_TRC_UNKNOWN) {
// Most people seem to complain when the image is darker or brighter
// than what they're "used to", so just avoid changing the gamma
// altogether by default. The only exceptions to this rule apply to
// very unusual TRCs, which even hardcode technoluddites would probably
// not enjoy viewing unaltered.
- dst.gamma = src.gamma;
+ dst.transfer = src.transfer;
// Avoid outputting linear light or HDR content "by default". For these
// just pick gamma 2.2 as a default, since it's a good estimate for
// the response of typical displays
- if (dst.gamma == MP_CSP_TRC_LINEAR || mp_trc_is_hdr(dst.gamma))
- dst.gamma = MP_CSP_TRC_GAMMA22;
+ if (dst.transfer == PL_COLOR_TRC_LINEAR || pl_color_space_is_hdr(&dst))
+ dst.transfer = PL_COLOR_TRC_GAMMA22;
}
// If there's no specific signal peak known for the output display, infer
// it from the chosen transfer function. Also normalize the src peak, in
// case it was unknown
if (!dst.hdr.max_luma)
- dst.hdr.max_luma = mp_trc_nom_peak(dst.gamma) * MP_REF_WHITE;
+ dst.hdr.max_luma = pl_color_transfer_nominal_peak(dst.transfer) * MP_REF_WHITE;
if (!src.hdr.max_luma)
- src.hdr.max_luma = mp_trc_nom_peak(src.gamma) * MP_REF_WHITE;
+ src.hdr.max_luma = pl_color_transfer_nominal_peak(src.transfer) * MP_REF_WHITE;
// Whitelist supported modes
switch (p->opts.tone_map.curve) {
@@ -2680,7 +2686,7 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src,
}
struct gl_tone_map_opts tone_map = p->opts.tone_map;
- bool detect_peak = tone_map.compute_peak >= 0 && mp_trc_is_hdr(src.gamma)
+ bool detect_peak = tone_map.compute_peak >= 0 && pl_color_space_is_hdr(&src)
&& src.hdr.max_luma > dst.hdr.max_luma;
if (detect_peak && !p->hdr_peak_ssbo) {
@@ -2719,7 +2725,22 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src,
}
// Adapt from src to dst as necessary
- pass_color_map(p->sc, p->use_linear && !osd, src, dst, &tone_map);
+ pass_color_map(p->sc, p->use_linear && !osd, src, dst, src_light, dst_light, &tone_map);
+
+ if (!osd) {
+ struct mp_csp_params cparams = MP_CSP_PARAMS_DEFAULTS;
+ mp_csp_equalizer_state_get(p->video_eq, &cparams);
+ if (cparams.levels_out == PL_COLOR_LEVELS_UNKNOWN)
+ cparams.levels_out = PL_COLOR_LEVELS_FULL;
+ p->target_params = (struct mp_image_params){
+ .imgfmt_name = p->fbo_format ? p->fbo_format->name : "unknown",
+ .w = p->texture_w,
+ .h = p->texture_h,
+ .color = dst,
+ .repr = {.sys = PL_COLOR_SYSTEM_RGB, .levels = cparams.levels_out},
+ .rotate = p->image_params.rotate,
+ };
+ }
if (p->use_lut_3d && (flags & RENDER_SCREEN_COLOR)) {
gl_sc_uniform_texture(p->sc, "lut_3d", p->lut_3d_texture);
@@ -2735,7 +2756,7 @@ void gl_video_set_fb_depth(struct gl_video *p, int fb_depth)
p->fb_depth = fb_depth;
}
-static void pass_dither(struct gl_video *p)
+static void pass_dither(struct gl_video *p, const struct ra_fbo *fbo)
{
// Assume 8 bits per component if unknown.
int dst_depth = p->fb_depth > 0 ? p->fb_depth : 8;
@@ -2868,7 +2889,9 @@ static void pass_dither(struct gl_video *p)
gl_sc_uniform_texture(p->sc, "dither", p->dither_texture);
- GLSLF("vec2 dither_pos = gl_FragCoord.xy * 1.0/%d.0;\n", dither_size);
+ GLSLF("vec2 dither_coord = vec2(gl_FragCoord.x, %d.0 + %f * gl_FragCoord.y);",
+ fbo->flip ? fbo->tex->params.h : 0, fbo->flip ? -1.0 : 1.0);
+ GLSLF("vec2 dither_pos = dither_coord * 1.0/%d.0;\n", dither_size);
if (p->opts.temporal_dither) {
int phase = (p->frames_rendered / p->opts.temporal_dither_period) % 8u;
@@ -2891,7 +2914,7 @@ static void pass_dither(struct gl_video *p)
// Draws the OSD, in scene-referred colors.. If cms is true, subtitles are
// instead adapted to the display's gamut.
static void pass_draw_osd(struct gl_video *p, int osd_flags, int frame_flags,
- double pts, struct mp_osd_res rect, struct ra_fbo fbo,
+ double pts, struct mp_osd_res rect, const struct ra_fbo *fbo,
bool cms)
{
if (frame_flags & RENDER_FRAME_VF_SUBS)
@@ -2910,20 +2933,21 @@ static void pass_draw_osd(struct gl_video *p, int osd_flags, int frame_flags,
// When subtitles need to be color managed, assume they're in sRGB
// (for lack of anything saner to do)
if (cms) {
- static const struct mp_colorspace csp_srgb = {
- .primaries = MP_CSP_PRIM_BT_709,
- .gamma = MP_CSP_TRC_SRGB,
- .light = MP_CSP_LIGHT_DISPLAY,
+ static const struct pl_color_space csp_srgb = {
+ .primaries = PL_COLOR_PRIM_BT_709,
+ .transfer = PL_COLOR_TRC_SRGB,
};
- pass_colormanage(p, csp_srgb, fbo.color_space, frame_flags, true);
+ pass_colormanage(p, csp_srgb, MP_CSP_LIGHT_DISPLAY, fbo->color_space,
+ frame_flags, true);
}
mpgl_osd_draw_finish(p->osd, n, p->sc, fbo);
}
timer_pool_stop(p->osd_timer);
pass_describe(p, "drawing osd");
- pass_record(p, timer_pool_measure(p->osd_timer));
+ struct mp_pass_perf perf = timer_pool_measure(p->osd_timer);
+ pass_record(p, &perf);
}
static float chroma_realign(int size, int pixel)
@@ -3013,7 +3037,7 @@ static bool pass_render_frame(struct gl_video *p, struct mp_image *mpi,
};
finish_pass_tex(p, &p->blend_subs_tex, rect.w, rect.h);
struct ra_fbo fbo = { p->blend_subs_tex };
- pass_draw_osd(p, OSD_DRAW_SUB_ONLY, flags, vpts, rect, fbo, false);
+ pass_draw_osd(p, OSD_DRAW_SUB_ONLY, flags, vpts, rect, &fbo, false);
pass_read_tex(p, p->blend_subs_tex);
pass_describe(p, "blend subs video");
}
@@ -3040,12 +3064,12 @@ static bool pass_render_frame(struct gl_video *p, struct mp_image *mpi,
rect.mt *= scale[1]; rect.mb *= scale[1];
// We should always blend subtitles in non-linear light
if (p->use_linear) {
- pass_delinearize(p->sc, p->image_params.color.gamma);
+ pass_delinearize(p->sc, p->image_params.color.transfer);
p->use_linear = false;
}
finish_pass_tex(p, &p->blend_subs_tex, p->texture_w, p->texture_h);
struct ra_fbo fbo = { p->blend_subs_tex };
- pass_draw_osd(p, OSD_DRAW_SUB_ONLY, flags, vpts, rect, fbo, false);
+ pass_draw_osd(p, OSD_DRAW_SUB_ONLY, flags, vpts, rect, &fbo, false);
pass_read_tex(p, p->blend_subs_tex);
pass_describe(p, "blend subs");
}
@@ -3055,7 +3079,7 @@ static bool pass_render_frame(struct gl_video *p, struct mp_image *mpi,
return true;
}
-static void pass_draw_to_screen(struct gl_video *p, struct ra_fbo fbo, int flags)
+static void pass_draw_to_screen(struct gl_video *p, const struct ra_fbo *fbo, int flags)
{
if (p->dumb_mode)
pass_render_frame_dumb(p);
@@ -3067,7 +3091,8 @@ static void pass_draw_to_screen(struct gl_video *p, struct ra_fbo fbo, int flags
GLSL(color.rgb = pow(color.rgb, vec3(user_gamma));)
}
- pass_colormanage(p, p->image_params.color, fbo.color_space, flags, false);
+ pass_colormanage(p, p->image_params.color, p->image_params.light,
+ fbo->color_space, flags, false);
// Since finish_pass_fbo doesn't work with compute shaders, and neither
// does the checkerboard/dither code, we may need an indirection via
@@ -3080,28 +3105,30 @@ static void pass_draw_to_screen(struct gl_video *p, struct ra_fbo fbo, int flags
copy_image(p, &(int){0}, tmp);
}
- if (p->has_alpha){
- if (p->opts.alpha_mode == ALPHA_BLEND_TILES) {
+ if (p->has_alpha) {
+ if (p->opts.background == BACKGROUND_TILES) {
// Draw checkerboard pattern to indicate transparency
GLSLF("// transparency checkerboard\n");
- GLSL(bvec2 tile = lessThan(fract(gl_FragCoord.xy * 1.0/32.0), vec2(0.5));)
+ GLSLF("vec2 tile_coord = vec2(gl_FragCoord.x, %d.0 + %f * gl_FragCoord.y);",
+ fbo->flip ? fbo->tex->params.h : 0, fbo->flip ? -1.0 : 1.0);
+ GLSL(bvec2 tile = lessThan(fract(tile_coord * 1.0 / 32.0), vec2(0.5));)
GLSL(vec3 background = vec3(tile.x == tile.y ? 0.93 : 0.87);)
GLSL(color.rgb += background.rgb * (1.0 - color.a);)
GLSL(color.a = 1.0;)
- } else if (p->opts.alpha_mode == ALPHA_BLEND) {
+ } else if (p->opts.background == BACKGROUND_COLOR) {
// Blend into background color (usually black)
- struct m_color c = p->opts.background;
+ struct m_color c = p->opts.background_color;
GLSLF("vec4 background = vec4(%f, %f, %f, %f);\n",
c.r / 255.0, c.g / 255.0, c.b / 255.0, c.a / 255.0);
- GLSL(color.rgb += background.rgb * (1.0 - color.a);)
- GLSL(color.a = background.a;)
+ GLSL(color += background * (1.0 - color.a);)
+ GLSL(color.rgb *= vec3(color.a););
}
}
pass_opt_hook_point(p, "OUTPUT", NULL);
if (flags & RENDER_SCREEN_COLOR)
- pass_dither(p);
+ pass_dither(p, fbo);
pass_describe(p, "output to screen");
finish_pass_fbo(p, fbo, false, &p->dst_rect);
}
@@ -3122,7 +3149,7 @@ static bool update_surface(struct gl_video *p, struct mp_image *mpi,
// because mixing in compressed light artificially darkens the results
if (!p->use_linear) {
p->use_linear = true;
- pass_linearize(p->sc, p->image_params.color.gamma);
+ pass_linearize(p->sc, p->image_params.color.transfer);
}
finish_pass_tex(p, &surf->tex, vp_w, vp_h);
@@ -3134,7 +3161,7 @@ static bool update_surface(struct gl_video *p, struct mp_image *mpi,
// Draws an interpolate frame to fbo, based on the frame timing in t
// flags: bit set of RENDER_FRAME_* flags
static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t,
- struct ra_fbo fbo, int flags)
+ const struct ra_fbo *fbo, int flags)
{
bool is_new = false;
@@ -3201,7 +3228,7 @@ static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t,
struct mp_image *f = t->frames[i];
uint64_t f_id = t->frame_id + i;
- if (!mp_image_params_equal(&f->params, &p->real_image_params))
+ if (!mp_image_params_static_equal(&f->params, &p->real_image_params))
continue;
if (f_id > p->surfaces[p->surface_idx].id) {
@@ -3306,11 +3333,11 @@ static void gl_video_interpolate_frame(struct gl_video *p, struct vo_frame *t,
}
void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame,
- struct ra_fbo fbo, int flags)
+ const struct ra_fbo *fbo, int flags)
{
gl_video_update_options(p);
- struct mp_rect target_rc = {0, 0, fbo.tex->params.w, fbo.tex->params.h};
+ struct mp_rect target_rc = {0, 0, fbo->tex->params.w, fbo->tex->params.h};
p->broken_frame = false;
@@ -3318,12 +3345,15 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame,
struct m_color c = p->clear_color;
float clear_color[4] = {c.r / 255.0, c.g / 255.0, c.b / 255.0, c.a / 255.0};
- p->ra->fns->clear(p->ra, fbo.tex, clear_color, &target_rc);
+ clear_color[0] *= clear_color[3];
+ clear_color[1] *= clear_color[3];
+ clear_color[2] *= clear_color[3];
+ p->ra->fns->clear(p->ra, fbo->tex, clear_color, &target_rc);
if (p->hwdec_overlay) {
if (has_frame) {
float *color = p->hwdec_overlay->overlay_colorkey;
- p->ra->fns->clear(p->ra, fbo.tex, color, &p->dst_rect);
+ p->ra->fns->clear(p->ra, fbo->tex, color, &p->dst_rect);
}
p->hwdec_overlay->driver->overlay_frame(p->hwdec_overlay, frame->current,
@@ -3364,43 +3394,41 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame,
// For the non-interpolation case, we draw to a single "cache"
// texture to speed up subsequent re-draws (if any exist)
- struct ra_fbo dest_fbo = fbo;
bool repeats = frame->num_vsyncs > 1 && frame->display_synced;
+ bool r = false;
if ((repeats || frame->still) && !p->dumb_mode &&
- (p->ra->caps & RA_CAP_BLIT) && fbo.tex->params.blit_dst)
+ (p->ra->caps & RA_CAP_BLIT) && fbo->tex->params.blit_dst)
{
// Attempt to use the same format as the destination FBO
// if possible. Some RAs use a wrapped dummy format here,
// so fall back to the fbo_format in that case.
- const struct ra_format *fmt = fbo.tex->params.format;
+ const struct ra_format *fmt = fbo->tex->params.format;
if (fmt->dummy_format)
fmt = p->fbo_format;
-
- bool r = ra_tex_resize(p->ra, p->log, &p->output_tex,
- fbo.tex->params.w, fbo.tex->params.h,
- fmt);
- if (r) {
- dest_fbo = (struct ra_fbo) { p->output_tex };
- p->output_tex_valid = true;
- }
+ r = ra_tex_resize(p->ra, p->log, &p->output_tex,
+ fbo->tex->params.w, fbo->tex->params.h,
+ fmt);
}
+ const struct ra_fbo *dest_fbo = r ? &(struct ra_fbo) { p->output_tex } : fbo;
+ p->output_tex_valid = r;
pass_draw_to_screen(p, dest_fbo, flags);
}
// "output tex valid" and "output tex needed" are equivalent
- if (p->output_tex_valid && fbo.tex->params.blit_dst) {
+ if (p->output_tex_valid && fbo->tex->params.blit_dst) {
pass_info_reset(p, true);
pass_describe(p, "redraw cached frame");
struct mp_rect src = p->dst_rect;
struct mp_rect dst = src;
- if (fbo.flip) {
- dst.y0 = fbo.tex->params.h - src.y0;
- dst.y1 = fbo.tex->params.h - src.y1;
+ if (fbo->flip) {
+ dst.y0 = fbo->tex->params.h - src.y0;
+ dst.y1 = fbo->tex->params.h - src.y1;
}
timer_pool_start(p->blit_timer);
- p->ra->fns->blit(p->ra, fbo.tex, p->output_tex, &dst, &src);
+ p->ra->fns->blit(p->ra, fbo->tex, p->output_tex, &dst, &src);
timer_pool_stop(p->blit_timer);
- pass_record(p, timer_pool_measure(p->blit_timer));
+ struct mp_pass_perf perf = timer_pool_measure(p->blit_timer);
+ pass_record(p, &perf);
}
}
}
@@ -3431,7 +3459,7 @@ done:
// Make the screen solid blue to make it visually clear that an
// error has occurred
float color[4] = {0.0, 0.05, 0.5, 1.0};
- p->ra->fns->clear(p->ra, fbo.tex, color, &target_rc);
+ p->ra->fns->clear(p->ra, fbo->tex, color, &target_rc);
}
p->frames_rendered++;
@@ -3522,7 +3550,7 @@ void gl_video_screenshot(struct gl_video *p, struct vo_frame *frame,
flags |= RENDER_FRAME_OSD;
if (args->scaled)
flags |= RENDER_SCREEN_COLOR;
- gl_video_render_frame(p, nframe, (struct ra_fbo){target}, flags);
+ gl_video_render_frame(p, nframe, &(struct ra_fbo){target}, flags);
res = mp_image_alloc(mpfmt, params.w, params.h);
if (!res)
@@ -3636,7 +3664,8 @@ static bool pass_upload_image(struct gl_video *p, struct mp_image *mpi, uint64_t
timer_pool_start(p->upload_timer);
bool ok = ra_hwdec_mapper_map(p->hwdec_mapper, vimg->mpi) >= 0;
timer_pool_stop(p->upload_timer);
- pass_record(p, timer_pool_measure(p->upload_timer));
+ struct mp_pass_perf perf = timer_pool_measure(p->upload_timer);
+ pass_record(p, &perf);
vimg->hwdec_mapped = true;
if (ok) {
@@ -3708,7 +3737,8 @@ static bool pass_upload_image(struct gl_video *p, struct mp_image *mpi, uint64_t
bool using_pbo = p->ra->use_pbo || !(p->ra->caps & RA_CAP_DIRECT_UPLOAD);
const char *mode = p->using_dr_path ? "DR" : using_pbo ? "PBO" : "naive";
pass_describe(p, "upload frame (%s)", mode);
- pass_record(p, timer_pool_measure(p->upload_timer));
+ struct mp_pass_perf perf = timer_pool_measure(p->upload_timer);
+ pass_record(p, &perf);
return true;
@@ -3806,9 +3836,8 @@ static void check_gl_features(struct gl_video *p)
p->opts.dither_algo = DITHER_NONE;
MP_WARN(p, "Disabling dithering (no gl_FragCoord).\n");
}
- if (!have_fragcoord && p->opts.alpha_mode == ALPHA_BLEND_TILES) {
- p->opts.alpha_mode = ALPHA_BLEND;
- // Verbose, since this is the default setting
+ if (!have_fragcoord && p->opts.background == BACKGROUND_TILES) {
+ p->opts.background = BACKGROUND_COLOR;
MP_VERBOSE(p, "Disabling alpha checkerboard (no gl_FragCoord).\n");
}
if (!have_fbo && have_compute) {
@@ -3864,9 +3893,9 @@ static void check_gl_features(struct gl_video *p)
.gamma_auto = p->opts.gamma_auto,
.pbo = p->opts.pbo,
.fbo_format = p->opts.fbo_format,
- .alpha_mode = p->opts.alpha_mode,
- .use_rectangle = p->opts.use_rectangle,
.background = p->opts.background,
+ .use_rectangle = p->opts.use_rectangle,
+ .background_color = p->opts.background_color,
.dither_algo = p->opts.dither_algo,
.dither_depth = p->opts.dither_depth,
.dither_size = p->opts.dither_size,
@@ -3913,8 +3942,8 @@ static void check_gl_features(struct gl_video *p)
}
}
- int use_cms = p->opts.target_prim != MP_CSP_PRIM_AUTO ||
- p->opts.target_trc != MP_CSP_TRC_AUTO || p->use_lut_3d;
+ int use_cms = p->opts.target_prim != PL_COLOR_PRIM_UNKNOWN ||
+ p->opts.target_trc != PL_COLOR_TRC_UNKNOWN || p->use_lut_3d;
// mix() is needed for some gamma functions
if (!have_mglsl && (p->opts.linear_downscaling ||
@@ -3926,8 +3955,8 @@ static void check_gl_features(struct gl_video *p)
MP_WARN(p, "Disabling linear/sigmoid scaling (GLSL version too old).\n");
}
if (!have_mglsl && use_cms) {
- p->opts.target_prim = MP_CSP_PRIM_AUTO;
- p->opts.target_trc = MP_CSP_TRC_AUTO;
+ p->opts.target_prim = PL_COLOR_PRIM_UNKNOWN;
+ p->opts.target_trc = PL_COLOR_TRC_UNKNOWN;
p->use_lut_3d = false;
MP_WARN(p, "Disabling color management (GLSL version too old).\n");
}
@@ -4022,7 +4051,7 @@ void gl_video_config(struct gl_video *p, struct mp_image_params *params)
unmap_overlay(p);
unref_current_image(p);
- if (!mp_image_params_equal(&p->real_image_params, params)) {
+ if (!mp_image_params_static_equal(&p->real_image_params, params)) {
uninit_video(p);
p->real_image_params = *params;
p->image_params = *params;
@@ -4117,7 +4146,7 @@ static void reinit_from_options(struct gl_video *p)
p->opts = *(struct gl_video_opts *)p->opts_cache->opts;
if (!p->force_clear_color)
- p->clear_color = p->opts.background;
+ p->clear_color = p->opts.background_color;
check_gl_features(p);
uninit_rendering(p);
@@ -4362,3 +4391,8 @@ void gl_video_load_hwdecs_for_img_fmt(struct gl_video *p, struct mp_hwdec_device
assert(p->hwdec_ctx.ra_ctx);
ra_hwdec_ctx_load_fmt(&p->hwdec_ctx, devs, params);
}
+
+struct mp_image_params *gl_video_get_target_params_ptr(struct gl_video *p)
+{
+ return &p->target_params;
+}