diff options
Diffstat (limited to 'video/out/opengl/hwdec_vdpau.c')
-rw-r--r-- | video/out/opengl/hwdec_vdpau.c | 155 |
1 files changed, 111 insertions, 44 deletions
diff --git a/video/out/opengl/hwdec_vdpau.c b/video/out/opengl/hwdec_vdpau.c index b1d49622fc..83f664a756 100644 --- a/video/out/opengl/hwdec_vdpau.c +++ b/video/out/opengl/hwdec_vdpau.c @@ -36,20 +36,35 @@ 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; }; +static void unmap(struct gl_hwdec *hw) +{ + struct priv *p = hw->priv; + GL *gl = hw->gl; + + 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; +} + static void mark_vdpau_objects_uninitialized(struct gl_hwdec *hw) { struct priv *p = hw->priv; p->vdp_surface = VDP_INVALID_HANDLE; - p->mixer->video_mixer = VDP_INVALID_HANDLE; p->mapped = false; } @@ -60,16 +75,15 @@ static void destroy_objects(struct gl_hwdec *hw) struct vdp_functions *vdp = &p->ctx->vdp; VdpStatus vdp_st; - if (p->mapped) - gl->VDPAUUnmapSurfacesNV(1, &p->vdpgl_surface); - p->mapped = false; + unmap(hw); if (p->vdpgl_surface) 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); @@ -77,14 +91,14 @@ static void destroy_objects(struct gl_hwdec *hw) } p->vdp_surface = VDP_INVALID_HANDLE; - glCheckError(gl, hw->log, "Before uninitializing OpenGL interop"); + gl_check_error(gl, hw->log, "Before uninitializing OpenGL interop"); if (p->vdpgl_initialized) gl->VDPAUFiniNV(); p->vdpgl_initialized = false; - glCheckError(gl, hw->log, "After uninitializing OpenGL interop"); + gl_check_error(gl, hw->log, "After uninitializing OpenGL interop"); } static void destroy(struct gl_hwdec *hw) @@ -93,14 +107,14 @@ static void destroy(struct gl_hwdec *hw) destroy_objects(hw); mp_vdpau_mixer_destroy(p->mixer); + if (p->ctx) + hwdec_devices_remove(hw->devs, &p->ctx->hwctx); mp_vdpau_destroy(p->ctx); } static int create(struct gl_hwdec *hw) { GL *gl = hw->gl; - if (hw->hwctx) - return -1; Display *x11disp = glXGetCurrentDisplay(); if (!x11disp) return -1; @@ -120,8 +134,8 @@ static int create(struct gl_hwdec *hw) destroy(hw); return -1; } - hw->hwctx = &p->ctx->hwctx; - hw->converted_imgfmt = IMGFMT_RGB0; + p->ctx->hwctx.driver_name = hw->driver->name; + hwdec_devices_add(hw->devs, &p->ctx->hwctx); return 0; } @@ -144,39 +158,50 @@ 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); + + params->imgfmt = IMGFMT_RGB0; + } - glCheckError(gl, hw->log, "After initializing vdpau OpenGL interop"); + gl_check_error(gl, hw->log, "After initializing vdpau OpenGL interop"); return 0; } -static int map_image(struct gl_hwdec *hw, struct mp_image *hw_image, - GLuint *out_textures) +static int map_frame(struct gl_hwdec *hw, struct mp_image *hw_image, + struct gl_hwdec_frame *out_frame) { struct priv *p = hw->priv; GL *gl = hw->gl; - - assert(hw_image && hw_image->imgfmt == IMGFMT_VDPAU); + struct vdp_functions *vdp = &p->ctx->vdp; + VdpStatus vdp_st; int pe = mp_vdpau_handle_preemption(p->ctx, &p->preemption_counter); if (pe < 1) { @@ -187,17 +212,58 @@ static int map_image(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]; - if (p->mapped) - gl->VDPAUUnmapSurfacesNV(1, &p->vdpgl_surface); + // 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"); + + p->vdpgl_surface = gl->VDPAURegisterVideoSurfaceNV(BRAINDEATH(surface), + GL_TEXTURE_2D, + 4, p->gl_textures); + if (!p->vdpgl_surface) + return -1; - mp_vdpau_mixer_render(p->mixer, NULL, p->vdp_surface, NULL, hw_image, NULL); + 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 = 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, + }, + }, + }; + } - gl->VDPAUMapSurfacesNV(1, &p->vdpgl_surface); - p->mapped = true; - out_textures[0] = p->gl_texture; return 0; } @@ -207,6 +273,7 @@ const struct gl_hwdec_driver gl_hwdec_vdpau = { .imgfmt = IMGFMT_VDPAU, .create = create, .reinit = reinit, - .map_image = map_image, + .map_frame = map_frame, + .unmap = unmap, .destroy = destroy, }; |