From 571e697a7c557d10bcc9130915c431829981d877 Mon Sep 17 00:00:00 2001 From: wm4 Date: Mon, 4 Nov 2013 00:00:18 +0100 Subject: vo_opengl: add infrastructure for hardware decoding OpenGL interop Most hardware decoding APIs provide some OpenGL interop. This allows using vo_opengl, without having to read the video data back from GPU. This requires adding a backend for each hardware decoding API. (Each backend is an entry in gl_hwdec_vaglx[].) The backends expose video data as a set of OpenGL textures. Add infrastructure to support this. The next commit will add support for VA-API. --- video/out/gl_video.c | 123 ++++++++++++++++++++++++++++++++++++++------------- 1 file changed, 93 insertions(+), 30 deletions(-) (limited to 'video/out/gl_video.c') diff --git a/video/out/gl_video.c b/video/out/gl_video.c index d4b4b507c3..b376fead36 100644 --- a/video/out/gl_video.c +++ b/video/out/gl_video.c @@ -114,6 +114,7 @@ struct texplane { struct video_image { struct texplane planes[4]; bool image_flipped; + struct mp_image *hwimage; // if hw decoding is active }; struct scaler { @@ -202,6 +203,9 @@ struct gl_video { int last_dither_matrix_size; float *last_dither_matrix; + struct gl_hwdec *hwdec; + bool hwdec_active; + void *scratch; }; @@ -1129,7 +1133,7 @@ static void reinit_rendering(struct gl_video *p) uninit_rendering(p); - if (!p->image.planes[0].gl_texture) + if (!p->image_format) return; for (int n = 0; n < 2; n++) @@ -1196,17 +1200,41 @@ void gl_video_set_lut3d(struct gl_video *p, struct lut3d *lut3d) debug_check_gl(p, "after 3d lut creation"); } -static void set_image_textures(struct gl_video *p, struct video_image *vimg) +static void set_image_textures(struct gl_video *p, struct video_image *vimg, + GLuint imgtex[4]) { GL *gl = p->gl; + GLuint dummy[4]; + if (!imgtex) + imgtex = dummy; - for (int n = 0; n < p->plane_count; n++) { - struct texplane *plane = &vimg->planes[n]; + if (p->hwdec_active) { + assert(vimg->hwimage); + p->hwdec->driver->load_image(p->hwdec, vimg->hwimage, imgtex); + } else { + for (int n = 0; n < p->plane_count; n++) + imgtex[n] = vimg->planes[n].gl_texture; + } + for (int n = 0; n < 4; n++) { gl->ActiveTexture(GL_TEXTURE0 + n); - gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture); + gl->BindTexture(GL_TEXTURE_2D, imgtex[n]); + } + gl->ActiveTexture(GL_TEXTURE0); +} + +static void unset_image_textures(struct gl_video *p) +{ + GL *gl = p->gl; + + for (int n = 0; n < 4; n++) { + gl->ActiveTexture(GL_TEXTURE0 + n); + gl->BindTexture(GL_TEXTURE_2D, 0); } gl->ActiveTexture(GL_TEXTURE0); + + if (p->hwdec_active) + p->hwdec->driver->unload_image(p->hwdec); } static void init_video(struct gl_video *p) @@ -1243,21 +1271,27 @@ static void init_video(struct gl_video *p) plane->w = full_w >> p->image_desc.xs[n]; plane->h = full_h >> p->image_desc.ys[n]; - texture_size(p, plane->w, plane->h, - &plane->tex_w, &plane->tex_h); + if (p->hwdec_active) { + // We expect hwdec backends to allocate exact size + plane->tex_w = plane->w; + plane->tex_h = plane->h; + } else { + texture_size(p, plane->w, plane->h, + &plane->tex_w, &plane->tex_h); - MP_VERBOSE(p, "Texture for plane %d: %dx%d\n", - n, plane->tex_w, plane->tex_h); + gl->ActiveTexture(GL_TEXTURE0 + n); + gl->GenTextures(1, &plane->gl_texture); + gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture); - gl->ActiveTexture(GL_TEXTURE0 + n); - gl->GenTextures(1, &plane->gl_texture); - gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture); + gl->TexImage2D(GL_TEXTURE_2D, 0, plane->gl_internal_format, + plane->tex_w, plane->tex_h, 0, + plane->gl_format, plane->gl_type, NULL); - gl->TexImage2D(GL_TEXTURE_2D, 0, plane->gl_internal_format, - plane->tex_w, plane->tex_h, 0, - plane->gl_format, plane->gl_type, NULL); + default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR); + } - default_tex_params(gl, GL_TEXTURE_2D, GL_LINEAR); + MP_VERBOSE(p, "Texture for plane %d: %dx%d\n", + n, plane->tex_w, plane->tex_h); } gl->ActiveTexture(GL_TEXTURE0); @@ -1266,6 +1300,11 @@ static void init_video(struct gl_video *p) debug_check_gl(p, "after video texture creation"); + if (p->hwdec_active) { + if (p->hwdec->driver->reinit(p->hwdec, p->image_w, p->image_h) < 0) + MP_ERR(p, "Initializing hardware ddecoding video texture failed.\n"); + } + reinit_rendering(p); } @@ -1287,6 +1326,7 @@ static void uninit_video(struct gl_video *p) plane->buffer_ptr = NULL; plane->buffer_size = 0; } + mp_image_unrefp(&vimg->hwimage); fbotex_uninit(p, &p->indirect_fbo); fbotex_uninit(p, &p->scale_sep_fbo); @@ -1373,14 +1413,15 @@ void gl_video_render_frame(struct gl_video *p) // Order of processing: // [indirect -> [scale_sep ->]] final - set_image_textures(p, vimg); + GLuint imgtex[4] = {0}; + set_image_textures(p, vimg, imgtex); struct fbotex chain = { .vp_w = p->image_w, .vp_h = p->image_h, .tex_w = p->texture_w, .tex_h = p->texture_h, - .texture = vimg->planes[0].gl_texture, + .texture = imgtex[0], }; handle_pass(p, &chain, &p->indirect_fbo, p->indirect_program); @@ -1441,6 +1482,8 @@ void gl_video_render_frame(struct gl_video *p) gl->UseProgram(0); + unset_image_textures(p); + p->frames_rendered++; debug_check_gl(p, "after video rendering"); @@ -1552,16 +1595,21 @@ static bool get_image(struct gl_video *p, struct mp_image *mpi) void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi) { GL *gl = p->gl; - int n; - - assert(mpi->num_planes == p->plane_count); struct video_image *vimg = &p->image; + if (p->hwdec_active) { + mp_image_setrefp(&vimg->hwimage, mpi); + p->have_image = true; + return; + } + + assert(mpi->num_planes == p->plane_count); + mp_image_t mpi2 = *mpi; bool pbo = false; if (!vimg->planes[0].buffer_ptr && get_image(p, &mpi2)) { - for (n = 0; n < p->plane_count; n++) { + for (int n = 0; n < p->plane_count; n++) { int line_bytes = mpi->plane_w[n] * p->image_desc.bytes[n]; memcpy_pic(mpi2.planes[n], mpi->planes[n], line_bytes, mpi->plane_h[n], mpi2.stride[n], mpi->stride[n]); @@ -1570,7 +1618,7 @@ void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi) pbo = true; } vimg->image_flipped = mpi->stride[0] < 0; - for (n = 0; n < p->plane_count; n++) { + for (int n = 0; n < p->plane_count; n++) { struct texplane *plane = &vimg->planes[n]; void *plane_ptr = mpi->planes[n]; if (pbo) { @@ -1598,10 +1646,11 @@ struct mp_image *gl_video_download_image(struct gl_video *p) struct video_image *vimg = &p->image; - if (!p->have_image || !vimg->planes[0].gl_texture) + if (!p->have_image) return NULL; - assert(p->image_format == p->image_params.imgfmt); + set_image_textures(p, vimg, NULL); + assert(p->texture_w >= p->image_params.w); assert(p->texture_h >= p->image_params.h); @@ -1611,12 +1660,12 @@ struct mp_image *gl_video_download_image(struct gl_video *p) for (int n = 0; n < p->plane_count; n++) { struct texplane *plane = &vimg->planes[n]; gl->ActiveTexture(GL_TEXTURE0 + n); - gl->BindTexture(GL_TEXTURE_2D, plane->gl_texture); glDownloadTex(gl, GL_TEXTURE_2D, plane->gl_format, plane->gl_type, image->planes[n], image->stride[n]); } - gl->ActiveTexture(GL_TEXTURE0); - mp_image_set_params(image, &p->image_params); + mp_image_set_attributes(image, &p->image_params); + + unset_image_textures(p); return image; } @@ -1884,6 +1933,12 @@ static bool init_format(int fmt, struct gl_video *init) if (!init) init = &dummy; + init->hwdec_active = false; + if (init->hwdec && init->hwdec->driver->query_format(fmt)) { + fmt = init->hwdec->converted_imgfmt; + init->hwdec_active = true; + } + struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(fmt); if (!desc.id) return false; @@ -1985,9 +2040,10 @@ static bool init_format(int fmt, struct gl_video *init) return true; } -bool gl_video_check_format(int mp_format) +bool gl_video_check_format(struct gl_video *p, int mp_format) { - return init_format(mp_format, NULL); + struct gl_video tmp = *p; + return init_format(mp_format, &tmp); } void gl_video_config(struct gl_video *p, struct mp_image_params *params) @@ -2012,6 +2068,7 @@ void gl_video_config(struct gl_video *p, struct mp_image_params *params) p->colorspace = csp; p->have_image = false; + mp_image_unrefp(&p->image.hwimage); } void gl_video_set_output_depth(struct gl_video *p, int r, int g, int b) @@ -2132,3 +2189,9 @@ void gl_video_resize_redraw(struct gl_video *p, int w, int h) gl_video_render_frame(p); mpgl_osd_redraw_cb(p->osd, draw_osd_cb, p); } + +void gl_video_set_hwdec(struct gl_video *p, struct gl_hwdec *hwdec) +{ + p->hwdec = hwdec; + mp_image_unrefp(&p->image.hwimage); +} -- cgit v1.2.3