vl,frontends/va: Implement YUV->YUV matrix coeff conversion

Use separate matrix for YUV->RGB and RGB->YUV conversions.

Acked-by: Ruijing Dong <ruijing.dong@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/37058>
This commit is contained in:
David Rosca 2025-09-05 12:16:02 +02:00 committed by Marge Bot
parent 6e8a8d8ee7
commit 5bc0df5aad
5 changed files with 77 additions and 26 deletions

View file

@ -888,7 +888,7 @@ vl_compositor_init_state(struct vl_compositor_state *s, struct pipe_context *pip
pipe->screen, pipe->screen,
PIPE_BIND_CONSTANT_BUFFER, PIPE_BIND_CONSTANT_BUFFER,
PIPE_USAGE_DEFAULT, PIPE_USAGE_DEFAULT,
sizeof(vl_csc_matrix) + 32 * sizeof(float) + 2 * sizeof(int) sizeof(vl_csc_matrix) * 2 + 32 * sizeof(float) + 2 * sizeof(int)
); );
if (!s->shader_params) if (!s->shader_params)

View file

@ -131,6 +131,8 @@ struct vl_compositor_state
struct vl_compositor_layer layers[VL_COMPOSITOR_MAX_LAYERS]; struct vl_compositor_layer layers[VL_COMPOSITOR_MAX_LAYERS];
bool interlaced; bool interlaced;
unsigned chroma_location; unsigned chroma_location;
vl_csc_matrix yuv2rgb;
vl_csc_matrix rgb2yuv;
vl_csc_matrix csc_matrix; vl_csc_matrix csc_matrix;
float luma_min, luma_max; float luma_min, luma_max;

View file

@ -55,7 +55,7 @@ struct cs_shader {
unsigned num_samplers; unsigned num_samplers;
nir_variable *samplers[3]; nir_variable *samplers[3];
nir_variable *image; nir_variable *image;
nir_def *params[11]; nir_def *params[14];
nir_def *fone; nir_def *fone;
nir_def *fzero; nir_def *fzero;
}; };
@ -66,6 +66,11 @@ enum coords_flags {
COORDS_CHROMA_OFFSET = 0x2, COORDS_CHROMA_OFFSET = 0x2,
}; };
enum color_conversion {
YUV2RGB,
RGB2YUV,
};
static nir_def *cs_create_shader(struct vl_compositor *c, struct cs_shader *s) static nir_def *cs_create_shader(struct vl_compositor *c, struct cs_shader *s)
{ {
/* /*
@ -77,7 +82,7 @@ static nir_def *cs_create_shader(struct vl_compositor *c, struct cs_shader *s)
layout (std140, binding = 0) uniform ubo layout (std140, binding = 0) uniform ubo
{ {
vec4 csc_mat[3]; // params[0-2] vec4 yuv2rgb[3]; // params[0-2]
float luma_min; // params[3].x float luma_min; // params[3].x
float luma_max; // params[3].y float luma_max; // params[3].y
vec2 chroma_offset; // params[3].zw vec2 chroma_offset; // params[3].zw
@ -88,6 +93,7 @@ static nir_def *cs_create_shader(struct vl_compositor *c, struct cs_shader *s)
vec2 chroma_clamp; // params[6].zw vec2 chroma_clamp; // params[6].zw
vec4 proj[3]; // params[7-8] vec4 proj[3]; // params[7-8]
vec4 chroma_proj[3]; // params[9-10] vec4 chroma_proj[3]; // params[9-10]
vec4 rgb2yuv[3]; // params[11-13]
}; };
void main() void main()
@ -246,13 +252,14 @@ static inline nir_def *cs_normalize(struct cs_shader *s, nir_def *src, unsigned
return nir_fdiv(b, src, div); return nir_fdiv(b, src, div);
} }
static inline nir_def *cs_color_space_conversion(struct cs_shader *s, nir_def *src, unsigned comp) static inline nir_def *cs_color_space_conversion(struct cs_shader *s, nir_def *src,
unsigned comp, enum color_conversion conversion)
{ {
/* /*
return dot(src, params[comp]); return dot(src, params[(conversion == RGB2YUV ? 11 : 0) + comp]);
*/ */
nir_builder *b = &s->b; nir_builder *b = &s->b;
return nir_fdot4(b, src, s->params[comp]); return nir_fdot4(b, src, s->params[(conversion == RGB2YUV ? 11 : 0) + comp]);
} }
static inline nir_def *cs_fetch_texel(struct cs_shader *s, nir_def *coords, unsigned sampler) static inline nir_def *cs_fetch_texel(struct cs_shader *s, nir_def *coords, unsigned sampler)
@ -335,7 +342,7 @@ static void *create_video_buffer_shader(struct vl_compositor *c)
nir_def *color = nir_vec4(b, col[0], col[1], col[2], s.fone); nir_def *color = nir_vec4(b, col[0], col[1], col[2], s.fone);
for (unsigned i = 0; i < 3; ++i) for (unsigned i = 0; i < 3; ++i)
col[i] = cs_color_space_conversion(&s, color, i); col[i] = cs_color_space_conversion(&s, color, i, YUV2RGB);
color = nir_vec4(b, col[0], col[1], col[2], alpha); color = nir_vec4(b, col[0], col[1], col[2], alpha);
cs_image_store(&s, cs_translate(&s, ipos), color); cs_image_store(&s, cs_translate(&s, ipos), color);
@ -352,19 +359,36 @@ static void *create_yuv_progressive_shader(struct vl_compositor *c, enum vl_comp
nir_builder *b = &s.b; nir_builder *b = &s.b;
nir_def *ipos = cs_create_shader(c, &s); nir_def *ipos = cs_create_shader(c, &s);
nir_def *pos = cs_tex_coords(&s, ipos, plane == VL_COMPOSITOR_PLANE_Y ? COORDS_LUMA : COORDS_CHROMA); nir_def *pos_luma = cs_tex_coords(&s, ipos, COORDS_LUMA);
nir_def *pos_chroma = cs_tex_coords(&s, ipos, COORDS_CHROMA |
(plane == VL_COMPOSITOR_PLANE_Y ? COORDS_CHROMA_OFFSET : 0));
nir_def *col[3];
for (unsigned i = 0; i < 3; i++)
col[i] = cs_fetch_texel(&s, i == 0 ? pos_luma : pos_chroma, i);
nir_def *color = nir_vec4(b, col[0], col[1], col[2], s.fone);
for (unsigned i = 0; i < 3; i++)
col[i] = cs_color_space_conversion(&s, color, i, YUV2RGB);
color = nir_vec4(b, col[0], col[1], col[2], s.fone);
for (unsigned i = 0; i < 3; i++)
col[i] = cs_color_space_conversion(&s, color, i, RGB2YUV);
color = nir_vec4(b, col[0], col[1], col[2], s.fone);
nir_def *color;
if (plane != VL_COMPOSITOR_PLANE_UV) { if (plane != VL_COMPOSITOR_PLANE_UV) {
unsigned c = 0; unsigned c = 0;
if (plane == VL_COMPOSITOR_PLANE_U) if (plane == VL_COMPOSITOR_PLANE_U)
c = 1; c = 1;
else if (plane == VL_COMPOSITOR_PLANE_V) else if (plane == VL_COMPOSITOR_PLANE_V)
c = 2; c = 2;
color = nir_channel(b, cs_fetch_texel(&s, pos, c), c); color = nir_channel(b, color, c);
} else { } else {
nir_def *col1 = cs_fetch_texel(&s, pos, 1); nir_def *col1 = nir_channel(b, color, 1);
nir_def *col2 = cs_fetch_texel(&s, pos, 2); nir_def *col2 = nir_channel(b, color, 2);
color = nir_vec2(b, col1, col2); color = nir_vec2(b, col1, col2);
} }
@ -439,10 +463,10 @@ static void *create_rgb_yuv_shader(struct vl_compositor *c, enum vl_compositor_p
c = 1; c = 1;
else if (plane == VL_COMPOSITOR_PLANE_V) else if (plane == VL_COMPOSITOR_PLANE_V)
c = 2; c = 2;
color = cs_color_space_conversion(&s, color, c); color = cs_color_space_conversion(&s, color, c, RGB2YUV);
} else { } else {
nir_def *col1 = cs_color_space_conversion(&s, color, 1); nir_def *col1 = cs_color_space_conversion(&s, color, 1, RGB2YUV);
nir_def *col2 = cs_color_space_conversion(&s, color, 2); nir_def *col2 = cs_color_space_conversion(&s, color, 2, RGB2YUV);
color = nir_vec2(b, col1, col2); color = nir_vec2(b, col1, col2);
} }
@ -560,7 +584,7 @@ static nir_def *create_weave_shader(struct vl_compositor *c, bool rgb, bool y)
if (rgb) { if (rgb) {
nir_def *alpha = cs_luma_key(&s, nir_channel(b, color, 2)); nir_def *alpha = cs_luma_key(&s, nir_channel(b, color, 2));
for (unsigned i = 0; i < 3; ++i) for (unsigned i = 0; i < 3; ++i)
col[i] = cs_color_space_conversion(&s, color, i); col[i] = cs_color_space_conversion(&s, color, i, YUV2RGB);
color = nir_vec4(b, col[0], col[1], col[2], alpha); color = nir_vec4(b, col[0], col[1], col[2], alpha);
} else if (y) { } else if (y) {
color = nir_channel(b, color, 0); color = nir_channel(b, color, 0);
@ -774,7 +798,7 @@ set_viewport(struct vl_compositor_state *s,
if (!ptr) if (!ptr)
return false; return false;
memcpy(ptr, &s->csc_matrix, sizeof(vl_csc_matrix)); memcpy(ptr, &s->yuv2rgb, sizeof(vl_csc_matrix));
float *ptr_float = (float *)ptr; float *ptr_float = (float *)ptr;
ptr_float += sizeof(vl_csc_matrix) / sizeof(float); ptr_float += sizeof(vl_csc_matrix) / sizeof(float);
@ -816,6 +840,9 @@ set_viewport(struct vl_compositor_state *s,
memcpy(ptr_float, drawn->proj, sizeof(drawn->proj)); memcpy(ptr_float, drawn->proj, sizeof(drawn->proj));
ptr_float += sizeof(drawn->proj) / sizeof(float); ptr_float += sizeof(drawn->proj) / sizeof(float);
memcpy(ptr_float, drawn->chroma_proj, sizeof(drawn->chroma_proj)); memcpy(ptr_float, drawn->chroma_proj, sizeof(drawn->chroma_proj));
ptr_float += sizeof(drawn->chroma_proj) / sizeof(float);
memcpy(ptr_float, &s->rgb2yuv, sizeof(vl_csc_matrix));
pipe_buffer_unmap(s->pipe, buf_transfer); pipe_buffer_unmap(s->pipe, buf_transfer);

View file

@ -58,7 +58,6 @@ vlVaPostProcCompositor(vlVaDriver *drv,
struct pipe_vpp_desc *param) struct pipe_vpp_desc *param)
{ {
struct pipe_surface *surfaces; struct pipe_surface *surfaces;
enum pipe_video_vpp_matrix_coefficients coeffs;
enum vl_compositor_rotation rotation; enum vl_compositor_rotation rotation;
enum vl_compositor_mirror mirror; enum vl_compositor_mirror mirror;
bool src_yuv = util_format_is_yuv(src->buffer_format); bool src_yuv = util_format_is_yuv(src->buffer_format);
@ -75,14 +74,37 @@ vlVaPostProcCompositor(vlVaDriver *drv,
if (!surfaces[0].texture) if (!surfaces[0].texture)
return VA_STATUS_ERROR_INVALID_SURFACE; return VA_STATUS_ERROR_INVALID_SURFACE;
if (src_yuv == dst_yuv || util_format_get_nr_components(src->buffer_format) == 1) if (util_format_get_nr_components(src->buffer_format) == 1) {
coeffs = PIPE_VIDEO_VPP_MCF_RGB; /* identity */ /* Identity */
else vl_csc_get_rgbyuv_matrix(PIPE_VIDEO_VPP_MCF_RGB, src->buffer_format, dst->buffer_format,
coeffs = src_yuv ? param->in_matrix_coefficients : param->out_matrix_coefficients; param->in_color_range, param->out_color_range, &drv->cstate.yuv2rgb);
vl_csc_get_rgbyuv_matrix(PIPE_VIDEO_VPP_MCF_RGB, src->buffer_format, dst->buffer_format,
param->in_color_range, param->out_color_range, &drv->cstate.rgb2yuv);
} else if (src_yuv == dst_yuv) {
if (!src_yuv) {
/* RGB to RGB */
vl_csc_get_rgbyuv_matrix(PIPE_VIDEO_VPP_MCF_RGB, src->buffer_format, dst->buffer_format,
param->in_color_range, param->out_color_range, &drv->cstate.yuv2rgb);
} else {
/* YUV to YUV (convert to RGB for transfer function and primaries) */
enum pipe_format rgb_format = PIPE_FORMAT_B8G8R8A8_UNORM;
vl_csc_get_rgbyuv_matrix(param->in_matrix_coefficients, src->buffer_format, rgb_format,
param->in_color_range, PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_FULL,
&drv->cstate.yuv2rgb);
vl_csc_get_rgbyuv_matrix(param->out_matrix_coefficients, rgb_format, dst->buffer_format,
PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_FULL, param->out_color_range,
&drv->cstate.rgb2yuv);
}
} else if (src_yuv) {
/* YUV to RGB */
vl_csc_get_rgbyuv_matrix(param->in_matrix_coefficients, src->buffer_format, dst->buffer_format,
param->in_color_range, param->out_color_range, &drv->cstate.yuv2rgb);
} else {
/* RGB to YUV */
vl_csc_get_rgbyuv_matrix(param->out_matrix_coefficients, src->buffer_format, dst->buffer_format,
param->in_color_range, param->out_color_range, &drv->cstate.rgb2yuv);
}
vl_csc_get_rgbyuv_matrix(coeffs, src->buffer_format, dst->buffer_format,
param->in_color_range, param->out_color_range, &drv->csc);
vl_compositor_set_csc_matrix(&drv->cstate, &drv->csc, 1.0f, 0.0f);
if (src_yuv || dst_yuv) { if (src_yuv || dst_yuv) {
enum pipe_format format = src_yuv ? src->buffer_format : dst->buffer_format; enum pipe_format format = src_yuv ? src->buffer_format : dst->buffer_format;

View file

@ -402,7 +402,7 @@ vlVaPutSurface(VADriverContextP ctx, VASurfaceID surface_id, void* draw, short s
vl_csc_get_rgbyuv_matrix(coeffs, format, surf_templ.format, vl_csc_get_rgbyuv_matrix(coeffs, format, surf_templ.format,
PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_REDUCED, PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_REDUCED,
PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_FULL, &drv->cstate.csc_matrix); PIPE_VIDEO_VPP_CHROMA_COLOR_RANGE_FULL, &drv->cstate.yuv2rgb);
vl_compositor_clear_layers(&drv->cstate); vl_compositor_clear_layers(&drv->cstate);