diff --git a/modules/video_output/placebo_utils.h b/modules/video_output/placebo_utils.h
index 96a43cdf4b..733d6e5faf 100644
--- a/modules/video_output/placebo_utils.h
+++ b/modules/video_output/placebo_utils.h
@@ -183,12 +183,21 @@ static const char * const tone_text[] = {
 #define PEAK_FRAMES_TEXT "HDR peak detection buffer size"
 #define PEAK_FRAMES_LONGTEXT "How many input frames to consider when determining the brightness of HDR signals. Higher values result in a slower/smoother response to brightness level changes. Setting this to 0 disables peak detection entirely."
 
+#define PEAK_PERIOD_TEXT "HDR peak detection period"
+#define PEAK_PERIOD_LONGTEXT "This option enables peak detection with the specified smoothing period. A value of 0.0 disables peak detection. Higher values result in a larger smoothing period which means the detected values will be stable over a longer number of frames, at the cost of responding more slowly to changes in scene brightness"
+
 #define TARGET_AVG_TEXT "Target peak brightness average"
 #define TARGET_AVG_LONGTEXT "If the source frame has an average brightness exceeding this number, the frame will be automatically darkened to compensate. This feature only works when peak detection is enabled."
 
 #define SCENE_THRESHOLD_TEXT "HDR peak scene change threshold"
 #define SCENE_THRESHOLD_LONGTEXT "When using HDR peak detection, this sets a threshold for sudden brightness changes that should be considered as scene changes. This will result in the detected peak being immediately updated to the new value, rather than gradually being adjusted. Setting this to 0 disables this feature."
 
+#define SCENE_THRESHOLD_LOW_TEXT "Scene change lower threshold"
+#define SCENE_THRESHOLD_LOW_LONGTEXT "When using HDR peak detection, this sets the lower boundary of a brightness change indicating a scene change. Brightness changes between frames that exceed this threshold will begin to be mixed into the detected peak more strongly, bypassing the peak smoothing. Setting this to a negative number disables this logic."
+
+#define SCENE_THRESHOLD_HIGH_TEXT "Scene change upper threshold"
+#define SCENE_THRESHOLD_HIGH_LONGTEXT "This sets the upper boundary of a brightness change indicating a scene change. Brightness changes that exceed this value will instantly replace the detected peak, bypassing all smoothing. Setting this to a negative number disables this logic."
+
 #define DITHER_TEXT "Dithering algorithm"
 #define DITHER_LONGTEXT "The algorithm to use when dithering to a lower bit depth."
 
@@ -484,4 +493,7 @@ static const struct pl_filter_function *const filter_fun[] = {
 #define FORCE_GENERAL_TEXT "Force the use of general-purpose scalers"
 #define FORCE_GENERAL_LONGTEXT "Normally, certain special scalers will be replaced by faster versions instead of going through the general scaler architecture. Enabling this option disables these optimizations."
 
+#define DELAYED_PEAK_TEXT "Allow delaying peak detection by up to one frame"
+#define DELAYED_PEAK_LONGTEXT "In some cases, peak detection may be more convenient to compute if the results are delayed by a frame. When this option is disabled, libplacebo will use an indirect buffer simply to force peak detection results to be up-to-date. Enabling it allows skipping this indirection in order to improve performance at the cost of some potentially noticeable brightness flickering immediately after a scene change."
+
 #endif // VLC_PLACEBO_UTILS_H
diff --git a/modules/video_output/vulkan/display.c b/modules/video_output/vulkan/display.c
index 48fa4eafb2..d2ef6cdfee 100644
--- a/modules/video_output/vulkan/display.c
+++ b/modules/video_output/vulkan/display.c
@@ -71,6 +71,9 @@ struct vout_display_sys_t
     struct pl_dither_params dither;
     struct pl_render_params params;
     struct pl_color_space target;
+#if PL_API_VER >= 13
+    struct pl_peak_detect_params peak_detect;
+#endif
     enum pl_chroma_location yuv_chroma_loc;
     int dither_depth;
 };
@@ -617,12 +620,25 @@ vlc_module_begin () set_shortname ("Vulkan")
             TONEMAP_DESAT_TEXT, TONEMAP_DESAT_LONGTEXT, false)
 #endif
     add_bool("gamut-warning", false, GAMUT_WARN_TEXT, GAMUT_WARN_LONGTEXT, true)
+
+#if PL_API_VER < 12
     add_integer_with_range("peak-frames", pl_color_map_default_params.peak_detect_frames,
             0, 255, PEAK_FRAMES_TEXT, PEAK_FRAMES_LONGTEXT, false)
-    add_float_with_range("target-avg", 0.25,
-            0.0, 1.0, TARGET_AVG_TEXT, TARGET_AVG_LONGTEXT, false)
     add_float_with_range("scene-threshold", pl_color_map_default_params.scene_threshold,
             0., 10., SCENE_THRESHOLD_TEXT, SCENE_THRESHOLD_LONGTEXT, false)
+#endif
+
+#if PL_API_VER >= 13
+    add_float_with_range("peak-period", pl_peak_detect_default_params.smoothing_period,
+            0., 1000., PEAK_PERIOD_TEXT, PEAK_PERIOD_LONGTEXT, false)
+    add_float("scene-threshold-low", pl_peak_detect_default_params.scene_threshold_low,
+            SCENE_THRESHOLD_LOW_TEXT, SCENE_THRESHOLD_LOW_LONGTEXT, false)
+    add_float("scene-threshold-high", pl_peak_detect_default_params.scene_threshold_high,
+            SCENE_THRESHOLD_HIGH_TEXT, SCENE_THRESHOLD_HIGH_LONGTEXT, false)
+#endif
+
+    add_float_with_range("target-avg", 0.25,
+            0.0, 1.0, TARGET_AVG_TEXT, TARGET_AVG_LONGTEXT, false)
 
     set_section("Dithering", NULL)
     add_integer("dither", -1,
@@ -673,6 +689,9 @@ vlc_module_begin () set_shortname ("Vulkan")
     add_bool("overlay-direct", false, OVERLAY_DIRECT_TEXT, OVERLAY_DIRECT_LONGTEXT, false)
     add_bool("disable-linear", false, DISABLE_LINEAR_TEXT, DISABLE_LINEAR_LONGTEXT, false)
     add_bool("force-general", false, FORCE_GENERAL_TEXT, FORCE_GENERAL_LONGTEXT, false)
+#if PL_API_VER >= 13
+    add_bool("delayed-peak", false, DELAYED_PEAK_TEXT, DELAYED_PEAK_LONGTEXT, false)
+#endif
 
 vlc_module_end ()
 
@@ -711,8 +730,10 @@ static void UpdateParams(vout_display_t *vd)
     sys->color_map.tone_mapping_desaturate = var_InheritFloat(vd, "tone-mapping-desat");
 #endif
     sys->color_map.gamut_warning = var_InheritBool(vd, "gamut-warning");
+#if PL_API_VER < 12
     sys->color_map.peak_detect_frames = var_InheritInteger(vd, "peak-frames");
     sys->color_map.scene_threshold = var_InheritFloat(vd, "scene-threshold");
+#endif
 
     sys->dither = pl_dither_default_params;
     int method = var_InheritInteger(vd, "dither");
@@ -734,6 +755,16 @@ static void UpdateParams(vout_display_t *vd)
     sys->params.disable_linear_scaling = var_InheritBool(vd, "disable-linear");
     sys->params.disable_builtin_scalers = var_InheritBool(vd, "force-general");
 
+#if PL_API_VER >= 13
+    sys->peak_detect.smoothing_period = var_InheritFloat(vd, "peak-period");
+    sys->peak_detect.scene_threshold_low = var_InheritFloat(vd, "scene-threshold-low");
+    sys->peak_detect.scene_threshold_high = var_InheritFloat(vd, "scene-threshold-high");
+    if (sys->peak_detect.smoothing_period > 0.0) {
+        sys->params.peak_detect_params = &sys->peak_detect;
+        sys->params.allow_delayed_peak_detect = var_InheritBool(vd, "delayed-peak");
+    }
+#endif
+
     int preset = var_InheritInteger(vd, "upscaler-preset");
     sys->params.upscaler = scale_config[preset];
     if (preset == SCALE_CUSTOM) {
