st/mesa: Add NV12 lowering to PIPE_FORMAT_R8_G8B8_420_UNORM

Some GPUs can sample biplanar formats like NV12 natively, returning
the YUV values. Add a lowering type that uses that for sampling and
relies on existing colorspace conversions.

Reviewed-by: Marek Olšák <marek.olsak@amd.com>
Reviewed-by: Rob Clark <robdclark@chromium.org>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/6693>
This commit is contained in:
Kristian H. Kristensen 2020-09-28 20:11:18 +00:00 committed by Marge Bot
parent e23bcb69c3
commit 826a10255f
9 changed files with 92 additions and 5 deletions

View File

@ -4489,6 +4489,7 @@ typedef struct nir_lower_tex_options {
unsigned lower_xy_uxvx_external;
unsigned lower_ayuv_external;
unsigned lower_xyuv_external;
unsigned lower_yuv_external;
unsigned bt709_external;
unsigned bt2020_external;

View File

@ -427,6 +427,22 @@ lower_xyuv_external(nir_builder *b, nir_tex_instr *tex,
options);
}
static void
lower_yuv_external(nir_builder *b, nir_tex_instr *tex,
const nir_lower_tex_options *options)
{
b->cursor = nir_after_instr(&tex->instr);
nir_ssa_def *yuv = sample_plane(b, tex, 0, options);
convert_yuv_to_rgb(b, tex,
nir_channel(b, yuv, 0),
nir_channel(b, yuv, 1),
nir_channel(b, yuv, 2),
nir_imm_float(b, 1.0f),
options);
}
/*
* Converts a nir_texop_txd instruction to nir_texop_txl with the given lod
* computed from the gradients.
@ -1062,6 +1078,11 @@ nir_lower_tex_block(nir_block *block, nir_builder *b,
progress = true;
}
if ((1 << tex->texture_index) & options->lower_yuv_external) {
lower_yuv_external(b, tex, options);
progress = true;
}
if (sat_mask) {
saturate_src(b, tex, sat_mask);
progress = true;

View File

@ -726,6 +726,16 @@ dri2_update_tex_buffer(struct dri_drawable *drawable,
/* no-op */
}
static const struct dri2_format_mapping r8_g8b8_mapping = {
DRM_FORMAT_NV12,
__DRI_IMAGE_FORMAT_NONE,
__DRI_IMAGE_COMPONENTS_Y_UV,
PIPE_FORMAT_R8_G8B8_420_UNORM,
2,
{ { 0, 0, 0, __DRI_IMAGE_FORMAT_R8, 1 },
{ 1, 1, 1, __DRI_IMAGE_FORMAT_GR88, 2 } }
};
static __DRIimage *
dri2_create_image_from_winsys(__DRIscreen *_screen,
int width, int height, const struct dri2_format_mapping *map,
@ -748,6 +758,14 @@ dri2_create_image_from_winsys(__DRIscreen *_screen,
PIPE_BIND_SAMPLER_VIEW))
tex_usage |= PIPE_BIND_SAMPLER_VIEW;
/* For NV12, see if we have support for sampling r8_b8g8 */
if (!tex_usage && map->pipe_format == PIPE_FORMAT_NV12 &&
pscreen->is_format_supported(pscreen, PIPE_FORMAT_R8_G8B8_420_UNORM,
screen->target, 0, 0, PIPE_BIND_SAMPLER_VIEW)) {
map = &r8_g8b8_mapping;
tex_usage |= PIPE_BIND_SAMPLER_VIEW;
}
if (!tex_usage && util_format_is_yuv(map->pipe_format)) {
/* YUV format sampling can be emulated by the GL gallium frontend by
* using multiple samplers of varying formats.

View File

@ -315,6 +315,10 @@ update_shader_samplers(struct st_context *st,
switch (st_get_view_format(stObj)) {
case PIPE_FORMAT_NV12:
if (stObj->pt->format == PIPE_FORMAT_R8_G8B8_420_UNORM)
/* no additional views needed */
break;
/* fallthrough */
case PIPE_FORMAT_P010:
case PIPE_FORMAT_P012:
case PIPE_FORMAT_P016:

View File

@ -188,6 +188,10 @@ update_textures(struct st_context *st,
switch (st_get_view_format(stObj)) {
case PIPE_FORMAT_NV12:
if (stObj->pt->format == PIPE_FORMAT_R8_G8B8_420_UNORM)
/* no additional views needed */
break;
/* we need one additional R8G8 view: */
tmpl.format = PIPE_FORMAT_RG88_UNORM;
tmpl.swizzle_g = PIPE_SWIZZLE_Y; /* tmpl from Y plane is R8 */

View File

@ -113,6 +113,25 @@ is_format_supported(struct pipe_screen *screen, enum pipe_format format,
return supported;
}
static bool
is_nv12_as_r8_g8b8_supported(struct pipe_screen *screen, struct st_egl_image *out,
unsigned usage, bool *native_supported)
{
if (out->format == PIPE_FORMAT_NV12 &&
out->texture->format == PIPE_FORMAT_R8_G8B8_420_UNORM &&
screen->is_format_supported(screen, PIPE_FORMAT_R8_G8B8_420_UNORM,
PIPE_TEXTURE_2D,
out->texture->nr_samples,
out->texture->nr_storage_samples,
usage)) {
*native_supported = false;
return true;
}
return false;
}
/**
* Return the gallium texture of an EGLImage.
*/
@ -136,7 +155,8 @@ st_get_egl_image(struct gl_context *ctx, GLeglImageOES image_handle,
return false;
}
if (!is_format_supported(screen, out->format, out->texture->nr_samples,
if (!is_nv12_as_r8_g8b8_supported(screen, out, usage, native_supported) &&
!is_format_supported(screen, out->format, out->texture->nr_samples,
out->texture->nr_storage_samples, usage,
native_supported)) {
/* unable to specify a texture object using the specified EGL image */
@ -249,8 +269,13 @@ st_bind_egl_image(struct gl_context *ctx,
if (!native_supported) {
switch (stimg->format) {
case PIPE_FORMAT_NV12:
texFormat = MESA_FORMAT_R_UNORM8;
texObj->RequiredTextureImageUnits = 2;
if (stimg->texture->format == PIPE_FORMAT_R8_G8B8_420_UNORM) {
texFormat = MESA_FORMAT_R8G8B8X8_UNORM;
texObj->RequiredTextureImageUnits = 1;
} else {
texFormat = MESA_FORMAT_R_UNORM8;
texObj->RequiredTextureImageUnits = 2;
}
break;
case PIPE_FORMAT_P010:
case PIPE_FORMAT_P012:

View File

@ -1320,7 +1320,8 @@ st_create_fp_variant(struct st_context *st,
if (unlikely(key->external.lower_nv12 || key->external.lower_iyuv ||
key->external.lower_xy_uxvx || key->external.lower_yx_xuxv ||
key->external.lower_ayuv || key->external.lower_xyuv)) {
key->external.lower_ayuv || key->external.lower_xyuv ||
key->external.lower_yuv)) {
st_nir_lower_samplers(pipe->screen, state.ir.nir,
stfp->shader_program, &stfp->Base);
@ -1332,6 +1333,7 @@ st_create_fp_variant(struct st_context *st,
options.lower_yx_xuxv_external = key->external.lower_yx_xuxv;
options.lower_ayuv_external = key->external.lower_ayuv;
options.lower_xyuv_external = key->external.lower_xyuv;
options.lower_yuv_external = key->external.lower_yuv;
NIR_PASS_V(state.ir.nir, nir_lower_tex, &options);
finalize = true;
}
@ -1344,7 +1346,8 @@ st_create_fp_variant(struct st_context *st,
/* This pass needs to happen *after* nir_lower_sampler */
if (unlikely(key->external.lower_nv12 || key->external.lower_iyuv ||
key->external.lower_xy_uxvx || key->external.lower_yx_xuxv ||
key->external.lower_ayuv || key->external.lower_xyuv)) {
key->external.lower_ayuv || key->external.lower_xyuv ||
key->external.lower_yuv)) {
NIR_PASS_V(state.ir.nir, st_nir_lower_tex_src_plane,
~stfp->Base.SamplersUsed,
key->external.lower_nv12 || key->external.lower_xy_uxvx ||

View File

@ -57,6 +57,7 @@ struct st_external_sampler_key
GLuint lower_yx_xuxv; /**< bitmask of 2 plane YUV samplers */
GLuint lower_ayuv;
GLuint lower_xyuv;
GLuint lower_yuv;
};
static inline struct st_external_sampler_key
@ -79,6 +80,11 @@ st_get_external_sampler_key(struct st_context *st, struct gl_program *prog)
switch (format) {
case PIPE_FORMAT_NV12:
if (stObj->pt->format == PIPE_FORMAT_R8_G8B8_420_UNORM) {
key.lower_yuv |= (1 << unit);
break;
}
/* fallthrough */
case PIPE_FORMAT_P010:
case PIPE_FORMAT_P012:
case PIPE_FORMAT_P016:

View File

@ -496,6 +496,11 @@ get_sampler_view_format(struct st_context *st,
/* Use R8_UNORM for video formats */
switch (format) {
case PIPE_FORMAT_NV12:
if (stObj->pt->format == PIPE_FORMAT_R8_G8B8_420_UNORM) {
format = PIPE_FORMAT_R8_G8B8_420_UNORM;
break;
}
/* fallthrough */
case PIPE_FORMAT_IYUV:
format = PIPE_FORMAT_R8_UNORM;
break;