Skip to content
Snippets Groups Projects
Commit 70509c8a authored by Romain Vimont's avatar Romain Vimont Committed by Hugo Beauzée-Luyssen
Browse files

opengl: render YUY2 at full definition

Some YUV 4:2:2 formats are packed: two consecutive pixels are stored
using 4 values (for example [Y1 U Y2 V]).

But in OpenGL we cannot have both:
 - a single texture, and
 - a correct native interpolation for both Y and UV components.

To avoid the problem, the current implementation just dropped the Y2
value, so the pictures were rendered at half the horizontal resolution.

To render at full definition, upload the single plane into two separate
OpenGL textures:
 - one in GL_RG, to read each Y value in a different texel;
 - one in GL_RGBA, to read both U and V values in a single texel.

As a consequence, pic->i_planes is not necessarily equal to
interop->tex_count anymore (there might be 1 picture plane but 2
textures).

Fixes #26712
parent cf0b7fcb
No related branches found
No related tags found
1 merge request!1602opengl: render YUY2 at full definition
Pipeline #202656 passed with stages
in 35 minutes and 49 seconds
......@@ -276,20 +276,18 @@ interop_yuv_base_init(struct vlc_gl_interop *interop, GLenum tex_target,
else if (desc->plane_count == 1)
{
/* Only YUV 4:2:2 formats */
/* Y1 U Y2 V fits in R G B A */
interop->tex_count = 1;
/* The pictures have only 1 plane, but it is uploaded twice, once to
* access the Y components, once to access the UV components. See
* #26712. */
interop->tex_count = 2;
interop->texs[0] = (struct vlc_gl_tex_cfg) {
{ desc->p[0].w.num, desc->p[0].w.den },
{ desc->p[0].h.num, desc->p[0].h.den },
{ 1, 1 }, { 1, 1 },
twoplanes_texfmt, twoplanes_texfmt, GL_UNSIGNED_BYTE
};
interop->texs[1] = (struct vlc_gl_tex_cfg) {
{ 1, 2 }, { 1, 1 },
GL_RGBA, GL_RGBA, GL_UNSIGNED_BYTE
};
/*
* Currently, Y2 is ignored, so the texture is stored at chroma
* resolution. In other words, half the horizontal resolution is lost,
* so we must adapt the horizontal scaling.
*/
DivideRationalByTwo(&interop->texs[0].w);
}
else
return VLC_EGENERIC;
......
......@@ -111,7 +111,7 @@ pbo_picture_create(const struct vlc_gl_interop *interop)
}
assert(pic->i_planes > 0
&& (unsigned) pic->i_planes == interop->tex_count);
&& (unsigned) pic->i_planes <= interop->tex_count);
for (int i = 0; i < pic->i_planes; ++i)
{
......@@ -208,6 +208,18 @@ tc_pbo_update(const struct vlc_gl_interop *interop, uint32_t textures[],
priv->gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
if (pic->i_planes == 1 && interop->tex_count == 2)
{
/* For YUV 4:2:2 formats, a single plane is uploaded into 2 textures */
priv->gl.ActiveTexture(GL_TEXTURE1);
priv->gl.BindTexture(interop->tex_target, textures[1]);
priv->gl.PixelStorei(GL_UNPACK_ROW_LENGTH, pic->p[0].i_pitch
* tex_width[1] / (pic->p[0].i_visible_pitch ? pic->p[0].i_visible_pitch : 1));
priv->gl.TexSubImage2D(interop->tex_target, 0, 0, 0, tex_width[1], tex_height[1],
interop->texs[1].format, interop->texs[1].type, NULL);
priv->gl.PixelStorei(GL_UNPACK_ROW_LENGTH, 0);
}
/* turn off pbo */
priv->gl.BindBuffer(GL_PIXEL_UNPACK_BUFFER, 0);
......@@ -294,7 +306,7 @@ tc_common_update(const struct vlc_gl_interop *interop, uint32_t textures[],
{
const struct priv *priv = interop->priv;
int ret = VLC_SUCCESS;
for (unsigned i = 0; i < interop->tex_count && ret == VLC_SUCCESS; i++)
for (int i = 0; i < pic->i_planes && ret == VLC_SUCCESS; i++)
{
assert(textures[i] != 0);
priv->gl.ActiveTexture(GL_TEXTURE0 + i);
......@@ -306,6 +318,21 @@ tc_common_update(const struct vlc_gl_interop *interop, uint32_t textures[],
ret = upload_plane(interop, i, tex_width[i], tex_height[i],
pic->p[i].i_pitch, pic->p[i].i_visible_pitch, pixels);
}
if (pic->i_planes == 1 && interop->tex_count == 2)
{
/* For YUV 4:2:2 formats, a single plane is uploaded into 2 textures */
assert(textures[1] != 0);
priv->gl.ActiveTexture(GL_TEXTURE1);
priv->gl.BindTexture(interop->tex_target, textures[1]);
const void *pixels = plane_offset != NULL ?
&pic->p[0].p_pixels[plane_offset[0]] :
pic->p[0].p_pixels;
ret = upload_plane(interop, 1, tex_width[1], tex_height[1],
pic->p[0].i_pitch, pic->p[0].i_visible_pitch, pixels);
}
return ret;
}
......
......@@ -449,6 +449,8 @@ opengl_init_swizzle(struct vlc_gl_sampler *sampler,
else if (desc->plane_count == 1)
{
/*
* One plane, but uploaded into two separate textures for Y and UV.
*
* Set swizzling in Y1 U V order
* R G B A
* U Y1 V Y2 => GRB
......@@ -459,16 +461,20 @@ opengl_init_swizzle(struct vlc_gl_sampler *sampler,
switch (chroma)
{
case VLC_CODEC_UYVY:
swizzle_per_tex[0] = "grb";
swizzle_per_tex[0] = "g";
swizzle_per_tex[1] = "rb";
break;
case VLC_CODEC_YUYV:
swizzle_per_tex[0] = "rga";
swizzle_per_tex[0] = "r";
swizzle_per_tex[1] = "ga";
break;
case VLC_CODEC_VYUY:
swizzle_per_tex[0] = "gbr";
swizzle_per_tex[0] = "g";
swizzle_per_tex[1] = "br";
break;
case VLC_CODEC_YVYU:
swizzle_per_tex[0] = "rag";
swizzle_per_tex[0] = "r";
swizzle_per_tex[1] = "ag";
break;
default:
assert(!"missing chroma");
......@@ -636,8 +642,7 @@ opengl_fragment_shader_init(struct vlc_gl_sampler *sampler, bool expose_planes)
if (desc == NULL)
return VLC_EGENERIC;
unsigned tex_count = desc->plane_count;
assert(tex_count == glfmt->tex_count);
unsigned tex_count = glfmt->tex_count;
if (expose_planes)
return sampler_planes_init(sampler);
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment