diff options
Diffstat (limited to 'video/out/opengl')
-rw-r--r-- | video/out/opengl/common.c | 1 | ||||
-rw-r--r-- | video/out/opengl/common.h | 2 | ||||
-rw-r--r-- | video/out/opengl/hwdec.h | 1 | ||||
-rw-r--r-- | video/out/opengl/hwdec_vdpau.c | 125 | ||||
-rw-r--r-- | video/out/opengl/video.c | 50 |
5 files changed, 142 insertions, 37 deletions
diff --git a/video/out/opengl/common.c b/video/out/opengl/common.c index 30321abc86..1c5aa0a2cf 100644 --- a/video/out/opengl/common.c +++ b/video/out/opengl/common.c @@ -349,6 +349,7 @@ static const struct gl_functions gl_functions[] = { DEF_FN(VDPAUInitNV), DEF_FN(VDPAUFiniNV), DEF_FN(VDPAURegisterOutputSurfaceNV), + DEF_FN(VDPAURegisterVideoSurfaceNV), DEF_FN(VDPAUUnregisterSurfaceNV), DEF_FN(VDPAUSurfaceAccessNV), DEF_FN(VDPAUMapSurfacesNV), diff --git a/video/out/opengl/common.h b/video/out/opengl/common.h index 280c1f514b..e3ebd66c41 100644 --- a/video/out/opengl/common.h +++ b/video/out/opengl/common.h @@ -203,6 +203,8 @@ struct GL { void (GLAPIENTRY *VDPAUFiniNV)(void); GLvdpauSurfaceNV (GLAPIENTRY *VDPAURegisterOutputSurfaceNV) (GLvoid *, GLenum, GLsizei, const GLuint *); + GLvdpauSurfaceNV (GLAPIENTRY *VDPAURegisterVideoSurfaceNV) + (GLvoid *, GLenum, GLsizei, const GLuint *); void (GLAPIENTRY *VDPAUUnregisterSurfaceNV)(GLvdpauSurfaceNV); void (GLAPIENTRY *VDPAUSurfaceAccessNV)(GLvdpauSurfaceNV, GLenum); void (GLAPIENTRY *VDPAUMapSurfacesNV)(GLsizei, const GLvdpauSurfaceNV *); diff --git a/video/out/opengl/hwdec.h b/video/out/opengl/hwdec.h index 4a074ec4a5..29ccd18a42 100644 --- a/video/out/opengl/hwdec.h +++ b/video/out/opengl/hwdec.h @@ -27,6 +27,7 @@ struct gl_hwdec_plane { struct gl_hwdec_frame { struct gl_hwdec_plane planes[4]; + bool vdpau_fields; }; struct gl_hwdec_driver { diff --git a/video/out/opengl/hwdec_vdpau.c b/video/out/opengl/hwdec_vdpau.c index e1bccd7771..83f664a756 100644 --- a/video/out/opengl/hwdec_vdpau.c +++ b/video/out/opengl/hwdec_vdpau.c @@ -36,11 +36,12 @@ struct priv { struct mp_vdpau_ctx *ctx; uint64_t preemption_counter; struct mp_image_params image_params; - GLuint gl_texture; + GLuint gl_textures[4]; bool vdpgl_initialized; GLvdpauSurfaceNV vdpgl_surface; VdpOutputSurface vdp_surface; struct mp_vdpau_mixer *mixer; + bool direct_mode; bool mapped; }; @@ -49,8 +50,13 @@ static void unmap(struct gl_hwdec *hw) struct priv *p = hw->priv; GL *gl = hw->gl; - if (p->mapped) + if (p->mapped) { gl->VDPAUUnmapSurfacesNV(1, &p->vdpgl_surface); + if (p->direct_mode) { + gl->VDPAUUnregisterSurfaceNV(p->vdpgl_surface); + p->vdpgl_surface = 0; + } + } p->mapped = false; } @@ -75,8 +81,9 @@ static void destroy_objects(struct gl_hwdec *hw) gl->VDPAUUnregisterSurfaceNV(p->vdpgl_surface); p->vdpgl_surface = 0; - glDeleteTextures(1, &p->gl_texture); - p->gl_texture = 0; + glDeleteTextures(4, p->gl_textures); + for (int n = 0; n < 4; n++) + p->gl_textures[n] = 0; if (p->vdp_surface != VDP_INVALID_HANDLE) { vdp_st = vdp->output_surface_destroy(p->vdp_surface); @@ -151,30 +158,39 @@ static int reinit(struct gl_hwdec *hw, struct mp_image_params *params) p->vdpgl_initialized = true; - vdp_st = vdp->output_surface_create(p->ctx->vdp_device, - VDP_RGBA_FORMAT_B8G8R8A8, - params->w, params->h, &p->vdp_surface); - CHECK_VDP_ERROR(p, "Error when calling vdp_output_surface_create"); - - gl->GenTextures(1, &p->gl_texture); - gl->BindTexture(GL_TEXTURE_2D, p->gl_texture); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + p->direct_mode = params->hw_subfmt == IMGFMT_NV12; + + gl->GenTextures(4, p->gl_textures); + for (int n = 0; n < 4; n++) { + gl->BindTexture(GL_TEXTURE_2D, p->gl_textures[n]); + GLenum filter = p->direct_mode ? GL_NEAREST : GL_LINEAR; + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, filter); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, filter); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->TexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); + } gl->BindTexture(GL_TEXTURE_2D, 0); - p->vdpgl_surface = gl->VDPAURegisterOutputSurfaceNV(BRAINDEATH(p->vdp_surface), - GL_TEXTURE_2D, - 1, &p->gl_texture); - if (!p->vdpgl_surface) - return -1; + if (p->direct_mode) { + params->imgfmt = IMGFMT_NV12; + } else { + vdp_st = vdp->output_surface_create(p->ctx->vdp_device, + VDP_RGBA_FORMAT_B8G8R8A8, + params->w, params->h, &p->vdp_surface); + CHECK_VDP_ERROR(p, "Error when calling vdp_output_surface_create"); + + p->vdpgl_surface = gl->VDPAURegisterOutputSurfaceNV(BRAINDEATH(p->vdp_surface), + GL_TEXTURE_2D, + 1, p->gl_textures); + if (!p->vdpgl_surface) + return -1; - gl->VDPAUSurfaceAccessNV(p->vdpgl_surface, GL_READ_ONLY); + gl->VDPAUSurfaceAccessNV(p->vdpgl_surface, GL_READ_ONLY); - gl_check_error(gl, hw->log, "After initializing vdpau OpenGL interop"); + params->imgfmt = IMGFMT_RGB0; + } - params->imgfmt = IMGFMT_RGB0; + gl_check_error(gl, hw->log, "After initializing vdpau OpenGL interop"); return 0; } @@ -184,6 +200,8 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, { struct priv *p = hw->priv; GL *gl = hw->gl; + struct vdp_functions *vdp = &p->ctx->vdp; + VdpStatus vdp_st; int pe = mp_vdpau_handle_preemption(p->ctx, &p->preemption_counter); if (pe < 1) { @@ -194,23 +212,58 @@ static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, return -1; } - if (!p->vdpgl_surface) - return -1; + if (p->direct_mode) { + VdpVideoSurface surface = (intptr_t)hw_image->planes[3]; + + // We need the uncropped size. + VdpChromaType s_chroma_type; + uint32_t s_w, s_h; + vdp_st = vdp->video_surface_get_parameters(surface, &s_chroma_type, &s_w, &s_h); + CHECK_VDP_ERROR(hw, "Error when calling vdp_video_surface_get_parameters"); - mp_vdpau_mixer_render(p->mixer, NULL, p->vdp_surface, NULL, hw_image, NULL); + p->vdpgl_surface = gl->VDPAURegisterVideoSurfaceNV(BRAINDEATH(surface), + GL_TEXTURE_2D, + 4, p->gl_textures); + if (!p->vdpgl_surface) + return -1; - gl->VDPAUMapSurfacesNV(1, &p->vdpgl_surface); - p->mapped = true; - *out_frame = (struct gl_hwdec_frame){ - .planes = { - { - .gl_texture = p->gl_texture, + gl->VDPAUSurfaceAccessNV(p->vdpgl_surface, GL_READ_ONLY); + gl->VDPAUMapSurfacesNV(1, &p->vdpgl_surface); + + p->mapped = true; + *out_frame = (struct gl_hwdec_frame){ + .vdpau_fields = true, + }; + for (int n = 0; n < 4; n++) { + bool chroma = n >= 2; + out_frame->planes[n] = (struct gl_hwdec_plane){ + .gl_texture = p->gl_textures[n], .gl_target = GL_TEXTURE_2D, - .tex_w = p->image_params.w, - .tex_h = p->image_params.h, + .tex_w = s_w / (chroma ? 2 : 1), + .tex_h = s_h / (chroma ? 4 : 2), + }; + }; + } else { + if (!p->vdpgl_surface) + return -1; + + mp_vdpau_mixer_render(p->mixer, NULL, p->vdp_surface, NULL, hw_image, NULL); + + gl->VDPAUMapSurfacesNV(1, &p->vdpgl_surface); + + p->mapped = true; + *out_frame = (struct gl_hwdec_frame){ + .planes = { + { + .gl_texture = p->gl_textures[0], + .gl_target = GL_TEXTURE_2D, + .tex_w = p->image_params.w, + .tex_h = p->image_params.h, + }, }, - }, - }; + }; + } + return 0; } diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index 62bbfd1d05..3b99ba95ca 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -217,6 +217,7 @@ struct gl_video { struct fbotex blend_subs_fbo; struct fbotex output_fbo; struct fbosurface surfaces[FBOSURFACES_MAX]; + struct fbotex vdpau_deinterleave_fbo[2]; int surface_idx; int surface_now; @@ -585,6 +586,9 @@ static void uninit_rendering(struct gl_video *p) for (int n = 0; n < MAX_SAVED_TEXTURES; n++) fbotex_uninit(&p->hook_fbos[n]); + for (int n = 0; n < 2; n++) + fbotex_uninit(&p->vdpau_deinterleave_fbo[n]); + gl_video_reset_surfaces(p); gl_video_reset_hooks(p); @@ -957,7 +961,6 @@ static void render_pass_quad(struct gl_video *p, int vp_w, int vp_h, debug_check_gl(p, "after rendering"); } -// flags: see render_pass_quad static void finish_pass_direct(struct gl_video *p, GLint fbo, int vp_w, int vp_h, const struct mp_rect *dst) { @@ -2917,6 +2920,49 @@ static bool map_image(struct gl_video *p, struct mp_image *mpi) return true; } +// This assumes nv12, with textures set to GL_NEAREST filtering. +static void reinterleave_vdpau(struct gl_video *p, struct gl_hwdec_frame *frame) +{ + struct gl_hwdec_frame res = {0}; + for (int n = 0; n < 2; n++) { + struct fbotex *fbo = &p->vdpau_deinterleave_fbo[n]; + // This is an array of the 2 to-merge planes. + struct gl_hwdec_plane *src = &frame->planes[n * 2]; + int w = src[0].tex_w; + int h = src[0].tex_h; + int ids[2]; + for (int t = 0; t < 2; t++) { + ids[t] = pass_bind(p, (struct img_tex){ + .gl_tex = src[t].gl_texture, + .gl_target = src[t].gl_target, + .multiplier = 1.0, + .transform = identity_trans, + .tex_w = w, + .tex_h = h, + .w = w, + .h = h, + }); + } + + GLSLF("color = fract(gl_FragCoord.y / 2) < 0.5\n"); + GLSLF(" ? texture(texture%d, texcoord%d)\n", ids[0], ids[0]); + GLSLF(" : texture(texture%d, texcoord%d);", ids[1], ids[1]); + + fbotex_change(fbo, p->gl, p->log, w, h * 2, n == 0 ? GL_R8 : GL_RG8, 0); + + finish_pass_direct(p, fbo->fbo, fbo->rw, fbo->rh, + &(struct mp_rect){0, 0, w, h * 2}); + + res.planes[n] = (struct gl_hwdec_plane){ + .gl_texture = fbo->texture, + .gl_target = GL_TEXTURE_2D, + .tex_w = w, + .tex_h = h * 2, + }; + } + *frame = res; +} + // Returns false on failure. static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi) { @@ -2943,6 +2989,8 @@ static bool gl_video_upload_image(struct gl_video *p, struct mp_image *mpi) if (ok) { struct mp_image layout = {0}; mp_image_set_params(&layout, &p->image_params); + if (gl_frame.vdpau_fields) + reinterleave_vdpau(p, &gl_frame); for (int n = 0; n < p->plane_count; n++) { struct gl_hwdec_plane *plane = &gl_frame.planes[n]; vimg->planes[n] = (struct texplane){ |