mpv-player / mpv

🎥 Command line video player
https://mpv.io
Other
28.02k stars 2.88k forks source link

Anime4K_Clamp_Highlights.glsl causes darker colors when upscaling with gpu-next #14943

Open guidocella opened 1 day ago

guidocella commented 1 day ago

mpv Information

mpv v0.39.0-26-gc3d9243a3e Copyright © 2000-2024 mpv/MPlayer/mplayer2 projects
 built on Sep 28 2024 16:19:34
libplacebo version: v7.349.0 (v7.349.0-13-ga018ab04-dirty)
FFmpeg version: n7.0.2
FFmpeg library versions:
   libavcodec      61.3.100
   libavdevice     61.1.100
   libavfilter     10.1.100
   libavformat     61.1.100
   libavutil       59.8.100
   libswresample   5.1.100
   libswscale      8.1.100

Important Information

- Platform version: Latest Arch Linux
- GPU model, driver and version: can be reproduced on both AMD+Mesa and Nvidia proprietary drivers

Reproduction Steps

Download https://raw.githubusercontent.com/bloc97/Anime4K/7684e9586f8dcc738af08a1cdceb024cc184f426/glsl/Restore/Anime4K_Clamp_Highlights.glsl mpv --no-config --vo=gpu-next --glsl-shaders=Anime4K_Clamp_Highlights.glsl with any image or video Upscale the image or video

Expected Behavior

Colors stay the same

Actual Behavior

Colors become darker. In some images they even blend with the desktop wallpaper if the platform supports background transparency. This issue doesn't occur on vo_gpu or if upscaling with a shader.

Possibly related to https://github.com/mpv-player/mpv/issues/9524

Log File

mpv.log

Sample Files

Original screenshot: screenshot

Upscaled with no shader: good

Upscaled with Anime4K_Clamp_Highlights.glsl: bad

I carefully read all instruction and confirm that I did the following:

guidocella commented 1 day ago

--linear-downscaling=no prevents the change of colors.

The wallpaper blending (e.g. with mpv --glsl-shaders=Anime4K_Clamp_Highlights.glsl --vo=gpu-next --video-unscaled --background-color=0/0 https://0x0.st/XgNQ.jpg) is fixed by https://github.com/mpv-player/mpv/issues/9524#issuecomment-980260406, but even with that diff and disabling linear downscaling colors of images that would blend are much darker.

kasper93 commented 1 day ago

This is probably effect of bt.1886 implementation in libplacebo

        const float lb = powf(csp_min, 1/2.4f);
        const float lw = powf(csp_max, 1/2.4f);
        const float a = powf(lw - lb, 2.4f);
        const float b = lb / (lw - lb);
        GLSL("color.rgb = "$" * pow(color.rgb + vec3("$"), vec3(2.4)); \n",
             SH_FLOAT(a), SH_FLOAT(b));
[   0.092][d][vo/gpu-next/libplacebo] [ 72] const float _8002 = float(0.0595848374068737); 
[   0.092][d][vo/gpu-next/libplacebo] [ 73] const float _8003 = float(0.8703105449676514); 
[   0.092][d][vo/gpu-next/libplacebo] [ 74] vec4 _8001(vec4 color) {
[   0.092][d][vo/gpu-next/libplacebo] [ 75] // pl_shader_linearize           
[   0.092][d][vo/gpu-next/libplacebo] [ 76] color.rgb = max(color.rgb, 0.0); 
[   0.092][d][vo/gpu-next/libplacebo] [ 77] color.rgb = _8003 * pow(color.rgb + vec3(_8002), vec3(2.4)); 
[   0.092][d][vo/gpu-next/libplacebo] [ 78] return color;
[   0.092][d][vo/gpu-next/libplacebo] [ 79] }

and

[   0.092][d][vo/gpu-next/libplacebo] [ 82] const float _4002 = float(0.0595848374068737); 
[   0.092][d][vo/gpu-next/libplacebo] [ 83] const float _4003 = float(1.149015188217163); 
[   0.092][d][vo/gpu-next/libplacebo] [ 84] vec4 _4001(vec4 color) {
[   0.092][d][vo/gpu-next/libplacebo] [ 85] // pl_shader_delinearize 
[   0.092][d][vo/gpu-next/libplacebo] [ 86] color.rgb = max(color.rgb, 0.0); 
[   0.092][d][vo/gpu-next/libplacebo] [ 87] color.rgb = pow(_4003 * color.rgb, vec3(1.0/2.4)) - vec3(_4002); 
[   0.092][d][vo/gpu-next/libplacebo] [ 88] return color;
[   0.092][d][vo/gpu-next/libplacebo] [ 89] }
norinoriko commented 1 day ago

--linear-downscaling=no prevents the change of colors.

linear-downscaling=no is a red herring I'm pretty sure, no? AFAIK, there's a behavioral quirk with libplacebo where this option controls all colorspace linearization, including the linearization that occurs before sigmoidal resampling. I don't remember if this was ever fixed or not. You just need to disable --sigmoid-upscaling to not crush the highlights.

Here's how the image looks like with --sigmoid-slope=11.5

mpv-shot0001

kasper93 commented 1 day ago

there's a behavioral quirk with libplacebo where this option controls all colorspace linearization, including the linearization that occurs before sigmoidal resampling. I don't remember if this was ever fixed or not.

No, it was not. linear-downscaling controls everything.

Here's how the image looks like with --sigmoid-slope=11.5

Yeah, but vo_gpu does the same. So not sure what's your point exactly?

Anyway, I was fixing something else, and made a fix for libplacebo https://code.videolan.org/videolan/libplacebo/-/merge_requests/676 might affect behavior here too, if you want to test, for me it doesn't affects this case.

linear-downscaling=no is a red herring I'm pretty sure, no?

Well, the difference in brightness is introduced by bt.1886 scaling in linearization, I don't believe it is sigmoid itself that makes different to vo_gpu.

guidocella commented 1 day ago

Anyway, I was fixing something else, and made a fix for libplacebo https://code.videolan.org/videolan/libplacebo/-/merge_requests/676 might affect behavior here too, if you want to test, for me it doesn't affects this case.

There is no difference with it.

norinoriko commented 1 day ago

So not sure what's your point exactly?

I dunno I thought the image looked cool. B) <--(clueless)

Well, the difference in brightness is introduced by bt.1886 scaling in linearization, I don't believe it is sigmoid itself that makes different to vo_gpu.

I think you're right. gpu and gpu-next look identical if I use --target-contrast=inf.

mightyhuhn commented 1 day ago

This is probably effect of bt.1886 implementation in libplacebo

        const float lb = powf(csp_min, 1/2.4f);
        const float lw = powf(csp_max, 1/2.4f);
        const float a = powf(lw - lb, 2.4f);
        const float b = lb / (lw - lb);
        GLSL("color.rgb = "$" * pow(color.rgb + vec3("$"), vec3(2.4)); \n",
             SH_FLOAT(a), SH_FLOAT(b));
[   0.092][d][vo/gpu-next/libplacebo] [ 72] const float _8002 = float(0.0595848374068737); 
[   0.092][d][vo/gpu-next/libplacebo] [ 73] const float _8003 = float(0.8703105449676514); 
[   0.092][d][vo/gpu-next/libplacebo] [ 74] vec4 _8001(vec4 color) {
[   0.092][d][vo/gpu-next/libplacebo] [ 75] // pl_shader_linearize           
[   0.092][d][vo/gpu-next/libplacebo] [ 76] color.rgb = max(color.rgb, 0.0); 
[   0.092][d][vo/gpu-next/libplacebo] [ 77] color.rgb = _8003 * pow(color.rgb + vec3(_8002), vec3(2.4)); 
[   0.092][d][vo/gpu-next/libplacebo] [ 78] return color;
[   0.092][d][vo/gpu-next/libplacebo] [ 79] }

and

[   0.092][d][vo/gpu-next/libplacebo] [ 82] const float _4002 = float(0.0595848374068737); 
[   0.092][d][vo/gpu-next/libplacebo] [ 83] const float _4003 = float(1.149015188217163); 
[   0.092][d][vo/gpu-next/libplacebo] [ 84] vec4 _4001(vec4 color) {
[   0.092][d][vo/gpu-next/libplacebo] [ 85] // pl_shader_delinearize 
[   0.092][d][vo/gpu-next/libplacebo] [ 86] color.rgb = max(color.rgb, 0.0); 
[   0.092][d][vo/gpu-next/libplacebo] [ 87] color.rgb = pow(_4003 * color.rgb, vec3(1.0/2.4)) - vec3(_4002); 
[   0.092][d][vo/gpu-next/libplacebo] [ 88] return color;
[   0.092][d][vo/gpu-next/libplacebo] [ 89] }

is the result accurate with just pow(source, 2.4) processing and pow(source, 1/2.4)?

isn't const float gamma_light = float(1.0/2.4) faster?