From b0ba193b66b402c5417aa5c0863cc357139e528d Mon Sep 17 00:00:00 2001 From: Niklas Haas Date: Sat, 23 Sep 2017 09:54:42 +0200 Subject: vo_gpu: handle texture initialization errors gracefully Tested by making the ra_tex_resize function always fail (apart from the initial FBO check). This required a few changes: 1. reset shaders on failed dispatch 2. reset cleanup binds on failed dispatch 3. fall back to initializing the struct image to 1x1 on failure 4. handle output_fbo_valid gracefully --- video/out/gpu/shader_cache.c | 6 ++---- video/out/gpu/shader_cache.h | 3 +++ video/out/gpu/video.c | 37 ++++++++++++++++++++++--------------- 3 files changed, 27 insertions(+), 19 deletions(-) (limited to 'video') diff --git a/video/out/gpu/shader_cache.c b/video/out/gpu/shader_cache.c index ead759d931..86939083db 100644 --- a/video/out/gpu/shader_cache.c +++ b/video/out/gpu/shader_cache.c @@ -104,8 +104,6 @@ struct gl_shader_cache { struct mpv_global *global; // can be NULL }; -static void gl_sc_reset(struct gl_shader_cache *sc); - struct gl_shader_cache *gl_sc_create(struct ra *ra, struct mpv_global *global, struct mp_log *log) { @@ -120,8 +118,8 @@ struct gl_shader_cache *gl_sc_create(struct ra *ra, struct mpv_global *global, } // Reset the previous pass. This must be called after gl_sc_generate and before -// starting a new shader. -static void gl_sc_reset(struct gl_shader_cache *sc) +// starting a new shader. It may also be called on errors. +void gl_sc_reset(struct gl_shader_cache *sc) { sc->prelude_text.len = 0; sc->header_text.len = 0; diff --git a/video/out/gpu/shader_cache.h b/video/out/gpu/shader_cache.h index 82a078079b..377293391c 100644 --- a/video/out/gpu/shader_cache.h +++ b/video/out/gpu/shader_cache.h @@ -53,4 +53,7 @@ struct mp_pass_perf gl_sc_dispatch_draw(struct gl_shader_cache *sc, void *ptr, size_t num); struct mp_pass_perf gl_sc_dispatch_compute(struct gl_shader_cache *sc, int w, int h, int d); +// The application can call this on errors, to reset the current shader. This +// is normally done implicitly by gl_sc_dispatch_* +void gl_sc_reset(struct gl_shader_cache *sc); void gl_sc_set_cache_dir(struct gl_shader_cache *sc, const char *dir); diff --git a/video/out/gpu/video.c b/video/out/gpu/video.c index ae847b1782..4cc6114c52 100644 --- a/video/out/gpu/video.c +++ b/video/out/gpu/video.c @@ -622,8 +622,8 @@ static struct image image_wrap(struct ra_tex *tex, enum plane_type type, .type = type, .tex = tex, .multiplier = 1.0, - .w = tex->params.w, - .h = tex->params.h, + .w = tex ? tex->params.w : 1, + .h = tex ? tex->params.h : 1, .transform = identity_trans, .components = components, }; @@ -1096,6 +1096,12 @@ static void pass_is_compute(struct gl_video *p, int bw, int bh) }; } +static void cleanup_binds(struct gl_video *p) +{ + memset(&p->pass_img, 0, sizeof(p->pass_img)); + p->pass_img_num = 0; +} + // w/h: the width/height of the compute shader's operating domain (e.g. the // target target that needs to be written, or the source texture that needs to // be reduced) @@ -1140,9 +1146,7 @@ static void dispatch_compute(struct gl_video *p, int w, int h, num_y = info.block_h > 0 ? (h + info.block_h - 1) / info.block_h : 1; pass_record(p, gl_sc_dispatch_compute(p->sc, num_x, num_y, 1)); - - memset(&p->pass_img, 0, sizeof(p->pass_img)); - p->pass_img_num = 0; + cleanup_binds(p); } static struct mp_pass_perf render_pass_quad(struct gl_video *p, @@ -1184,14 +1188,13 @@ static struct mp_pass_perf render_pass_quad(struct gl_video *p, } static void finish_pass_fbo(struct gl_video *p, struct ra_fbo fbo, - const struct mp_rect *dst) + const struct mp_rect *dst) { pass_prepare_src_tex(p); gl_sc_set_vertex_format(p->sc, vertex_vao, sizeof(struct vertex)); pass_record(p, render_pass_quad(p, fbo, dst)); debug_check_gl(p, "after rendering"); - memset(&p->pass_img, 0, sizeof(p->pass_img)); - p->pass_img_num = 0; + cleanup_binds(p); } // dst_fbo: this will be used for rendering; possibly reallocating the whole @@ -1201,8 +1204,11 @@ static void finish_pass_fbo(struct gl_video *p, struct ra_fbo fbo, static void finish_pass_tex(struct gl_video *p, struct ra_tex **dst_tex, int w, int h) { - if (!ra_tex_resize(p->ra, p->log, dst_tex, w, h, p->fbo_format)) + if (!ra_tex_resize(p->ra, p->log, dst_tex, w, h, p->fbo_format)) { + cleanup_binds(p); + gl_sc_reset(p->sc); return; + } if (p->pass_compute.active) { gl_sc_uniform_image2D_wo(p->sc, "out_image", *dst_tex); @@ -3044,12 +3050,13 @@ void gl_video_render_frame(struct gl_video *p, struct vo_frame *frame, if (frame->num_vsyncs > 1 && frame->display_synced && !p->dumb_mode && (p->ra->caps & RA_CAP_BLIT)) { - ra_tex_resize(p->ra, p->log, &p->output_tex, - fbo.tex->params.w, fbo.tex->params.h, - p->fbo_format); - - dest_fbo = (struct ra_fbo) { p->output_tex }; - p->output_tex_valid = true; + bool r = ra_tex_resize(p->ra, p->log, &p->output_tex, + fbo.tex->params.w, fbo.tex->params.h, + p->fbo_format); + if (r) { + dest_fbo = (struct ra_fbo) { p->output_tex }; + p->output_tex_valid = true; + } } pass_draw_to_screen(p, dest_fbo); } -- cgit v1.2.3