diff options
Diffstat (limited to 'video/out/opengl/video.c')
-rw-r--r-- | video/out/opengl/video.c | 207 |
1 files changed, 125 insertions, 82 deletions
diff --git a/video/out/opengl/video.c b/video/out/opengl/video.c index 79807d072b..b78295b368 100644 --- a/video/out/opengl/video.c +++ b/video/out/opengl/video.c @@ -91,6 +91,7 @@ static const struct gl_vao_entry vertex_vao[] = { struct texplane { int w, h; + int tex_w, tex_h; GLint gl_internal_format; GLenum gl_target; bool use_integer; @@ -98,12 +99,14 @@ struct texplane { GLenum gl_type; GLuint gl_texture; int gl_buffer; + char swizzle[5]; }; struct video_image { struct texplane planes[4]; bool image_flipped; struct mp_image *mpi; // original input image + bool hwdec_mapped; }; enum plane_type { @@ -128,7 +131,7 @@ struct img_tex { int w, h; // logical size (with pre_transform applied) struct gl_transform pre_transform; // source texture space struct gl_transform transform; // rendering transformation - bool texture_la; // it's a GL_LUMINANCE_ALPHA texture (access with .ra not .rg) + char swizzle[5]; }; struct fbosurface { @@ -156,8 +159,6 @@ struct gl_video { struct gl_shader_cache *sc; - GLenum gl_target; // texture target (GL_TEXTURE_2D, ...) for video and FBOs - struct gl_vao vao; struct osd_state *osd_state; @@ -536,7 +537,8 @@ const struct m_sub_options gl_video_conf = { static void uninit_rendering(struct gl_video *p); static void uninit_scaler(struct gl_video *p, struct scaler *scaler); static void check_gl_features(struct gl_video *p); -static bool init_format(int fmt, struct gl_video *init); +static bool init_format(struct gl_video *p, int fmt, bool test_only); +static void init_image_desc(struct gl_video *p, int fmt); static void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi); static void assign_options(struct gl_video_opts *dst, struct gl_video_opts *src); static void get_scale_factors(struct gl_video *p, bool transpose_rot, double xy[2]); @@ -855,14 +857,14 @@ static void pass_get_img_tex(struct gl_video *p, struct video_image *vimg, .gl_target = t->gl_target, .multiplier = tex_mul, .use_integer = t->use_integer, - .tex_w = t->w, - .tex_h = t->h, + .tex_w = t->tex_w, + .tex_h = t->tex_h, .w = t->w, .h = t->h, .transform = type == PLANE_CHROMA ? chroma : identity_trans, .components = p->image_desc.components[n], - .texture_la = t->gl_format == GL_LUMINANCE_ALPHA, }; + snprintf(tex[n].swizzle, sizeof(tex[n].swizzle), "%s", t->swizzle); get_plane_source_transform(p, t->w, t->h, &tex[n].pre_transform); if (p->image_params.rotate % 180 == 90) MPSWAP(int, tex[n].w, tex[n].h); @@ -873,17 +875,15 @@ static void init_video(struct gl_video *p) { GL *gl = p->gl; - init_format(p->image_params.imgfmt, p); - p->gl_target = p->opts.use_rectangle ? GL_TEXTURE_RECTANGLE : GL_TEXTURE_2D; - check_gl_features(p); - if (p->hwdec_active) { + if (p->hwdec && p->hwdec->driver->imgfmt == p->image_params.imgfmt) { if (p->hwdec->driver->reinit(p->hwdec, &p->image_params) < 0) MP_ERR(p, "Initializing texture for hardware decoding failed.\n"); - init_format(p->image_params.imgfmt, p); - p->image_params.imgfmt = p->image_desc.id; - p->gl_target = p->hwdec->gl_texture_target; + init_image_desc(p, p->image_params.imgfmt); + p->hwdec_active = true; + } else { + init_format(p, p->image_params.imgfmt, false); } mp_image_params_guess_csp(&p->image_params); @@ -899,44 +899,61 @@ static void init_video(struct gl_video *p) debug_check_gl(p, "before video texture creation"); - struct video_image *vimg = &p->image; + if (!p->hwdec_active) { + struct video_image *vimg = &p->image; - struct mp_image layout = {0}; - mp_image_set_params(&layout, &p->image_params); + GLenum gl_target = + p->opts.use_rectangle ? GL_TEXTURE_RECTANGLE : GL_TEXTURE_2D; - for (int n = 0; n < p->plane_count; n++) { - struct texplane *plane = &vimg->planes[n]; + struct mp_image layout = {0}; + mp_image_set_params(&layout, &p->image_params); + + for (int n = 0; n < p->plane_count; n++) { + struct texplane *plane = &vimg->planes[n]; - plane->gl_target = p->gl_target; + plane->gl_target = gl_target; - plane->w = mp_image_plane_w(&layout, n); - plane->h = mp_image_plane_h(&layout, n); + plane->w = plane->tex_w = mp_image_plane_w(&layout, n); + plane->h = plane->tex_h = mp_image_plane_h(&layout, n); - if (!p->hwdec_active) { gl->ActiveTexture(GL_TEXTURE0 + n); gl->GenTextures(1, &plane->gl_texture); - gl->BindTexture(p->gl_target, plane->gl_texture); + gl->BindTexture(gl_target, plane->gl_texture); - gl->TexImage2D(p->gl_target, 0, plane->gl_internal_format, + gl->TexImage2D(gl_target, 0, plane->gl_internal_format, plane->w, plane->h, 0, plane->gl_format, plane->gl_type, NULL); int filter = plane->use_integer ? GL_NEAREST : GL_LINEAR; - gl->TexParameteri(p->gl_target, GL_TEXTURE_MIN_FILTER, filter); - gl->TexParameteri(p->gl_target, GL_TEXTURE_MAG_FILTER, filter); - gl->TexParameteri(p->gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); - gl->TexParameteri(p->gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - } + gl->TexParameteri(gl_target, GL_TEXTURE_MIN_FILTER, filter); + gl->TexParameteri(gl_target, GL_TEXTURE_MAG_FILTER, filter); + gl->TexParameteri(gl_target, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE); + gl->TexParameteri(gl_target, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE); - MP_VERBOSE(p, "Texture for plane %d: %dx%d\n", n, plane->w, plane->h); + MP_VERBOSE(p, "Texture for plane %d: %dx%d\n", n, plane->w, plane->h); + } + gl->ActiveTexture(GL_TEXTURE0); } - gl->ActiveTexture(GL_TEXTURE0); debug_check_gl(p, "after video texture creation"); reinit_rendering(p); } +static void unref_current_image(struct gl_video *p) +{ + struct video_image *vimg = &p->image; + + if (vimg->hwdec_mapped) { + assert(p->hwdec_active); + if (p->hwdec->driver->unmap) + p->hwdec->driver->unmap(p->hwdec); + memset(vimg->planes, 0, sizeof(vimg->planes)); + vimg->hwdec_mapped = false; + } + mp_image_unrefp(&vimg->mpi); +} + static void uninit_video(struct gl_video *p) { GL *gl = p->gl; @@ -945,21 +962,21 @@ static void uninit_video(struct gl_video *p) struct video_image *vimg = &p->image; + unref_current_image(p); + for (int n = 0; n < p->plane_count; n++) { struct texplane *plane = &vimg->planes[n]; - if (!p->hwdec_active) - gl->DeleteTextures(1, &plane->gl_texture); - plane->gl_texture = 0; + gl->DeleteTextures(1, &plane->gl_texture); gl->DeleteBuffers(1, &plane->gl_buffer); - plane->gl_buffer = 0; } - mp_image_unrefp(&vimg->mpi); + *vimg = (struct video_image){0}; // Invalidate image_params to ensure that gl_video_config() will call // init_video() on uninitialized gl_video. p->real_image_params = (struct mp_image_params){0}; p->image_params = p->real_image_params; + p->hwdec_active = false; } static void pass_prepare_src_tex(struct gl_video *p) @@ -1457,7 +1474,7 @@ static void copy_img_tex(struct gl_video *p, int *offset, struct img_tex img) int id = pass_bind(p, img); char src[5] = {0}; char dst[5] = {0}; - const char *tex_fmt = img.texture_la ? "ragg" : "rgba"; + const char *tex_fmt = img.swizzle[0] ? img.swizzle : "rgba"; const char *dst_fmt = "rgba"; for (int i = 0; i < count; i++) { src[i] = tex_fmt[i]; @@ -2531,18 +2548,34 @@ static void gl_video_upload_image(struct gl_video *p, struct mp_image *mpi) if (!mpi) abort(); - talloc_free(vimg->mpi); + unref_current_image(p); + vimg->mpi = mpi; p->osd_pts = mpi->pts; p->frames_uploaded++; if (p->hwdec_active) { - GLuint imgtex[4] = {0}; - bool ok = p->hwdec->driver->map_image(p->hwdec, vimg->mpi, imgtex) >= 0; - for (int n = 0; n < p->plane_count; n++) - vimg->planes[n].gl_texture = ok ? imgtex[n] : -1; - if (!ok) + struct gl_hwdec_frame gl_frame = {0}; + bool ok = p->hwdec->driver->map_frame(p->hwdec, vimg->mpi, &gl_frame) >= 0; + vimg->hwdec_mapped = true; + if (ok) { + struct mp_image layout = {0}; + mp_image_set_params(&layout, &p->image_params); + for (int n = 0; n < p->plane_count; n++) { + struct gl_hwdec_plane *plane = &gl_frame.planes[n]; + vimg->planes[n] = (struct texplane){ + .w = mp_image_plane_w(&layout, n), + .h = mp_image_plane_h(&layout, n), + .tex_w = plane->tex_w, + .tex_h = plane->tex_h, + .gl_target = plane->gl_target, + .gl_texture = plane->gl_texture, + }; + } + } else { MP_FATAL(p, "Mapping hardware decoded surface failed.\n"); + unref_current_image(p); + } return; } @@ -2860,15 +2893,24 @@ static const struct fmt_entry *find_plane_format(GL *gl, int bytes_per_comp, return &gl_ui_byte_formats_gles3[n_channels - 1 + (bytes_per_comp - 1) * 4]; } -static bool init_format(int fmt, struct gl_video *init) +static void init_image_desc(struct gl_video *p, int fmt) { - struct GL *gl = init->gl; + p->image_desc = mp_imgfmt_get_desc(fmt); - init->hwdec_active = false; - if (init->hwdec && init->hwdec->driver->imgfmt == fmt) { - fmt = init->hwdec->converted_imgfmt; - init->hwdec_active = true; - } + p->plane_count = p->image_desc.num_planes; + p->is_yuv = p->image_desc.flags & MP_IMGFLAG_YUV; + p->has_alpha = p->image_desc.flags & MP_IMGFLAG_ALPHA; + p->use_integer_conversion = false; + p->color_swizzle[0] = '\0'; + p->is_packed_yuv = fmt == IMGFMT_UYVY || fmt == IMGFMT_YUYV; + p->hwdec_active = false; +} + +// test_only=true checks if the format is supported +// test_only=false also initializes some rendering parameters accordingly +static bool init_format(struct gl_video *priv, int fmt, bool test_only) +{ + struct GL *gl = priv->gl; struct mp_imgfmt_desc desc = mp_imgfmt_get_desc(fmt); if (!desc.id) @@ -2878,21 +2920,18 @@ static bool init_format(int fmt, struct gl_video *init) return false; const struct fmt_entry *plane_format[4] = {0}; - - init->color_swizzle[0] = '\0'; - init->has_alpha = false; + char color_swizzle[5] = ""; // YUV/planar formats if (desc.flags & (MP_IMGFLAG_YUV_P | MP_IMGFLAG_RGB_P)) { int bits = desc.component_bits; if ((desc.flags & MP_IMGFLAG_NE) && bits >= 8 && bits <= 16) { - init->has_alpha = desc.num_planes > 3; plane_format[0] = find_plane_format(gl, (bits + 7) / 8, 1); for (int p = 1; p < desc.num_planes; p++) plane_format[p] = plane_format[0]; // RGB/planar if (desc.flags & MP_IMGFLAG_RGB_P) - snprintf(init->color_swizzle, sizeof(init->color_swizzle), "brga"); + snprintf(color_swizzle, sizeof(color_swizzle), "brga"); goto supported; } } @@ -2904,7 +2943,7 @@ static bool init_format(int fmt, struct gl_video *init) plane_format[0] = find_plane_format(gl, (bits + 7) / 8, 1); plane_format[1] = find_plane_format(gl, (bits + 7) / 8, 2); if (desc.flags & MP_IMGFLAG_YUV_NV_SWAP) - snprintf(init->color_swizzle, sizeof(init->color_swizzle), "rbga"); + snprintf(color_swizzle, sizeof(color_swizzle), "rbga"); goto supported; } } @@ -2928,19 +2967,16 @@ static bool init_format(int fmt, struct gl_video *init) if (e->fmt == fmt) { int n_comp = desc.bytes[0] / e->component_size; plane_format[0] = find_tex_format(gl, e->component_size, n_comp); - packed_fmt_swizzle(init->color_swizzle, plane_format[0], e); - init->has_alpha = e->components[3] != 0; + packed_fmt_swizzle(color_swizzle, plane_format[0], e); goto supported; } } // Packed YUV Apple formats - if (init->gl->mpgl_caps & MPGL_CAP_APPLE_RGB_422) { + if (priv->gl->mpgl_caps & MPGL_CAP_APPLE_RGB_422) { for (const struct fmt_entry *e = gl_apple_formats; e->mp_format; e++) { if (e->mp_format == fmt) { - init->is_packed_yuv = true; - snprintf(init->color_swizzle, sizeof(init->color_swizzle), - "gbra"); + snprintf(color_swizzle, sizeof(color_swizzle), "gbra"); plane_format[0] = e; goto supported; } @@ -2953,7 +2989,7 @@ static bool init_format(int fmt, struct gl_video *init) supported: if (desc.component_bits > 8 && desc.component_bits < 16) { - if (init->texture_16bit_depth < 16) + if (priv->texture_16bit_depth < 16) return false; } @@ -2967,32 +3003,40 @@ supported: if (use_integer != use_int_plane) return false; // mixed planes not supported } - init->use_integer_conversion = use_integer; - if (init->use_integer_conversion && init->forced_dumb_mode) + if (use_integer && priv->forced_dumb_mode) return false; - for (int p = 0; p < desc.num_planes; p++) { - struct texplane *plane = &init->image.planes[p]; - const struct fmt_entry *format = plane_format[p]; - assert(format); - plane->gl_format = format->format; - plane->gl_internal_format = format->internal_format; - plane->gl_type = format->type; - plane->use_integer = init->use_integer_conversion; - } + if (!test_only) { + for (int p = 0; p < desc.num_planes; p++) { + struct texplane *plane = &priv->image.planes[p]; + const struct fmt_entry *format = plane_format[p]; + assert(format); + plane->gl_format = format->format; + plane->gl_internal_format = format->internal_format; + plane->gl_type = format->type; + plane->use_integer = use_integer; + if (plane->gl_format == GL_LUMINANCE_ALPHA) + snprintf(plane->swizzle, sizeof(plane->swizzle), "raaa"); + } - init->is_yuv = desc.flags & MP_IMGFLAG_YUV; - init->plane_count = desc.num_planes; - init->image_desc = desc; + init_image_desc(priv, fmt); + + priv->use_integer_conversion = use_integer; + snprintf(priv->color_swizzle, sizeof(priv->color_swizzle), "%s", + color_swizzle); + } return true; } bool gl_video_check_format(struct gl_video *p, int mp_format) { - struct gl_video tmp = *p; - return init_format(mp_format, &tmp); + if (init_format(p, mp_format, true)) + return true; + if (p->hwdec && p->hwdec->driver->imgfmt == mp_format) + return true; + return false; } void gl_video_config(struct gl_video *p, struct mp_image_params *params) @@ -3033,7 +3077,6 @@ struct gl_video *gl_video_init(GL *gl, struct mp_log *log, struct mpv_global *g, .log = log, .cms = cms, .opts = gl_video_opts_def, - .gl_target = GL_TEXTURE_2D, .texture_16bit_depth = 16, .sc = gl_sc_create(gl, log), }; @@ -3241,5 +3284,5 @@ void gl_video_set_ambient_lux(struct gl_video *p, int lux) void gl_video_set_hwdec(struct gl_video *p, struct gl_hwdec *hwdec) { p->hwdec = hwdec; - mp_image_unrefp(&p->image.mpi); + unref_current_image(p); } |