From 4fed18e81e7ffca623e4260d8569f959410b10bb Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Fri, 6 Feb 2015 03:37:21 +0100 Subject: vo_opengl: add support for linear scaling without CMS This introduces a new option linear-scaling, which is now implied by srgb, icc-profile and sigmoid-upscaling. Notably, this means (sigmoidized) linear upscaling is now enabled by default in opengl-hq mode. The impact should be negligible, and there has been no observation of negative side effects of sigmoidized scaling, so it feels safe to do so. --- DOCS/man/vo.rst | 15 +++++++++----- video/out/gl_video.c | 45 ++++++++++++++++++++++++----------------- video/out/gl_video.h | 1 + video/out/gl_video_shaders.glsl | 3 +++ 4 files changed, 41 insertions(+), 23 deletions(-) diff --git a/DOCS/man/vo.rst b/DOCS/man/vo.rst index 2f23bf7ca9..2a01af1b43 100644 --- a/DOCS/man/vo.rst +++ b/DOCS/man/vo.rst @@ -359,7 +359,7 @@ Available video output drivers are: ``srgb`` Convert and color correct the output to sRGB before displaying it on - the screen. This option enables linear light scaling. + the screen. This option enables ``linear-scaling``. This option is equivalent to using ``icc-profile`` with an sRGB ICC profile, but it is implemented without a 3DLUT and does not require @@ -438,6 +438,11 @@ Available video output drivers are: See ``scale-param1``, ``scale-param2``, ``scale-radius`` and ``scale-antiring``. + ``linear-scaling`` + Scale in linear light. This is automatically enabled if ``srgb``, + ``icc-profile`` or ``sigmoid-upscaling`` is set. It should only + be used with a ``fbo-format`` that has at least 16 bit precision. + ``fancy-downscaling`` When using convolution based filters, extend the filter size when downscaling. Trades quality for reduced downscaling performance. @@ -447,8 +452,8 @@ Available video output drivers are: different directions. ``sigmoid-upscaling`` - When upscaling in linear light, use a sigmoidal color transform - to avoid emphasizing ringing artifacts. + When upscaling, use a sigmoidal color transform to avoid emphasizing + ringing artifacts. This also enables ``linear-scaling``. ``sigmoid-center`` The center of the sigmoid curve used for ``sigmoid-upscaling``, must @@ -521,8 +526,8 @@ Available video output drivers are: ``icc-profile=`` Load an ICC profile and use it to transform linear RGB to screen output. Needs LittleCMS 2 support compiled in. This option overrides the ``srgb`` - property, as using both is somewhat redundant. It also enables linear - light scaling. + property, as using both is somewhat redundant. It also enables + ``linear-scaling``. ``icc-profile-auto`` diff --git a/video/out/gl_video.c b/video/out/gl_video.c index 9d69c822d8..231d77bdf3 100644 --- a/video/out/gl_video.c +++ b/video/out/gl_video.c @@ -370,6 +370,7 @@ const struct m_sub_options gl_video_conf = { OPT_FLOATRANGE("scale-antiring", scaler_antiring[0], 0, 0.0, 1.0), OPT_FLOATRANGE("cscale-antiring", scaler_antiring[1], 0, 0.0, 1.0), OPT_FLAG("scaler-resizes-only", scaler_resizes_only, 0), + OPT_FLAG("linear-scaling", linear_scaling, 0), OPT_FLAG("fancy-downscaling", fancy_downscaling, 0), OPT_FLAG("sigmoid-upscaling", sigmoid_upscaling, 0), OPT_FLOATRANGE("sigmoid-center", sigmoid_center, 0, 0.0, 1.0), @@ -904,6 +905,8 @@ static void compile_shaders(struct gl_video *p) rg, tex1d, tex3d, arrays, shader_prelude, PRELUDE_END); bool use_cms = p->opts.srgb || p->use_lut_3d; + // 3DLUT overrides sRGB + bool use_srgb = p->opts.srgb && !p->use_lut_3d; float input_gamma = 1.0; float conv_gamma = 1.0; @@ -911,12 +914,8 @@ static void compile_shaders(struct gl_video *p) bool is_xyz = p->image_desc.flags & MP_IMGFLAG_XYZ; if (is_xyz) { input_gamma *= 2.6; - - // If we're using cms, we can treat it as proper linear input, - // otherwise we just scale back to 2.40 to match typical displays, - // as a reasonable approximation. - if (!use_cms) - conv_gamma *= 1.0 / 2.40; + // Note that this results in linear light, so we make sure to enable + // use_linear_light for XYZ inputs as well. } p->input_gamma = input_gamma; @@ -928,10 +927,13 @@ static void compile_shaders(struct gl_video *p) enum mp_csp_trc gamma_fun = MP_CSP_TRC_NONE; - // Linear light scaling is only enabled when either color correction - // option (3dlut or srgb) is enabled, otherwise scaling is done in the - // source space. - if (use_cms) { + // If either color correction option (3dlut or srgb) is enabled, or if + // sigmoidal upscaling is requested, or if the source is linear XYZ, we + // always scale in linear light + bool use_linear_light = p->opts.linear_scaling || p->opts.sigmoid_upscaling + || use_cms || is_xyz; + + if (use_linear_light) { // We use the color level range to distinguish between PC // content like images, which are most likely sRGB, and TV content // like movies, which are most likely BT.1886. XYZ input is always @@ -945,11 +947,19 @@ static void compile_shaders(struct gl_video *p) } } - bool use_linear_light = gamma_fun != MP_CSP_TRC_NONE; + // The inverse of the above transformation is normally handled by + // the CMS cases, but if CMS is disabled we need to go back manually + bool use_inv_bt1886 = false; + if (use_linear_light && !use_cms) { + if (gamma_fun == MP_CSP_TRC_SRGB) { + use_srgb = true; + } else { + use_inv_bt1886 = true; + } + } - // Optionally transform to sigmoidal color space if requested, but only - // when upscaling in linear light - p->sigmoid_enabled = p->opts.sigmoid_upscaling && use_linear_light; + // Optionally transform to sigmoidal color space if requested. + p->sigmoid_enabled = p->opts.sigmoid_upscaling; bool use_sigmoid = p->sigmoid_enabled && p->upscaling; // Figure out the right color spaces we need to convert, if any @@ -994,8 +1004,7 @@ static void compile_shaders(struct gl_video *p) use_cms && gamma_fun == MP_CSP_TRC_SRGB); shader_def_opt(&header_osd, "USE_OSD_CMS_MATRIX", use_cms_matrix); shader_def_opt(&header_osd, "USE_OSD_3DLUT", p->use_lut_3d); - // 3DLUT overrides SRGB - shader_def_opt(&header_osd, "USE_OSD_SRGB", !p->use_lut_3d && p->opts.srgb); + shader_def_opt(&header_osd, "USE_OSD_SRGB", use_cms && use_srgb); for (int n = 0; n < SUBBITMAP_COUNT; n++) { const char *name = osd_shaders[n]; @@ -1042,8 +1051,8 @@ static void compile_shaders(struct gl_video *p) shader_def_opt(&header_final, "USE_INV_GAMMA", p->user_gamma_enabled); shader_def_opt(&header_final, "USE_CMS_MATRIX", use_cms_matrix); shader_def_opt(&header_final, "USE_3DLUT", p->use_lut_3d); - // 3DLUT overrides SRGB - shader_def_opt(&header_final, "USE_SRGB", p->opts.srgb && !p->use_lut_3d); + shader_def_opt(&header_final, "USE_SRGB", use_srgb); + shader_def_opt(&header_final, "USE_INV_BT1886", use_inv_bt1886); shader_def_opt(&header_final, "USE_DITHER", p->dither_texture != 0); shader_def_opt(&header_final, "USE_TEMPORAL_DITHER", p->opts.temporal_dither); diff --git a/video/out/gl_video.h b/video/out/gl_video.h index 63e33718ce..74a8b7fd93 100644 --- a/video/out/gl_video.h +++ b/video/out/gl_video.h @@ -36,6 +36,7 @@ struct gl_video_opts { float scaler_antiring[2]; float gamma; int srgb; + int linear_scaling; int fancy_downscaling; int sigmoid_upscaling; float sigmoid_center; diff --git a/video/out/gl_video_shaders.glsl b/video/out/gl_video_shaders.glsl index a7348a47e7..636828c0ca 100644 --- a/video/out/gl_video_shaders.glsl +++ b/video/out/gl_video_shaders.glsl @@ -508,6 +508,9 @@ void main() { // Adapt and compand from the linear BT2020 source to the sRGB output color = srgb_compand(color); #endif +#ifdef USE_INV_BT1886 + color = pow(color, vec3(1.0/1.961)); +#endif #ifdef USE_DITHER vec2 dither_pos = gl_FragCoord.xy / dither_size; #ifdef USE_TEMPORAL_DITHER -- cgit v1.2.3