Skip to content

Instantly share code, notes, and snippets.

@bunkbail
Last active February 21, 2026 02:21
Show Gist options
  • Select an option

  • Save bunkbail/5cc0fd5e1d8196557b7c92af2b53dfe4 to your computer and use it in GitHub Desktop.

Select an option

Save bunkbail/5cc0fd5e1d8196557b7c92af2b53dfe4 to your computer and use it in GitHub Desktop.
CFL-Lite v1.2: A highly optimized Chroma From Luma Upscaler
// CFL-Lite v1.2 - A highly optimized Chroma From Luma Upscaler
// Author: bunkbail
// License: MIT
//
// An adaptive chroma upscaling shader that reconstructs high-resolution color
// information from high-resolution luma using local linear regression.
//
// Features:
// - Linear regression-based chroma prediction
// - Static ridge regularization optimized for SDR and HDR
// - Neighbor clamping for anti-ringing
// - R²-based confidence blending with bilinear fallback
// - Per-channel confidence for optimal prediction utilization
// - Bilinear-weighted regression for spatial consistency
// - Outlier-robust covariance for compression artifact immunity
// - Adaptive confidence floor based on local variance
// - Proper linearization for both SDR (x^2) and HDR (x^4)
// - Deferred chroma sampling for bandwidth optimization
// - Early exit for flat luma areas
//
// Usage: Place in your mpv shaders directory and load with:
// glsl-shaders="~~/shaders/cfl-lite.glsl"
//!HOOK CHROMA
//!BIND HOOKED
//!BIND LUMA
//!WIDTH LUMA.w
//!HEIGHT LUMA.h
//!WHEN CHROMA.w LUMA.w <
//!OFFSET ALIGN
//!DESC CFL-Lite v1.2
// ============================================================================
// FEATURE TOGGLES
// ============================================================================
// HDR Support
// 0 = SDR (Applies x^2 linearization for gamma 2.0 approximation)
// 1 = HDR (Applies x^4 linearization for PQ approximation)
// Should match FSR_HDR setting in FSR-Lite for consistent processing.
#ifndef CFL_HDR
#define CFL_HDR 0
#endif
// ============================================================================
// TUNABLE PARAMETERS
// ============================================================================
// Ridge regularization for linear regression
// Prevents division by zero when luma variance is near-zero.
// Scaled for weighted variance (range ~0 to 0.25 instead of ~0 to 1).
#define RIDGE_LAMBDA 2.5e-5
// Base confidence floor for R² correlation
// R² values below this are treated as "no meaningful correlation".
// Actual floor adapts based on local variance (see adaptive confidence).
#define CONFIDENCE_FLOOR 0.04
// Luma variance threshold for early exit
// Below this variance, the local area is considered flat and CFL is skipped.
// Scaled for weighted variance (range ~0 to 0.25 instead of ~0 to 1).
#define LUMA_VARIANCE_THRESHOLD 0.00025
// Epsilon for numerical safety
#define EPSILON 1.0e-12
// ============================================================================
// LINEARIZATION FUNCTIONS
// ============================================================================
#if CFL_HDR
// HDR: Fast approximation for PQ linearization (x^4)
// PQ has a steeper curve, x^4 is a reasonable approximation
vec4 ToLin4(vec4 v) { vec4 s = v * v; return s * s; }
vec2 ToLin2(vec2 v) { vec2 s = v * v; return s * s; }
float ToLin1(float v) { float s = v * v; return s * s; }
// HDR: Delinearization (sqrt(sqrt(x)))
vec2 ToGamma2(vec2 v) { return sqrt(sqrt(max(v, 0.0))); }
#else
// SDR: Fast approximation for Gamma 2.0 linearization (x^2)
// Standard SDR uses gamma 2.2-2.4, x^2 is close enough for regression
// Regression must be done in linear space for mathematically correct results
vec4 ToLin4(vec4 v) { return v * v; }
vec2 ToLin2(vec2 v) { return v * v; }
float ToLin1(float v) { return v * v; }
// SDR: Delinearization (sqrt(x))
vec2 ToGamma2(vec2 v) { return sqrt(max(v, 0.0)); }
#endif
// ============================================================================
// MAIN HOOK FUNCTION
// ============================================================================
vec4 hook() {
// ====================================================================
// SAMPLE COORDINATE CALCULATION
// ====================================================================
highp vec2 pp = HOOKED_pos * HOOKED_size - vec2(0.5);
highp vec2 fp = floor(pp);
pp -= fp;
// Bilinear weights for spatial blending
vec2 w1 = 1.0 - pp;
vec2 w2 = pp;
vec4 weights = vec4(w1.x * w1.y, w2.x * w1.y, w1.x * w2.y, w2.x * w2.y);
// ====================================================================
// DEFERRED SAMPLING: LUMA FIRST
// ====================================================================
// Sample luma at 2x2 neighbors (needed for variance check)
vec4 luma = vec4(
LUMA_texOff(vec2(0.0, 0.0)).x,
LUMA_texOff(vec2(1.0, 0.0)).x,
LUMA_texOff(vec2(0.0, 1.0)).x,
LUMA_texOff(vec2(1.0, 1.0)).x
);
// Linearize for correct regression math
luma = ToLin4(luma);
// Calculate weighted mean and variance
float lAvg = dot(luma, weights);
vec4 lDiff = luma - lAvg;
float lVar = dot(lDiff * lDiff, weights);
// ====================================================================
// EARLY EXIT FOR FLAT AREAS (saves 4 chroma fetches)
// ====================================================================
if (lVar < LUMA_VARIANCE_THRESHOLD) {
// Flat area: return simple bilinear chroma
vec2 cBilinear = ToLin2(HOOKED_tex(HOOKED_pos).xy);
return vec4(ToGamma2(cBilinear), 0.0, 1.0);
}
// ====================================================================
// CHROMA SAMPLING (only for non-flat areas)
// ====================================================================
// Sample chroma at 2x2 neighbors
vec2 tTL = HOOKED_texOff(vec2(0.0, 0.0)).xy;
vec2 tTR = HOOKED_texOff(vec2(1.0, 0.0)).xy;
vec2 tBL = HOOKED_texOff(vec2(0.0, 1.0)).xy;
vec2 tBR = HOOKED_texOff(vec2(1.0, 1.0)).xy;
vec4 chromaU = vec4(tTL.x, tTR.x, tBL.x, tBR.x);
vec4 chromaV = vec4(tTL.y, tTR.y, tBL.y, tBR.y);
// Linearize for correct regression math
chromaU = ToLin4(chromaU);
chromaV = ToLin4(chromaV);
vec2 tTL_lin = ToLin2(tTL);
vec2 tTR_lin = ToLin2(tTR);
vec2 tBL_lin = ToLin2(tBL);
vec2 tBR_lin = ToLin2(tBR);
// ====================================================================
// STATISTICAL ANALYSIS
// ====================================================================
// Bilinear-weighted means: this IS the bilinear interpolant
vec2 cAvg = vec2(dot(chromaU, weights), dot(chromaV, weights));
vec4 cDiffU = chromaU - cAvg.x;
vec4 cDiffV = chromaV - cAvg.y;
// Outlier-robust covariance via clamping
vec4 lDiffClamped = clamp(lDiff, -2.0 * sqrt(max(lVar, EPSILON)), 2.0 * sqrt(max(lVar, EPSILON)));
vec2 cov = vec2(
dot(lDiffClamped * weights, cDiffU),
dot(lDiffClamped * weights, cDiffV)
);
vec2 cVar = vec2(
dot(cDiffU * cDiffU, weights),
dot(cDiffV * cDiffV, weights)
);
// ====================================================================
// LINEAR REGRESSION WITH PER-CHANNEL ADAPTIVE SLOPE CLAMPING
// ====================================================================
vec2 alpha = cov / (lVar + RIDGE_LAMBDA);
// Optimized: single sqrt instead of sqrt/sqrt
vec2 maxSlope = max(vec2(1.0), sqrt(max(cVar, vec2(EPSILON)) / max(lVar, EPSILON)));
alpha = clamp(alpha, -maxSlope, maxSlope);
// High-res luma for prediction
float lHigh = ToLin1(LUMA_texOff(0.0).x);
vec2 cPred = cAvg + alpha * (lHigh - lAvg);
// ====================================================================
// ANTI-RINGING (NEIGHBOR CLAMPING)
// ====================================================================
vec2 cMin = min(min(tTL_lin, tTR_lin), min(tBL_lin, tBR_lin));
vec2 cMax = max(max(tTL_lin, tTR_lin), max(tBL_lin, tBR_lin));
cPred = clamp(cPred, cMin, cMax);
// ====================================================================
// CONFIDENCE CALCULATION
// ====================================================================
// Per-channel R² correlation
// Note: cov uses clamped lDiff while denominator uses unclamped lVar.
// This intentionally underestimates R² near outliers, causing conservative
// fallback to bilinear. This is safe behavior, not a bug.
vec2 denom = max(vec2(lVar) * cVar, vec2(EPSILON));
vec2 corrSq = clamp((cov * cov) / denom, 0.0, 1.0);
// Adaptive confidence floor: high variance = lower floor = trust CFL more
float adaptiveFloor = CONFIDENCE_FLOOR / (1.0 + lVar * 10.0);
vec2 conf = max(corrSq - adaptiveFloor, 0.0) / (1.0 - adaptiveFloor);
// Optimized: sqrt instead of pow(x, 0.7)
conf = sqrt(conf);
// ====================================================================
// FINAL OUTPUT
// ====================================================================
// Per-channel blending: conf=0 → bilinear (cAvg), conf=1 → CFL prediction
vec2 cFinal = mix(cAvg, cPred, conf);
cFinal = ToGamma2(cFinal);
return vec4(cFinal, 0.0, 1.0);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment