diff options
Diffstat (limited to 'video/out/gpu/video_shaders.c')
-rw-r--r-- | video/out/gpu/video_shaders.c | 128 |
1 files changed, 65 insertions, 63 deletions
diff --git a/video/out/gpu/video_shaders.c b/video/out/gpu/video_shaders.c index 6c0e8a8..e202818 100644 --- a/video/out/gpu/video_shaders.c +++ b/video/out/gpu/video_shaders.c @@ -17,6 +17,8 @@ #include <math.h> +#include <libplacebo/colorspace.h> + #include "video_shaders.h" #include "video.h" @@ -252,7 +254,7 @@ void pass_compute_polar(struct gl_shader_cache *sc, struct scaler *scaler, static void bicubic_calcweights(struct gl_shader_cache *sc, const char *t, const char *s) { // Explanation of how bicubic scaling with only 4 texel fetches is done: - // http://www.mate.tue.nl/mate/pdfs/10318.pdf + // <https://web.archive.org/web/20180720154854/http://www.mate.tue.nl/mate/pdfs/10318.pdf> // 'Efficient GPU-Based Texture Interpolation using Uniform B-Splines' // Explanation why this algorithm normally always blurs, even with unit // scaling: @@ -337,10 +339,10 @@ static const float SLOG_A = 0.432699, // // These functions always output to a normalized scale of [0,1], for // convenience of the video.c code that calls it. To get the values in an -// absolute scale, multiply the result by `mp_trc_nom_peak(trc)` -void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) +// absolute scale, multiply the result by `pl_color_transfer_nominal_peak(trc)` +void pass_linearize(struct gl_shader_cache *sc, enum pl_color_transfer trc) { - if (trc == MP_CSP_TRC_LINEAR) + if (trc == PL_COLOR_TRC_LINEAR) return; GLSLF("// linearize\n"); @@ -353,40 +355,40 @@ void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);) switch (trc) { - case MP_CSP_TRC_SRGB: + case PL_COLOR_TRC_SRGB: GLSLF("color.rgb = mix(color.rgb * vec3(1.0/12.92), \n" " pow((color.rgb + vec3(0.055))/vec3(1.055), vec3(2.4)), \n" " %s(lessThan(vec3(0.04045), color.rgb))); \n", gl_sc_bvec(sc, 3)); break; - case MP_CSP_TRC_BT_1886: + case PL_COLOR_TRC_BT_1886: GLSL(color.rgb = pow(color.rgb, vec3(2.4));) break; - case MP_CSP_TRC_GAMMA18: + case PL_COLOR_TRC_GAMMA18: GLSL(color.rgb = pow(color.rgb, vec3(1.8));) break; - case MP_CSP_TRC_GAMMA20: + case PL_COLOR_TRC_GAMMA20: GLSL(color.rgb = pow(color.rgb, vec3(2.0));) break; - case MP_CSP_TRC_GAMMA22: + case PL_COLOR_TRC_GAMMA22: GLSL(color.rgb = pow(color.rgb, vec3(2.2));) break; - case MP_CSP_TRC_GAMMA24: + case PL_COLOR_TRC_GAMMA24: GLSL(color.rgb = pow(color.rgb, vec3(2.4));) break; - case MP_CSP_TRC_GAMMA26: + case PL_COLOR_TRC_GAMMA26: GLSL(color.rgb = pow(color.rgb, vec3(2.6));) break; - case MP_CSP_TRC_GAMMA28: + case PL_COLOR_TRC_GAMMA28: GLSL(color.rgb = pow(color.rgb, vec3(2.8));) break; - case MP_CSP_TRC_PRO_PHOTO: + case PL_COLOR_TRC_PRO_PHOTO: GLSLF("color.rgb = mix(color.rgb * vec3(1.0/16.0), \n" " pow(color.rgb, vec3(1.8)), \n" " %s(lessThan(vec3(0.03125), color.rgb))); \n", gl_sc_bvec(sc, 3)); break; - case MP_CSP_TRC_PQ: + case PL_COLOR_TRC_PQ: GLSLF("color.rgb = pow(color.rgb, vec3(1.0/%f));\n", PQ_M2); GLSLF("color.rgb = max(color.rgb - vec3(%f), vec3(0.0)) \n" " / (vec3(%f) - vec3(%f) * color.rgb);\n", @@ -396,33 +398,33 @@ void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) // MP_REF_WHITE instead, so rescale GLSLF("color.rgb *= vec3(%f);\n", 10000 / MP_REF_WHITE); break; - case MP_CSP_TRC_HLG: + case PL_COLOR_TRC_HLG: GLSLF("color.rgb = mix(vec3(4.0) * color.rgb * color.rgb,\n" " exp((color.rgb - vec3(%f)) * vec3(1.0/%f)) + vec3(%f),\n" " %s(lessThan(vec3(0.5), color.rgb)));\n", HLG_C, HLG_A, HLG_B, gl_sc_bvec(sc, 3)); GLSLF("color.rgb *= vec3(1.0/%f);\n", MP_REF_WHITE_HLG); break; - case MP_CSP_TRC_V_LOG: + case PL_COLOR_TRC_V_LOG: GLSLF("color.rgb = mix((color.rgb - vec3(0.125)) * vec3(1.0/5.6), \n" " pow(vec3(10.0), (color.rgb - vec3(%f)) * vec3(1.0/%f)) \n" " - vec3(%f), \n" " %s(lessThanEqual(vec3(0.181), color.rgb))); \n", VLOG_D, VLOG_C, VLOG_B, gl_sc_bvec(sc, 3)); break; - case MP_CSP_TRC_S_LOG1: + case PL_COLOR_TRC_S_LOG1: GLSLF("color.rgb = pow(vec3(10.0), (color.rgb - vec3(%f)) * vec3(1.0/%f))\n" " - vec3(%f);\n", SLOG_C, SLOG_A, SLOG_B); break; - case MP_CSP_TRC_S_LOG2: + case PL_COLOR_TRC_S_LOG2: GLSLF("color.rgb = mix((color.rgb - vec3(%f)) * vec3(1.0/%f), \n" " (pow(vec3(10.0), (color.rgb - vec3(%f)) * vec3(1.0/%f)) \n" " - vec3(%f)) * vec3(1.0/%f), \n" " %s(lessThanEqual(vec3(%f), color.rgb))); \n", SLOG_Q, SLOG_P, SLOG_C, SLOG_A, SLOG_B, SLOG_K2, gl_sc_bvec(sc, 3), SLOG_Q); break; - case MP_CSP_TRC_ST428: + case PL_COLOR_TRC_ST428: GLSL(color.rgb = vec3(52.37/48.0) * pow(color.rgb, vec3(2.6));); break; default: @@ -430,7 +432,7 @@ void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) } // Rescale to prevent clipping on non-float textures - GLSLF("color.rgb *= vec3(1.0/%f);\n", mp_trc_nom_peak(trc)); + GLSLF("color.rgb *= vec3(1.0/%f);\n", pl_color_transfer_nominal_peak(trc)); } // Delinearize (compress), given a TRC as output. This corresponds to the @@ -438,51 +440,51 @@ void pass_linearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) // reference monitor. // // Like pass_linearize, this functions ingests values on an normalized scale -void pass_delinearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) +void pass_delinearize(struct gl_shader_cache *sc, enum pl_color_transfer trc) { - if (trc == MP_CSP_TRC_LINEAR) + if (trc == PL_COLOR_TRC_LINEAR) return; GLSLF("// delinearize\n"); GLSL(color.rgb = clamp(color.rgb, 0.0, 1.0);) - GLSLF("color.rgb *= vec3(%f);\n", mp_trc_nom_peak(trc)); + GLSLF("color.rgb *= vec3(%f);\n", pl_color_transfer_nominal_peak(trc)); switch (trc) { - case MP_CSP_TRC_SRGB: + case PL_COLOR_TRC_SRGB: GLSLF("color.rgb = mix(color.rgb * vec3(12.92), \n" " vec3(1.055) * pow(color.rgb, vec3(1.0/2.4)) \n" " - vec3(0.055), \n" " %s(lessThanEqual(vec3(0.0031308), color.rgb))); \n", gl_sc_bvec(sc, 3)); break; - case MP_CSP_TRC_BT_1886: + case PL_COLOR_TRC_BT_1886: GLSL(color.rgb = pow(color.rgb, vec3(1.0/2.4));) break; - case MP_CSP_TRC_GAMMA18: + case PL_COLOR_TRC_GAMMA18: GLSL(color.rgb = pow(color.rgb, vec3(1.0/1.8));) break; - case MP_CSP_TRC_GAMMA20: + case PL_COLOR_TRC_GAMMA20: GLSL(color.rgb = pow(color.rgb, vec3(1.0/2.0));) break; - case MP_CSP_TRC_GAMMA22: + case PL_COLOR_TRC_GAMMA22: GLSL(color.rgb = pow(color.rgb, vec3(1.0/2.2));) break; - case MP_CSP_TRC_GAMMA24: + case PL_COLOR_TRC_GAMMA24: GLSL(color.rgb = pow(color.rgb, vec3(1.0/2.4));) break; - case MP_CSP_TRC_GAMMA26: + case PL_COLOR_TRC_GAMMA26: GLSL(color.rgb = pow(color.rgb, vec3(1.0/2.6));) break; - case MP_CSP_TRC_GAMMA28: + case PL_COLOR_TRC_GAMMA28: GLSL(color.rgb = pow(color.rgb, vec3(1.0/2.8));) break; - case MP_CSP_TRC_PRO_PHOTO: + case PL_COLOR_TRC_PRO_PHOTO: GLSLF("color.rgb = mix(color.rgb * vec3(16.0), \n" " pow(color.rgb, vec3(1.0/1.8)), \n" " %s(lessThanEqual(vec3(0.001953), color.rgb))); \n", gl_sc_bvec(sc, 3)); break; - case MP_CSP_TRC_PQ: + case PL_COLOR_TRC_PQ: GLSLF("color.rgb *= vec3(1.0/%f);\n", 10000 / MP_REF_WHITE); GLSLF("color.rgb = pow(color.rgb, vec3(%f));\n", PQ_M1); GLSLF("color.rgb = (vec3(%f) + vec3(%f) * color.rgb) \n" @@ -490,32 +492,32 @@ void pass_delinearize(struct gl_shader_cache *sc, enum mp_csp_trc trc) PQ_C1, PQ_C2, PQ_C3); GLSLF("color.rgb = pow(color.rgb, vec3(%f));\n", PQ_M2); break; - case MP_CSP_TRC_HLG: + case PL_COLOR_TRC_HLG: GLSLF("color.rgb *= vec3(%f);\n", MP_REF_WHITE_HLG); GLSLF("color.rgb = mix(vec3(0.5) * sqrt(color.rgb),\n" " vec3(%f) * log(color.rgb - vec3(%f)) + vec3(%f),\n" " %s(lessThan(vec3(1.0), color.rgb)));\n", HLG_A, HLG_B, HLG_C, gl_sc_bvec(sc, 3)); break; - case MP_CSP_TRC_V_LOG: + case PL_COLOR_TRC_V_LOG: GLSLF("color.rgb = mix(vec3(5.6) * color.rgb + vec3(0.125), \n" " vec3(%f) * log(color.rgb + vec3(%f)) \n" " + vec3(%f), \n" " %s(lessThanEqual(vec3(0.01), color.rgb))); \n", VLOG_C / M_LN10, VLOG_B, VLOG_D, gl_sc_bvec(sc, 3)); break; - case MP_CSP_TRC_S_LOG1: + case PL_COLOR_TRC_S_LOG1: GLSLF("color.rgb = vec3(%f) * log(color.rgb + vec3(%f)) + vec3(%f);\n", SLOG_A / M_LN10, SLOG_B, SLOG_C); break; - case MP_CSP_TRC_S_LOG2: + case PL_COLOR_TRC_S_LOG2: GLSLF("color.rgb = mix(vec3(%f) * color.rgb + vec3(%f), \n" " vec3(%f) * log(vec3(%f) * color.rgb + vec3(%f)) \n" " + vec3(%f), \n" " %s(lessThanEqual(vec3(0.0), color.rgb))); \n", SLOG_P, SLOG_Q, SLOG_A / M_LN10, SLOG_K2, SLOG_B, SLOG_C, gl_sc_bvec(sc, 3)); break; - case MP_CSP_TRC_ST428: + case PL_COLOR_TRC_ST428: GLSL(color.rgb = pow(color.rgb * vec3(48.0/52.37), vec3(1.0/2.6));); break; default: @@ -834,42 +836,42 @@ static void pass_tone_map(struct gl_shader_cache *sc, // the caller to have already bound the appropriate SSBO and set up the compute // shader metadata void pass_color_map(struct gl_shader_cache *sc, bool is_linear, - struct mp_colorspace src, struct mp_colorspace dst, + struct pl_color_space src, struct pl_color_space dst, + enum mp_csp_light src_light, enum mp_csp_light dst_light, const struct gl_tone_map_opts *opts) { GLSLF("// color mapping\n"); // Some operations need access to the video's luma coefficients, so make // them available - float rgb2xyz[3][3]; - mp_get_rgb2xyz_matrix(mp_get_csp_primaries(src.primaries), rgb2xyz); - gl_sc_uniform_vec3(sc, "src_luma", rgb2xyz[1]); - mp_get_rgb2xyz_matrix(mp_get_csp_primaries(dst.primaries), rgb2xyz); - gl_sc_uniform_vec3(sc, "dst_luma", rgb2xyz[1]); - - bool need_ootf = src.light != dst.light; - if (src.light == MP_CSP_LIGHT_SCENE_HLG && src.hdr.max_luma != dst.hdr.max_luma) + pl_matrix3x3 rgb2xyz = pl_get_rgb2xyz_matrix(pl_raw_primaries_get(src.primaries)); + gl_sc_uniform_vec3(sc, "src_luma", rgb2xyz.m[1]); + rgb2xyz = pl_get_rgb2xyz_matrix(pl_raw_primaries_get(dst.primaries)); + gl_sc_uniform_vec3(sc, "dst_luma", rgb2xyz.m[1]); + + bool need_ootf = src_light != dst_light; + if (src_light == MP_CSP_LIGHT_SCENE_HLG && src.hdr.max_luma != dst.hdr.max_luma) need_ootf = true; // All operations from here on require linear light as a starting point, - // so we linearize even if src.gamma == dst.gamma when one of the other + // so we linearize even if src.gamma == dst.transfer when one of the other // operations needs it - bool need_linear = src.gamma != dst.gamma || + bool need_linear = src.transfer != dst.transfer || src.primaries != dst.primaries || src.hdr.max_luma != dst.hdr.max_luma || need_ootf; if (need_linear && !is_linear) { // We also pull it up so that 1.0 is the reference white - pass_linearize(sc, src.gamma); + pass_linearize(sc, src.transfer); is_linear = true; } // Pre-scale the incoming values into an absolute scale - GLSLF("color.rgb *= vec3(%f);\n", mp_trc_nom_peak(src.gamma)); + GLSLF("color.rgb *= vec3(%f);\n", pl_color_transfer_nominal_peak(src.transfer)); if (need_ootf) - pass_ootf(sc, src.light, src.hdr.max_luma / MP_REF_WHITE); + pass_ootf(sc, src_light, src.hdr.max_luma / MP_REF_WHITE); // Tone map to prevent clipping due to excessive brightness if (src.hdr.max_luma > dst.hdr.max_luma) { @@ -879,11 +881,11 @@ void pass_color_map(struct gl_shader_cache *sc, bool is_linear, // Adapt to the right colorspace if necessary if (src.primaries != dst.primaries) { - struct mp_csp_primaries csp_src = mp_get_csp_primaries(src.primaries), - csp_dst = mp_get_csp_primaries(dst.primaries); - float m[3][3] = {{0}}; - mp_get_cms_matrix(csp_src, csp_dst, MP_INTENT_RELATIVE_COLORIMETRIC, m); - gl_sc_uniform_mat3(sc, "cms_matrix", true, &m[0][0]); + const struct pl_raw_primaries *csp_src = pl_raw_primaries_get(src.primaries), + *csp_dst = pl_raw_primaries_get(dst.primaries); + pl_matrix3x3 m = pl_get_color_mapping_matrix(csp_src, csp_dst, + PL_INTENT_RELATIVE_COLORIMETRIC); + gl_sc_uniform_mat3(sc, "cms_matrix", true, &m.m[0][0]); GLSL(color.rgb = cms_matrix * color.rgb;) if (!opts->gamut_mode || opts->gamut_mode == GAMUT_DESATURATE) { @@ -900,14 +902,14 @@ void pass_color_map(struct gl_shader_cache *sc, bool is_linear, } if (need_ootf) - pass_inverse_ootf(sc, dst.light, dst.hdr.max_luma / MP_REF_WHITE); + pass_inverse_ootf(sc, dst_light, dst.hdr.max_luma / MP_REF_WHITE); // Post-scale the outgoing values from absolute scale to normalized. // For SDR, we normalize to the chosen signal peak. For HDR, we normalize // to the encoding range of the transfer function. float dst_range = dst.hdr.max_luma / MP_REF_WHITE; - if (mp_trc_is_hdr(dst.gamma)) - dst_range = mp_trc_nom_peak(dst.gamma); + if (pl_color_space_is_hdr(&dst)) + dst_range = pl_color_transfer_nominal_peak(dst.transfer); GLSLF("color.rgb *= vec3(%f);\n", 1.0 / dst_range); @@ -919,7 +921,7 @@ void pass_color_map(struct gl_shader_cache *sc, bool is_linear, } if (is_linear) - pass_delinearize(sc, dst.gamma); + pass_delinearize(sc, dst.transfer); } // Wide usage friendly PRNG, shamelessly stolen from a GLSL tricks forum post. @@ -964,7 +966,7 @@ const struct m_sub_options deband_conf = { // Stochastically sample a debanded result from a hooked texture. void pass_sample_deband(struct gl_shader_cache *sc, struct deband_opts *opts, - AVLFG *lfg, enum mp_csp_trc trc) + AVLFG *lfg, enum pl_color_transfer trc) { // Initialize the PRNG GLSLF("{\n"); @@ -1008,7 +1010,7 @@ void pass_sample_deband(struct gl_shader_cache *sc, struct deband_opts *opts, GLSL(noise.z = rand(h); h = permute(h);) // Noise is scaled to the signal level to prevent extreme noise for HDR - float gain = opts->grain/8192.0 / mp_trc_nom_peak(trc); + float gain = opts->grain/8192.0 / pl_color_transfer_nominal_peak(trc); GLSLF("color.xyz += %f * (noise - vec3(0.5));\n", gain); GLSLF("}\n"); } |