summaryrefslogtreecommitdiffstats
path: root/video/out/opengl/video.c
diff options
context:
space:
mode:
authorNiklas Haas <git@haasn.xyz>2017-07-17 21:39:06 +0200
committerNiklas Haas <git@haasn.xyz>2017-07-24 17:19:31 +0200
commitb196cadf9f9f6ea210db9236c2b26523a9a2719f (patch)
tree7faa5a77c65d84e45c074eb248fe0b54a62288ad /video/out/opengl/video.c
parentaad6ba018a17eded2b3f4af2212e0123cfb29b79 (diff)
downloadmpv-b196cadf9f9f6ea210db9236c2b26523a9a2719f.tar.bz2
mpv-b196cadf9f9f6ea210db9236c2b26523a9a2719f.tar.xz
vo_opengl: support HDR peak detection
This is done via compute shaders. As a consequence, the tone mapping algorithms had to be rewritten to compute their known constants in GLSL (ahead of time), instead of doing it once. Didn't affect performance. Using shmem/SSBO atomics in this way is extremely fast on nvidia, but it might be slow on other platforms. Needs testing. Unfortunately, setting up the SSBO still requires OpenGL calls, which means I can't have it in video_shaders.c, where it belongs. But I'll defer worrying about that until the backend refactor, since then I'll be breaking up the video/video_shaders structure anyway.
Diffstat (limited to 'video/out/opengl/video.c')
-rw-r--r--video/out/opengl/video.c57
1 files changed, 56 insertions, 1 deletions
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c
index ab8f311191..76b9d829ab 100644
--- a/video/out/opengl/video.c
+++ b/video/out/opengl/video.c
@@ -236,9 +236,11 @@ struct gl_video {
struct fbotex integer_fbo[4];
struct fbotex indirect_fbo;
struct fbotex blend_subs_fbo;
+ struct fbotex screen_fbo;
struct fbotex output_fbo;
struct fbosurface surfaces[FBOSURFACES_MAX];
struct fbotex vdpau_deinterleave_fbo[2];
+ GLuint hdr_peak_ssbo;
int surface_idx;
int surface_now;
@@ -368,6 +370,7 @@ const struct m_sub_options gl_video_conf = {
{"hable", TONE_MAPPING_HABLE},
{"gamma", TONE_MAPPING_GAMMA},
{"linear", TONE_MAPPING_LINEAR})),
+ OPT_FLAG("hdr-compute-peak", compute_hdr_peak, 0),
OPT_FLOAT("tone-mapping-param", tone_mapping_param, 0),
OPT_FLOAT("tone-mapping-desaturate", tone_mapping_desat, 0),
OPT_FLAG("opengl-pbo", pbo, 0),
@@ -541,6 +544,7 @@ static void uninit_rendering(struct gl_video *p)
fbotex_uninit(&p->indirect_fbo);
fbotex_uninit(&p->blend_subs_fbo);
+ fbotex_uninit(&p->screen_fbo);
for (int n = 0; n < FBOSURFACES_MAX; n++)
fbotex_uninit(&p->surfaces[n].fbotex);
@@ -2358,6 +2362,8 @@ static void pass_scale_main(struct gl_video *p)
// by previous passes (i.e. linear scaling)
static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, bool osd)
{
+ GL *gl = p->gl;
+
// Figure out the target color space from the options, or auto-guess if
// none were set
struct mp_colorspace dst = {
@@ -2417,10 +2423,42 @@ static void pass_colormanage(struct gl_video *p, struct mp_colorspace src, bool
dst.gamma = MP_CSP_TRC_GAMMA22;
}
+ bool detect_peak = p->opts.compute_hdr_peak && mp_trc_is_hdr(src.gamma);
+ if (detect_peak) {
+ pass_describe(p, "detect HDR peak");
+ compute_size_minimum(p, 8, 8); // 8x8 is good for performance
+
+ if (!p->hdr_peak_ssbo) {
+ struct {
+ GLuint sig_peak_raw;
+ GLuint index;
+ GLuint frame_max[PEAK_DETECT_FRAMES+1];
+ } peak_ssbo = {0};
+
+ // Prefill with safe values
+ int safe = MP_REF_WHITE * mp_trc_nom_peak(p->image_params.color.gamma);
+ peak_ssbo.sig_peak_raw = PEAK_DETECT_FRAMES * safe;
+ for (int i = 0; i < PEAK_DETECT_FRAMES+1; i++)
+ peak_ssbo.frame_max[i] = safe;
+
+ gl->GenBuffers(1, &p->hdr_peak_ssbo);
+ gl->BindBuffer(GL_SHADER_STORAGE_BUFFER, p->hdr_peak_ssbo);
+ gl->BufferData(GL_SHADER_STORAGE_BUFFER, sizeof(peak_ssbo),
+ &peak_ssbo, GL_STREAM_COPY);
+ gl->BindBuffer(GL_SHADER_STORAGE_BUFFER, 0);
+ }
+
+ gl_sc_ssbo(p->sc, "PeakDetect", p->hdr_peak_ssbo,
+ "uint sig_peak_raw;"
+ "uint index;"
+ "uint frame_max[%d];", PEAK_DETECT_FRAMES + 1
+ );
+ }
+
// Adapt from src to dst as necessary
pass_color_map(p->sc, src, dst, p->opts.hdr_tone_mapping,
p->opts.tone_mapping_param, p->opts.tone_mapping_desat,
- p->use_linear && !osd);
+ detect_peak, p->use_linear && !osd);
if (p->use_lut_3d) {
gl_sc_uniform_tex(p->sc, "lut_3d", GL_TEXTURE_3D, p->lut_3d_texture);
@@ -2710,6 +2748,17 @@ static void pass_draw_to_screen(struct gl_video *p, int fbo)
pass_colormanage(p, p->image_params.color, false);
+ // Since finish_pass_direct doesn't work with compute shaders, and neither
+ // does the checkerboard/dither code, we may need an indirection via
+ // p->screen_fbo here.
+ if (p->compute_w > 0 && p->compute_h > 0) {
+ int o_w = p->dst_rect.x1 - p->dst_rect.x0,
+ o_h = p->dst_rect.y1 - p->dst_rect.y0;
+ finish_pass_fbo(p, &p->screen_fbo, o_w, o_h, FBOTEX_FUZZY);
+ struct img_tex tmp = img_tex_fbo(&p->screen_fbo, PLANE_RGB, p->components);
+ copy_img_tex(p, &(int){0}, tmp);
+ }
+
if (p->has_alpha){
if (p->opts.alpha_mode == ALPHA_BLEND_TILES) {
// Draw checkerboard pattern to indicate transparency
@@ -3326,6 +3375,7 @@ static void check_gl_features(struct gl_video *p)
bool have_mglsl = gl->glsl_version >= 130; // modern GLSL (1st class arrays etc.)
bool have_texrg = gl->mpgl_caps & MPGL_CAP_TEX_RG;
bool have_tex16 = !gl->es || (gl->mpgl_caps & MPGL_CAP_EXT16);
+ bool have_compute = gl->glsl_version >= 430; // easiest way to ensure all
const GLint auto_fbo_fmts[] = {GL_RGBA16, GL_RGBA16F, GL_RGB10_A2,
GL_RGBA8, 0};
@@ -3436,6 +3486,10 @@ static void check_gl_features(struct gl_video *p)
p->opts.deband = 0;
MP_WARN(p, "Disabling debanding (GLSL version too old).\n");
}
+ if (!have_compute && p->opts.compute_hdr_peak) {
+ p->opts.compute_hdr_peak = 0;
+ MP_WARN(p, "Disabling HDR peak computation (no compute shaders).\n");
+ }
}
static void init_gl(struct gl_video *p)
@@ -3471,6 +3525,7 @@ void gl_video_uninit(struct gl_video *p)
gl_sc_destroy(p->sc);
gl->DeleteTextures(1, &p->lut_3d_texture);
+ gl->DeleteBuffers(1, &p->hdr_peak_ssbo);
gl_timer_free(p->upload_timer);
gl_timer_free(p->blit_timer);