Skip to content

Commit

Permalink
shaders/colorspace: use perceptually linear pure BPC
Browse files Browse the repository at this point in the history
It's not that hard to convert to PQ and back in pure GLSL, so we might
as well do that for pure BPC. Produces significantly better results (no
clipping) than naive/linear black point stretching.
  • Loading branch information
haasn committed Feb 17, 2023
1 parent 88dce45 commit d1bacd8
Showing 1 changed file with 32 additions and 4 deletions.
36 changes: 32 additions & 4 deletions src/shaders/colorspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1366,10 +1366,38 @@ static void tone_map(pl_shader sh,

} else if (pure_bpc) {

// Pure black point compensation
const float scale = (dst_max - dst_min) / (src_max - src_min);
GLSL("#define tone_map(x) (%s * (x) + %s) \n",
SH_FLOAT(scale), SH_FLOAT(dst_min - scale * src_min));
const float pq_src_min = pl_hdr_rescale(PL_HDR_NORM, PL_HDR_PQ, src_min);
const float pq_src_max = pl_hdr_rescale(PL_HDR_NORM, PL_HDR_PQ, src_max);
const float pq_dst_min = pl_hdr_rescale(PL_HDR_NORM, PL_HDR_PQ, dst_min);

ident_t bpc = sh_fresh(sh, "bpc_pq");
GLSLH("float %s(float x) { \n"
// PQ OETF
" x *= %f; \n"
" x = pow(max(x, 0.0), %f); \n"
" x = (%f + %f * x) / (1.0 + %f * x); \n"
" x = pow(x, %f); \n"
// Stretch the black point
" x -= %s; \n"
" x *= %s; \n"
" x += %s; \n"
// PQ EOTF
" x = pow(max(x, 0.0), 1.0/%f); \n"
" x = max(x - %f, 0.0) / (%f - %f * x); \n"
" x = pow(x, 1.0 / %f); \n"
" x *= %f; \n"
" return x; \n"
"} \n",
bpc,
PL_COLOR_SDR_WHITE / 10000.0,
PQ_M1, PQ_C1, PQ_C2, PQ_C3, PQ_M2,
SH_FLOAT(pq_src_min),
SH_FLOAT((pq_src_max - pq_dst_min) / (pq_src_max - pq_src_min)),
SH_FLOAT(pq_dst_min),
PQ_M2, PQ_C1, PQ_C2, PQ_C3, PQ_M1,
10000.0 / PL_COLOR_SDR_WHITE);

GLSL("#define tone_map(x) (%s(x)) \n", bpc);

} else if (lut && dynamic_peak) {

Expand Down

0 comments on commit d1bacd8

Please sign in to comment.