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.
This commit is contained in:
Niklas Haas 2015-02-06 03:37:21 +01:00
parent 4872443fc0
commit 4fed18e81e
No known key found for this signature in database
GPG Key ID: 3BA77D4BFDB10BCE
4 changed files with 41 additions and 23 deletions

View File

@ -359,7 +359,7 @@ Available video output drivers are:
``srgb`` ``srgb``
Convert and color correct the output to sRGB before displaying it on 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 This option is equivalent to using ``icc-profile`` with an sRGB ICC
profile, but it is implemented without a 3DLUT and does not require 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 See ``scale-param1``, ``scale-param2``, ``scale-radius`` and
``scale-antiring``. ``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`` ``fancy-downscaling``
When using convolution based filters, extend the filter size When using convolution based filters, extend the filter size
when downscaling. Trades quality for reduced downscaling performance. when downscaling. Trades quality for reduced downscaling performance.
@ -447,8 +452,8 @@ Available video output drivers are:
different directions. different directions.
``sigmoid-upscaling`` ``sigmoid-upscaling``
When upscaling in linear light, use a sigmoidal color transform When upscaling, use a sigmoidal color transform to avoid emphasizing
to avoid emphasizing ringing artifacts. ringing artifacts. This also enables ``linear-scaling``.
``sigmoid-center`` ``sigmoid-center``
The center of the sigmoid curve used for ``sigmoid-upscaling``, must The center of the sigmoid curve used for ``sigmoid-upscaling``, must
@ -521,8 +526,8 @@ Available video output drivers are:
``icc-profile=<file>`` ``icc-profile=<file>``
Load an ICC profile and use it to transform linear RGB to screen output. 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`` Needs LittleCMS 2 support compiled in. This option overrides the ``srgb``
property, as using both is somewhat redundant. It also enables linear property, as using both is somewhat redundant. It also enables
light scaling. ``linear-scaling``.
``icc-profile-auto`` ``icc-profile-auto``

View File

@ -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("scale-antiring", scaler_antiring[0], 0, 0.0, 1.0),
OPT_FLOATRANGE("cscale-antiring", scaler_antiring[1], 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("scaler-resizes-only", scaler_resizes_only, 0),
OPT_FLAG("linear-scaling", linear_scaling, 0),
OPT_FLAG("fancy-downscaling", fancy_downscaling, 0), OPT_FLAG("fancy-downscaling", fancy_downscaling, 0),
OPT_FLAG("sigmoid-upscaling", sigmoid_upscaling, 0), OPT_FLAG("sigmoid-upscaling", sigmoid_upscaling, 0),
OPT_FLOATRANGE("sigmoid-center", sigmoid_center, 0, 0.0, 1.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); rg, tex1d, tex3d, arrays, shader_prelude, PRELUDE_END);
bool use_cms = p->opts.srgb || p->use_lut_3d; 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 input_gamma = 1.0;
float conv_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; bool is_xyz = p->image_desc.flags & MP_IMGFLAG_XYZ;
if (is_xyz) { if (is_xyz) {
input_gamma *= 2.6; input_gamma *= 2.6;
// Note that this results in linear light, so we make sure to enable
// If we're using cms, we can treat it as proper linear input, // use_linear_light for XYZ inputs as well.
// 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;
} }
p->input_gamma = input_gamma; 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; enum mp_csp_trc gamma_fun = MP_CSP_TRC_NONE;
// Linear light scaling is only enabled when either color correction // If either color correction option (3dlut or srgb) is enabled, or if
// option (3dlut or srgb) is enabled, otherwise scaling is done in the // sigmoidal upscaling is requested, or if the source is linear XYZ, we
// source space. // always scale in linear light
if (use_cms) { 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 // We use the color level range to distinguish between PC
// content like images, which are most likely sRGB, and TV content // content like images, which are most likely sRGB, and TV content
// like movies, which are most likely BT.1886. XYZ input is always // 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 // Optionally transform to sigmoidal color space if requested.
// when upscaling in linear light p->sigmoid_enabled = p->opts.sigmoid_upscaling;
p->sigmoid_enabled = p->opts.sigmoid_upscaling && use_linear_light;
bool use_sigmoid = p->sigmoid_enabled && p->upscaling; bool use_sigmoid = p->sigmoid_enabled && p->upscaling;
// Figure out the right color spaces we need to convert, if any // 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); 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_CMS_MATRIX", use_cms_matrix);
shader_def_opt(&header_osd, "USE_OSD_3DLUT", p->use_lut_3d); shader_def_opt(&header_osd, "USE_OSD_3DLUT", p->use_lut_3d);
// 3DLUT overrides SRGB shader_def_opt(&header_osd, "USE_OSD_SRGB", use_cms && use_srgb);
shader_def_opt(&header_osd, "USE_OSD_SRGB", !p->use_lut_3d && p->opts.srgb);
for (int n = 0; n < SUBBITMAP_COUNT; n++) { for (int n = 0; n < SUBBITMAP_COUNT; n++) {
const char *name = osd_shaders[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_INV_GAMMA", p->user_gamma_enabled);
shader_def_opt(&header_final, "USE_CMS_MATRIX", use_cms_matrix); shader_def_opt(&header_final, "USE_CMS_MATRIX", use_cms_matrix);
shader_def_opt(&header_final, "USE_3DLUT", p->use_lut_3d); shader_def_opt(&header_final, "USE_3DLUT", p->use_lut_3d);
// 3DLUT overrides SRGB shader_def_opt(&header_final, "USE_SRGB", use_srgb);
shader_def_opt(&header_final, "USE_SRGB", p->opts.srgb && !p->use_lut_3d); 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_DITHER", p->dither_texture != 0);
shader_def_opt(&header_final, "USE_TEMPORAL_DITHER", p->opts.temporal_dither); shader_def_opt(&header_final, "USE_TEMPORAL_DITHER", p->opts.temporal_dither);

View File

@ -36,6 +36,7 @@ struct gl_video_opts {
float scaler_antiring[2]; float scaler_antiring[2];
float gamma; float gamma;
int srgb; int srgb;
int linear_scaling;
int fancy_downscaling; int fancy_downscaling;
int sigmoid_upscaling; int sigmoid_upscaling;
float sigmoid_center; float sigmoid_center;

View File

@ -508,6 +508,9 @@ void main() {
// Adapt and compand from the linear BT2020 source to the sRGB output // Adapt and compand from the linear BT2020 source to the sRGB output
color = srgb_compand(color); color = srgb_compand(color);
#endif #endif
#ifdef USE_INV_BT1886
color = pow(color, vec3(1.0/1.961));
#endif
#ifdef USE_DITHER #ifdef USE_DITHER
vec2 dither_pos = gl_FragCoord.xy / dither_size; vec2 dither_pos = gl_FragCoord.xy / dither_size;
#ifdef USE_TEMPORAL_DITHER #ifdef USE_TEMPORAL_DITHER