Skip to content

Commit

Permalink
renderer: implement new peak detection
Browse files Browse the repository at this point in the history
This also allows us to finally separate peak detection from color
management. The current place in the code actually has almost no
drawbacks, since it's effectively free unless FBOs are disabled.

One annoying consequence is that this means we will now always perform
peak detection at the source resolution, even if the display is smaller.
In the relatively common case of 4K video on 1080p displays, this is a
performance regression. To fix it, we could try investigating whether to
do the analysis after up/downscaling, but then we have more special
cases to think about, so I think I'll live with the status quo for now.
Peak detection isn't the end of the world even at 4K.

Closes #40.
  • Loading branch information
haasn committed Jan 5, 2019
1 parent 893ba13 commit 10670ff
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 21 deletions.
2 changes: 1 addition & 1 deletion meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ project('libplacebo', ['c', 'cpp'],
license: 'LGPL2.1+',
default_options: ['c_std=c99'],
meson_version: '>=0.47',
version: '1.12.0',
version: '1.13.0',
)

# Version number
Expand Down
11 changes: 11 additions & 0 deletions src/include/libplacebo/renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,11 @@ struct pl_render_params {
// desaturation, etc. If NULL, defaults to &pl_color_adjustment_neutral.
const struct pl_color_adjustment *color_adjustment;

// Configures the settings used to detect the peak of the source content,
// for HDR sources. Has no effect on SDR content. If NULL, peak detection
// is disabled.
const struct pl_peak_detect_params *peak_detect_params;

// Configures the settings used to tone map from HDR to SDR, or from higher
// gamut to standard gamut content. If NULL, defaults to
// `&pl_color_map_default_params`.
Expand Down Expand Up @@ -132,6 +137,12 @@ struct pl_render_params {
// already disabled if the overlay texture does not need to be scaled.
bool disable_overlay_sampling;

// Allows the peak detection result to be delayed by up to a single frame,
// which can sometimes (not always) allow skipping some otherwise redundant
// sampling work. Only relevant when peak detection is active (i.e.
// params->peak_detect_params is set and the source is HDR).
bool allow_delayed_peak_detect;

// --- Performance tuning / debugging options
// These may affect performance or may make debugging problems easier,
// but shouldn't have any effect on the quality.
Expand Down
83 changes: 63 additions & 20 deletions src/renderer.c
Original file line number Diff line number Diff line change
Expand Up @@ -66,14 +66,15 @@ struct pl_renderer {
const struct pl_fmt *fbofmt;

// Cached feature checks (inverted)
bool disable_compute; // disable the use of compute shaders
bool disable_sampling; // disable use of advanced scalers
bool disable_debanding; // disable the use of debanding shaders
bool disable_linear_hdr; // disable linear scaling for HDR signals
bool disable_linear_sdr; // disable linear scaling for SDR signals
bool disable_blending; // disable blending for the target/fbofmt
bool disable_overlay; // disable rendering overlays
bool disable_3dlut; // disable usage of a 3DLUT
bool disable_compute; // disable the use of compute shaders
bool disable_sampling; // disable use of advanced scalers
bool disable_debanding; // disable the use of debanding shaders
bool disable_linear_hdr; // disable linear scaling for HDR signals
bool disable_linear_sdr; // disable linear scaling for SDR signals
bool disable_blending; // disable blending for the target/fbofmt
bool disable_overlay; // disable rendering overlays
bool disable_3dlut; // disable usage of a 3DLUT
bool disable_peak_detect; // disable peak detection shader

// Shader resource objects and intermediate textures (FBOs)
struct pl_shader_obj *peak_detect_state;
Expand Down Expand Up @@ -198,14 +199,15 @@ void pl_renderer_flush_cache(struct pl_renderer *rr)
}

const struct pl_render_params pl_render_default_params = {
.upscaler = &pl_filter_spline36,
.downscaler = &pl_filter_mitchell,
.frame_mixer = NULL,

.deband_params = &pl_deband_default_params,
.sigmoid_params = &pl_sigmoid_default_params,
.color_map_params = &pl_color_map_default_params,
.dither_params = &pl_dither_default_params,
.upscaler = &pl_filter_spline36,
.downscaler = &pl_filter_mitchell,
.frame_mixer = NULL,

.deband_params = &pl_deband_default_params,
.sigmoid_params = &pl_sigmoid_default_params,
.peak_detect_params = &pl_peak_detect_default_params,
.color_map_params = &pl_color_map_default_params,
.dither_params = &pl_dither_default_params,
};

// Represents a "in-flight" image, which is a shader that's in the process of
Expand Down Expand Up @@ -598,6 +600,41 @@ static int deband_src(struct pl_renderer *rr, struct pl_shader *psh,
return DEBAND_NORMAL;
}

static void hdr_update_peak(struct pl_renderer *rr, struct pl_shader *sh,
const struct pass_state *pass,
const struct pl_render_params *params)
{
if (!params->peak_detect_params || !pl_color_space_is_hdr(pass->cur_img.color))
goto cleanup;

if (rr->disable_compute || rr->disable_peak_detect)
goto cleanup;

if (!rr->fbofmt && !params->allow_delayed_peak_detect) {
PL_WARN(rr, "Disabling peak detection because "
"`allow_delayed_peak_detect` is false, but lack of FBOs "
"forces the result to be delayed.");
rr->disable_peak_detect = true;
goto cleanup;
}

bool ok = pl_shader_detect_peak(sh, pass->cur_img.color,
&rr->peak_detect_state,
params->peak_detect_params);
if (!ok) {
PL_WARN(rr, "Failed creating HDR peak detection shader.. disabling");
rr->disable_peak_detect = true;
goto cleanup;
}

return;

cleanup:
// No peak detection required or supported, so clean up the state to avoid
// confusing it with later frames where peak detection is enabled again
pl_shader_obj_destroy(&rr->peak_detect_state);
}

// This scales and merges all of the source images, and initializes the cur_img.
static bool pass_read_image(struct pl_renderer *rr, struct pass_state *pass,
const struct pl_image *image,
Expand Down Expand Up @@ -747,6 +784,10 @@ static bool pass_read_image(struct pl_renderer *rr, struct pass_state *pass,

// Convert the image colorspace
pl_shader_decode_color(sh, &pass->cur_img.repr, params->color_adjustment);

// HDR peak detection, do this as early as possible
hdr_update_peak(rr, sh, pass, params);

GLSL("}\n");
return true;
}
Expand All @@ -770,14 +811,16 @@ static bool pass_scale_main(struct pl_renderer *rr, struct pass_state *pass,
.rect = img->rect,
};

bool need_fbo = image->num_overlays > 0;
need_fbo |= rr->peak_detect_state && !params->allow_delayed_peak_detect;

struct sampler_info info = sample_src_info(rr, &src, params);
bool need_osd = image->num_overlays > 0;
if (info.type == SAMPLER_DIRECT && !need_osd) {
if (info.type == SAMPLER_DIRECT && !need_fbo) {
PL_TRACE(rr, "Skipping main scaler (free sampling)");
return true;
}

if (info.dir == SAMPLER_NOOP && !need_osd) {
if (info.dir == SAMPLER_NOOP && !need_fbo) {
PL_TRACE(rr, "Skipping main scaler (would be no-op)");
return true;
}
Expand Down Expand Up @@ -873,7 +916,7 @@ static bool pass_output_target(struct pl_renderer *rr, struct pass_state *pass,
pl_3dlut_apply(sh, &rr->lut3d_state);
// 3DLUT out -> target
pl_shader_color_map(sh, params->color_map_params, res.dst_color,
target->color, &rr->peak_detect_state, false);
target->color, NULL, false);
}

fallback:
Expand Down

0 comments on commit 10670ff

Please sign in to comment.