Skip to content

Commit

Permalink
shaders/colorspace: add tone mapping visualization
Browse files Browse the repository at this point in the history
Infinitely useful during development, no need to constantly NIH this
patch or re-invent it ad-hoc.
  • Loading branch information
haasn committed Feb 17, 2023
1 parent 373afb7 commit 258cf93
Show file tree
Hide file tree
Showing 5 changed files with 100 additions and 0 deletions.
1 change: 1 addition & 0 deletions demos/plplay.c
Original file line number Diff line number Diff line change
Expand Up @@ -1085,6 +1085,7 @@ static void update_settings(struct plplay *p)
nk_property_float(nk, "Crosstalk", 0.0, &cpar->tone_mapping_crosstalk, 0.30, 0.01, 0.001);
nk_checkbox_label(nk, "Inverse tone mapping", &cpar->inverse_tone_mapping);
nk_checkbox_label(nk, "Force full LUT", &cpar->force_tone_mapping_lut);
nk_checkbox_label(nk, "Visualize LUT", &cpar->visualize_lut);

nk_layout_row_dynamic(nk, 50, 1);
if (ui_widget_hover(nk, "Drop .cube file here...") && dropped_file) {
Expand Down
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ project('libplacebo', ['c', 'cpp'],
5,
# API version
{
'247': 'add pl_color_map_params.visualize_lut',
'246': 'add `pl_tone_map_st2094_10` and `pl_tone_map_st2094_40`',
'245': 'add `pl_tone_map_params.hdr`',
'244': 'add `pl_map_hdr_metadata`',
Expand Down
3 changes: 3 additions & 0 deletions src/include/libplacebo/shaders/colorspace.h
Original file line number Diff line number Diff line change
Expand Up @@ -284,6 +284,9 @@ struct pl_color_map_params {
// faster pure GLSL replacements (e.g. clip).
bool force_tone_mapping_lut;

// Visualize the tone-mapping curve / LUT. (PQ-PQ graph)
bool visualize_lut;

// --- Deprecated fields
enum pl_tone_mapping_algorithm tone_mapping_algo PL_DEPRECATED;
float desaturation_strength PL_DEPRECATED;
Expand Down
94 changes: 94 additions & 0 deletions src/shaders/colorspace.c
Original file line number Diff line number Diff line change
Expand Up @@ -1246,6 +1246,95 @@ static void fill_lut(void *data, const struct sh_lut_params *params)
}
}

static inline void visualize_tone_map(pl_shader sh, ident_t fun,
float xmin, float xmax,
float ymin, float ymax,
bool dynamic_peak)
{
ident_t pos = sh_attr_vec2(sh, "screenpos", &(struct pl_rect2df) {
.x0 = 0.0f, .x1 = 1.0f,
.y0 = 1.0f, .y1 = 0.0f,
});

GLSL("// Visualize tone mapping \n"
"{ \n"
"float xmin = %s; \n"
"float xmax = %s; \n"
"float ymin = %s; \n"
"float ymax = %s; \n",
SH_FLOAT(pl_hdr_rescale(PL_HDR_NORM, PL_HDR_PQ, xmin)),
SH_FLOAT(pl_hdr_rescale(PL_HDR_NORM, PL_HDR_PQ, xmax)),
SH_FLOAT(pl_hdr_rescale(PL_HDR_NORM, PL_HDR_PQ, ymin)),
SH_FLOAT(pl_hdr_rescale(PL_HDR_NORM, PL_HDR_PQ, ymax)));

if (dynamic_peak) {
GLSL("vec2 avg = average.xy; \n"
"avg *= vec2(%f); \n"
"avg = pow(max(avg, 0.0), vec2(%f)); \n"
"avg = (vec2(%f) + vec2(%f) * avg) \n"
" / (vec2(1.0) + vec2(%f) * avg); \n"
"avg = pow(avg, vec2(%f)); \n"
"xmax = avg.y; \n",
PL_COLOR_SDR_WHITE / 10000.0,
PQ_M1, PQ_C1, PQ_C2, PQ_C3, PQ_M2);
}

GLSL("vec2 pos = %s; \n"
"vec3 viz = color.rgb; \n"
// PQ EOTF
"float vv = pos.x; \n"
"vv = pow(max(vv, 0.0), 1.0/%f); \n"
"vv = max(vv - %f, 0.0) / (%f - %f * vv); \n"
"vv = pow(vv, 1.0 / %f); \n"
"vv *= %f; \n"
// Apply tone-mapping function
"vv = %s(vv); \n"
// PQ OETF
"vv *= %f; \n"
"vv = pow(max(vv, 0.0), %f); \n"
"vv = (%f + %f * vv) / (1.0 + %f * vv); \n"
"vv = pow(vv, %f); \n"
// Color based on region
"if (pos.x < xmin || pos.x > xmax) { \n" // outside source
" viz = vec3(0.0); \n"
"} else if (pos.y < ymin || pos.y > ymax) {\n" // outside target
" if (pos.y < xmin || pos.y > xmax) { \n" // and also source
" viz = vec3(0.1, 0.1, 0.5); \n"
" } else { \n"
" viz = vec3(0.4, 0.1, 0.1); \n" // but inside source
" } \n"
"} else { \n" // inside domain
" if (abs(pos.x - pos.y) < 1e-3) { \n" // main diagonal
" viz = vec3(0.2); \n"
" } else if (pos.y < vv) { \n" // inside function
" viz = vec3(0.3, 1.0, 0.1); \n"
" if (vv > pos.x && pos.y > pos.x) \n" // output brighter than input
" viz.r = 0.7; \n"
" } else { \n" // outside function
" if (vv < pos.x && pos.y < pos.x) \n" // output darker than input
" viz = vec3(0.0, 0.05, 0.1); \n"
" } \n"
" if (pos.y > xmax) { \n" // inverse tone-mapping region
" vec3 hi = vec3(0.2, 0.5, 0.8); \n"
" viz = mix(viz, hi, 0.5); \n"
" } \n",
pos,
PQ_M2, PQ_C1, PQ_C2, PQ_C3, PQ_M1,
10000.0 / PL_COLOR_SDR_WHITE,
fun,
PL_COLOR_SDR_WHITE / 10000.0,
PQ_M1, PQ_C1, PQ_C2, PQ_C3, PQ_M2);

if (dynamic_peak) {
GLSL(" if (abs(pos.x - avg.x) < 1e-3) \n" // source avg brightness
" viz = vec3(0.5); \n");
}

GLSL("} \n"
"color.rgb = mix(color.rgb, viz, 0.5); \n"
"} \n");
}

static void tone_map(pl_shader sh,
const struct pl_color_space *src,
const struct pl_color_space *dst,
Expand Down Expand Up @@ -1585,6 +1674,11 @@ static void tone_map(pl_shader sh,
"color.rgb = (color.rgb - vec3(ct)) / ct_scale; \n",
ct);

if (params->visualize_lut) {
visualize_tone_map(sh, "tone_map", src_min, src_max, dst_min, dst_max,
dynamic_peak);
}

GLSL("#undef tone_map \n");
}

Expand Down
1 change: 1 addition & 0 deletions src/tests/gpu_tests.h
Original file line number Diff line number Diff line change
Expand Up @@ -1121,6 +1121,7 @@ static void pl_render_tests(pl_gpu gpu)
image.color = pl_color_space_hdr10;
TEST_PARAMS(color_map, tone_mapping_mode, PL_TONE_MAP_MODE_COUNT - 1);
TEST_PARAMS(color_map, gamut_mode, PL_GAMUT_MODE_COUNT - 1);
TEST_PARAMS(color_map, visualize_lut, true);

// Test inverse tone-mapping and pure BPC
image.color.hdr.max_luma = 1000;
Expand Down

0 comments on commit 258cf93

Please sign in to comment.