From 826a10255f5f8d444f0318f3e36ff616b41b5d15 Mon Sep 17 00:00:00 2001 From: "Kristian H. Kristensen" Date: Mon, 28 Sep 2020 20:11:18 +0000 Subject: [PATCH] st/mesa: Add NV12 lowering to PIPE_FORMAT_R8_G8B8_420_UNORM MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 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 Reviewed-by: Rob Clark Part-of: --- src/compiler/nir/nir.h | 1 + src/compiler/nir/nir_lower_tex.c | 21 ++++++++++++++++ src/gallium/frontends/dri/dri2.c | 18 ++++++++++++++ src/mesa/state_tracker/st_atom_sampler.c | 4 +++ src/mesa/state_tracker/st_atom_texture.c | 4 +++ src/mesa/state_tracker/st_cb_eglimage.c | 31 +++++++++++++++++++++--- src/mesa/state_tracker/st_program.c | 7 ++++-- src/mesa/state_tracker/st_program.h | 6 +++++ src/mesa/state_tracker/st_sampler_view.c | 5 ++++ 9 files changed, 92 insertions(+), 5 deletions(-) diff --git a/src/compiler/nir/nir.h b/src/compiler/nir/nir.h index 8ef95934e54..d7881d9251d 100644 --- a/src/compiler/nir/nir.h +++ b/src/compiler/nir/nir.h @@ -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; diff --git a/src/compiler/nir/nir_lower_tex.c b/src/compiler/nir/nir_lower_tex.c index 97521e51e7e..4f5e1805e8b 100644 --- a/src/compiler/nir/nir_lower_tex.c +++ b/src/compiler/nir/nir_lower_tex.c @@ -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; diff --git a/src/gallium/frontends/dri/dri2.c b/src/gallium/frontends/dri/dri2.c index aab9c8cca3c..40cf8ca352c 100644 --- a/src/gallium/frontends/dri/dri2.c +++ b/src/gallium/frontends/dri/dri2.c @@ -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. diff --git a/src/mesa/state_tracker/st_atom_sampler.c b/src/mesa/state_tracker/st_atom_sampler.c index 0d99eae6e61..a1158f7edc5 100644 --- a/src/mesa/state_tracker/st_atom_sampler.c +++ b/src/mesa/state_tracker/st_atom_sampler.c @@ -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: diff --git a/src/mesa/state_tracker/st_atom_texture.c b/src/mesa/state_tracker/st_atom_texture.c index f1f8dffcf2c..b3010c8c02b 100644 --- a/src/mesa/state_tracker/st_atom_texture.c +++ b/src/mesa/state_tracker/st_atom_texture.c @@ -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 */ diff --git a/src/mesa/state_tracker/st_cb_eglimage.c b/src/mesa/state_tracker/st_cb_eglimage.c index 8b44ba3e65a..a7b484ba38d 100644 --- a/src/mesa/state_tracker/st_cb_eglimage.c +++ b/src/mesa/state_tracker/st_cb_eglimage.c @@ -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: diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c index 2a80cb09b4e..d73b2776e90 100644 --- a/src/mesa/state_tracker/st_program.c +++ b/src/mesa/state_tracker/st_program.c @@ -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 || diff --git a/src/mesa/state_tracker/st_program.h b/src/mesa/state_tracker/st_program.h index 7fb94386ff9..40f5b673aa6 100644 --- a/src/mesa/state_tracker/st_program.h +++ b/src/mesa/state_tracker/st_program.h @@ -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: diff --git a/src/mesa/state_tracker/st_sampler_view.c b/src/mesa/state_tracker/st_sampler_view.c index 80ba82d9711..0a5773e8200 100644 --- a/src/mesa/state_tracker/st_sampler_view.c +++ b/src/mesa/state_tracker/st_sampler_view.c @@ -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;