[Mesa-dev] [RFC 2/2] mesa/st: support lowering multi-planar YUV

Marek Olšák maraeo at gmail.com
Mon Sep 5 16:52:09 UTC 2016


On Fri, Sep 2, 2016 at 9:45 PM, Rob Clark <robdclark at gmail.com> wrote:
> Support multi-planar YUV for external EGLImage's (currently just in the
> dma-buf import path) by lowering to multiple texture fetch's for each
> plane and CSC in shader.
>
> Currently lots of TODO's, only NV12 implemented so far, only wired up in
> frag shader, etc, etc..
> ---
>  src/gallium/auxiliary/util/u_inlines.h      |   4 +-
>  src/gallium/include/pipe/p_state.h          |   9 +++
>  src/gallium/include/state_tracker/st_api.h  |   3 +
>  src/gallium/state_trackers/dri/dri2.c       | 111 ++++++++++++++++++++++------
>  src/gallium/state_trackers/dri/dri_screen.c |  11 +++
>  src/mesa/main/mtypes.h                      |  16 ++++
>  src/mesa/program/ir_to_mesa.cpp             |   1 +
>  src/mesa/state_tracker/st_atom_sampler.c    |  52 ++++++++++++-
>  src/mesa/state_tracker/st_atom_shader.c     |  27 +++++++
>  src/mesa/state_tracker/st_atom_texture.c    |  71 +++++++++++++++++-
>  src/mesa/state_tracker/st_cb_eglimage.c     |  18 +++++
>  src/mesa/state_tracker/st_context.c         |  10 ++-
>  src/mesa/state_tracker/st_glsl_to_nir.cpp   |   1 +
>  src/mesa/state_tracker/st_glsl_to_tgsi.cpp  |   4 +
>  src/mesa/state_tracker/st_manager.c         |   1 +
>  src/mesa/state_tracker/st_program.c         |  18 +++++
>  src/mesa/state_tracker/st_program.h         |   3 +
>  17 files changed, 330 insertions(+), 30 deletions(-)
>
> diff --git a/src/gallium/auxiliary/util/u_inlines.h b/src/gallium/auxiliary/util/u_inlines.h
> index c2a0b08..b7b8313 100644
> --- a/src/gallium/auxiliary/util/u_inlines.h
> +++ b/src/gallium/auxiliary/util/u_inlines.h
> @@ -136,8 +136,10 @@ pipe_resource_reference(struct pipe_resource **ptr, struct pipe_resource *tex)
>     struct pipe_resource *old_tex = *ptr;
>
>     if (pipe_reference_described(&(*ptr)->reference, &tex->reference,
> -                                (debug_reference_descriptor)debug_describe_resource))
> +                                (debug_reference_descriptor)debug_describe_resource)) {
> +      pipe_resource_reference(&old_tex->next, NULL);
>        old_tex->screen->resource_destroy(old_tex->screen, old_tex);
> +   }
>     *ptr = tex;
>  }
>
> diff --git a/src/gallium/include/pipe/p_state.h b/src/gallium/include/pipe/p_state.h
> index ebd0337..4a88da6 100644
> --- a/src/gallium/include/pipe/p_state.h
> +++ b/src/gallium/include/pipe/p_state.h
> @@ -498,6 +498,15 @@ struct pipe_resource
>
>     unsigned bind;            /**< bitmask of PIPE_BIND_x */
>     unsigned flags;           /**< bitmask of PIPE_RESOURCE_FLAG_x */
> +
> +   /**
> +    * For planar images, ie. YUV EGLImage external, etc, pointer to the
> +    * next plane.
> +    *
> +    * TODO might be useful for dealing w/ z32s8 too, since at least a
> +    * couple drivers split these out into separate buffers internally.
> +    */
> +   struct pipe_resource *next;

I'm not a fan of this but I don't have a better idea.

>  };
>
>
> diff --git a/src/gallium/include/state_tracker/st_api.h b/src/gallium/include/state_tracker/st_api.h
> index 21d5177..06abfc5 100644
> --- a/src/gallium/include/state_tracker/st_api.h
> +++ b/src/gallium/include/state_tracker/st_api.h
> @@ -200,6 +200,9 @@ struct st_egl_image
>     /* this is owned by the caller */
>     struct pipe_resource *texture;
>
> +   /* format only differs from texture->format for multi-planar (YUV): */
> +   enum pipe_format format;
> +
>     unsigned level;
>     unsigned layer;
>  };
> diff --git a/src/gallium/state_trackers/dri/dri2.c b/src/gallium/state_trackers/dri/dri2.c
> index fdab499..91eabc8 100644
> --- a/src/gallium/state_trackers/dri/dri2.c
> +++ b/src/gallium/state_trackers/dri/dri2.c
> @@ -83,6 +83,20 @@ static int convert_fourcc(int format, int *dri_components_p)
>        format = __DRI_IMAGE_FORMAT_GR88;
>        dri_components = __DRI_IMAGE_COMPONENTS_RG;
>        break;
> +   /*
> +    * For multi-planar YUV formats, we return the format of the first
> +    * plane only.  Since there is only one caller which supports multi-
> +    * planar YUV it gets to figure out the remaining planes on it's
> +    * own.
> +    */
> +   case __DRI_IMAGE_FOURCC_YUV420:
> +      format = __DRI_IMAGE_FORMAT_R8;
> +      dri_components = __DRI_IMAGE_COMPONENTS_Y_U_V;
> +      break;
> +   case __DRI_IMAGE_FOURCC_NV12:
> +      format = __DRI_IMAGE_FORMAT_R8;
> +      dri_components = __DRI_IMAGE_COMPONENTS_Y_UV;
> +      break;
>     default:
>        return -1;
>     }
> @@ -90,6 +104,11 @@ static int convert_fourcc(int format, int *dri_components_p)
>     return format;
>  }
>
> +/* NOTE this probably isn't going to do the right thing for YUV images
> + * (but I think the same can be said for intel_query_image()).  I think
> + * only needed for exporting dmabuf's, so I think I won't loose much
> + * sleep over it.
> + */
>  static int convert_to_fourcc(int format)
>  {
>     switch(format) {
> @@ -762,14 +781,16 @@ dri2_lookup_egl_image(struct dri_screen *screen, void *handle)
>  static __DRIimage *
>  dri2_create_image_from_winsys(__DRIscreen *_screen,
>                                int width, int height, int format,
> -                              struct winsys_handle *whandle,
> +                              int num_handles, struct winsys_handle *whandle,
>                                void *loaderPrivate)
>  {
>     struct dri_screen *screen = dri_screen(_screen);
> +   struct pipe_screen *pscreen = screen->base.screen;
>     __DRIimage *img;
>     struct pipe_resource templ;
>     unsigned tex_usage;
>     enum pipe_format pf;
> +   int i;
>
>     tex_usage = PIPE_BIND_RENDER_TARGET | PIPE_BIND_SAMPLER_VIEW;
>
> @@ -783,19 +804,47 @@ dri2_create_image_from_winsys(__DRIscreen *_screen,
>
>     memset(&templ, 0, sizeof(templ));
>     templ.bind = tex_usage;
> -   templ.format = pf;
>     templ.target = screen->target;
>     templ.last_level = 0;
> -   templ.width0 = width;
> -   templ.height0 = height;
>     templ.depth0 = 1;
>     templ.array_size = 1;
>
> -   img->texture = screen->base.screen->resource_from_handle(screen->base.screen,
> -         &templ, whandle, PIPE_HANDLE_USAGE_READ_WRITE);
> -   if (!img->texture) {
> -      FREE(img);
> -      return NULL;
> +   for (i = num_handles - 1; i >= 0; i--) {
> +      struct pipe_resource *tex;
> +
> +      /* TODO: something a lot less ugly */
> +      switch (i) {
> +      case 0:
> +         templ.width0 = width;
> +         templ.height0 = height;
> +         templ.format = pf;
> +         break;
> +      case 1:
> +         templ.width0 = width / 2;
> +         templ.height0 = height / 2;
> +         templ.format = (num_handles == 2) ?
> +               PIPE_FORMAT_RG88_UNORM :   /* NV12, etc */
> +               PIPE_FORMAT_R8_UNORM;      /* I420, etc */
> +         break;
> +      case 2:
> +         templ.width0 = width / 2;
> +         templ.height0 = height / 2;
> +         templ.format = PIPE_FORMAT_R8_UNORM;
> +         break;
> +      default:
> +         unreachable("too many planes!");
> +      }
> +
> +      tex = pscreen->resource_from_handle(pscreen,
> +            &templ, &whandle[i], PIPE_HANDLE_USAGE_READ_WRITE);
> +      if (!tex) {
> +         pipe_resource_reference(&img->texture, NULL);
> +         FREE(img);
> +         return NULL;
> +      }
> +
> +      tex->next = img->texture;
> +      img->texture = tex;
>     }
>
>     img->level = 0;
> @@ -826,7 +875,7 @@ dri2_create_image_from_name(__DRIscreen *_screen,
>     whandle.stride = pitch * util_format_get_blocksize(pf);
>
>     return dri2_create_image_from_winsys(_screen, width, height, format,
> -                                        &whandle, loaderPrivate);
> +                                        1, &whandle, loaderPrivate);
>  }
>
>  static __DRIimage *
> @@ -836,12 +885,25 @@ dri2_create_image_from_fd(__DRIscreen *_screen,
>                            int *offsets, unsigned *error,
>                            int *dri_components, void *loaderPrivate)
>  {
> -   struct winsys_handle whandle;
> +   struct winsys_handle whandles[3];
>     int format;
>     __DRIimage *img = NULL;
>     unsigned err = __DRI_IMAGE_ERROR_SUCCESS;
> +   int expected_num_fds, i;
>
> -   if (num_fds != 1) {
> +   switch (fourcc) {
> +   case __DRI_IMAGE_FOURCC_YUV420:
> +      expected_num_fds = 3;
> +      break;
> +   case __DRI_IMAGE_FOURCC_NV12:
> +      expected_num_fds = 2;
> +      break;
> +   default:
> +      expected_num_fds = 1;
> +      break;
> +   }
> +
> +   if (num_fds != expected_num_fds) {
>        err = __DRI_IMAGE_ERROR_BAD_MATCH;
>        goto exit;
>     }
> @@ -852,19 +914,22 @@ dri2_create_image_from_fd(__DRIscreen *_screen,
>        goto exit;
>     }
>
> -   if (fds[0] < 0) {
> -      err = __DRI_IMAGE_ERROR_BAD_ALLOC;
> -      goto exit;
> -   }
> +   memset(whandles, 0, sizeof(whandles));
>
> -   memset(&whandle, 0, sizeof(whandle));
> -   whandle.type = DRM_API_HANDLE_TYPE_FD;
> -   whandle.handle = (unsigned)fds[0];
> -   whandle.stride = (unsigned)strides[0];
> -   whandle.offset = (unsigned)offsets[0];
> +   for (i = 0; i < num_fds; i++) {
> +      if (fds[i] < 0) {
> +         err = __DRI_IMAGE_ERROR_BAD_ALLOC;
> +         goto exit;
> +      }
> +
> +      whandles[i].type = DRM_API_HANDLE_TYPE_FD;
> +      whandles[i].handle = (unsigned)fds[i];
> +      whandles[i].stride = (unsigned)strides[i];
> +      whandles[i].offset = (unsigned)offsets[i];
> +   }
>
>     img = dri2_create_image_from_winsys(_screen, width, height, format,
> -                                       &whandle, loaderPrivate);
> +                                       num_fds, whandles, loaderPrivate);
>     if(img == NULL)
>        err = __DRI_IMAGE_ERROR_BAD_ALLOC;
>
> @@ -1067,7 +1132,7 @@ dri2_from_names(__DRIscreen *screen, int width, int height, int format,
>     whandle.offset = offsets[0];
>
>     img = dri2_create_image_from_winsys(screen, width, height, format,
> -                                       &whandle, loaderPrivate);
> +                                       1, &whandle, loaderPrivate);
>     if (img == NULL)
>        return NULL;
>
> diff --git a/src/gallium/state_trackers/dri/dri_screen.c b/src/gallium/state_trackers/dri/dri_screen.c
> index 79bcb5a..aa0ad09 100644
> --- a/src/gallium/state_trackers/dri/dri_screen.c
> +++ b/src/gallium/state_trackers/dri/dri_screen.c
> @@ -334,6 +334,17 @@ dri_get_egl_image(struct st_manager *smapi,
>
>     stimg->texture = NULL;
>     pipe_resource_reference(&stimg->texture, img->texture);
> +   switch (img->dri_components) {
> +   case __DRI_IMAGE_COMPONENTS_Y_U_V:
> +      stimg->format = PIPE_FORMAT_IYUV;
> +      break;
> +   case __DRI_IMAGE_COMPONENTS_Y_UV:
> +      stimg->format = PIPE_FORMAT_NV12;
> +      break;
> +   default:
> +      stimg->format = img->texture->format;
> +      break;
> +   }
>     stimg->level = img->level;
>     stimg->layer = img->layer;
>
> diff --git a/src/mesa/main/mtypes.h b/src/mesa/main/mtypes.h
> index 4013ca7..4500376 100644
> --- a/src/mesa/main/mtypes.h
> +++ b/src/mesa/main/mtypes.h
> @@ -45,6 +45,7 @@
>  #include "compiler/shader_enums.h"
>  #include "main/formats.h"       /* MESA_FORMAT_COUNT */
>  #include "compiler/glsl/list.h"
> +#include "util/bitscan.h"
>
>
>  #ifdef __cplusplus
> @@ -1926,6 +1927,7 @@ struct gl_program
>     GLbitfield TexturesUsed[MAX_COMBINED_TEXTURE_IMAGE_UNITS];  /**< TEXTURE_x_BIT bitmask */
>     GLbitfield SamplersUsed;   /**< Bitfield of which samplers are used */
>     GLbitfield ShadowSamplers; /**< Texture units used for shadow sampling. */
> +   GLbitfield ExternalSamplersUsed; /**< Texture units used for samplerExternalOES */
>
>     GLboolean UsesGather; /**< Does this program use gather4 at all? */
>
> @@ -2457,6 +2459,20 @@ struct gl_linked_shader
>     struct gl_shader_info info;
>  };
>
> +static inline GLbitfield gl_external_samplers(struct gl_linked_shader *shader)
> +{
> +   GLbitfield external_samplers = 0;
> +   GLbitfield mask = shader->active_samplers;
> +
> +   while (mask) {
> +      int idx = u_bit_scan(&mask);
> +      if (shader->SamplerTargets[idx] == TEXTURE_EXTERNAL_INDEX)
> +         external_samplers |= (1 << idx);
> +   }
> +
> +   return external_samplers;
> +}
> +
>  /**
>   * A GLSL shader object.
>   */
> diff --git a/src/mesa/program/ir_to_mesa.cpp b/src/mesa/program/ir_to_mesa.cpp
> index e74d94f..9b6b5e8 100644
> --- a/src/mesa/program/ir_to_mesa.cpp
> +++ b/src/mesa/program/ir_to_mesa.cpp
> @@ -2921,6 +2921,7 @@ get_mesa_program(struct gl_context *ctx,
>
>     prog->SamplersUsed = shader->active_samplers;
>     prog->ShadowSamplers = shader->shadow_samplers;
> +   prog->ExternalSamplersUsed = gl_external_samplers(shader);
>     _mesa_update_shader_textures_used(shader_program, prog);
>
>     /* Set the gl_FragDepth layout. */
> diff --git a/src/mesa/state_tracker/st_atom_sampler.c b/src/mesa/state_tracker/st_atom_sampler.c
> index 6b36ac7..ffdec08 100644
> --- a/src/mesa/state_tracker/st_atom_sampler.c
> +++ b/src/mesa/state_tracker/st_atom_sampler.c
> @@ -243,13 +243,12 @@ update_shader_samplers(struct st_context *st,
>                         struct pipe_sampler_state *samplers,
>                         unsigned *num_samplers)
>  {
> -   GLuint unit;
> -   GLbitfield samplers_used;
> +   GLbitfield samplers_used = prog->SamplersUsed;
> +   GLbitfield external_samplers_used = prog->ExternalSamplersUsed;
> +   GLuint unit, last_used = 0;
>     const GLuint old_max = *num_samplers;
>     const struct pipe_sampler_state *states[PIPE_MAX_SAMPLERS];
>
> -   samplers_used = prog->SamplersUsed;
> -
>     if (*num_samplers == 0 && samplers_used == 0x0)
>        return;
>
> @@ -264,6 +263,7 @@ update_shader_samplers(struct st_context *st,
>
>           convert_sampler(st, sampler, texUnit);
>           states[unit] = sampler;
> +         last_used = unit;
>           *num_samplers = unit + 1;
>        }
>        else if (samplers_used != 0 || unit < old_max) {
> @@ -275,6 +275,50 @@ update_shader_samplers(struct st_context *st,
>        }
>     }
>
> +   /* For any external samplers with multiplaner YUV, stuff the additional
> +    * sampler states we need at the end.
> +    *
> +    * Just re-use the existing sampler-state from the primary slot.
> +    */
> +   while (unlikely(external_samplers_used)) {
> +      struct gl_context *ctx = st->ctx;
> +      GLuint unit = u_bit_scan(&external_samplers_used);
> +      const GLuint texUnit = prog->SamplerUnits[unit];
> +      struct gl_texture_object *texObj = ctx->Texture.Unit[texUnit]._Current;
> +      struct st_texture_object *stObj = st_texture_object(texObj);
> +      struct pipe_sampler_state *sampler = samplers + unit;
> +      enum pipe_format view_format;
> +
> +      if (!texObj)
> +         continue;
> +
> +      view_format =
> +         stObj->surface_based ? stObj->surface_format : stObj->pt->format;
> +
> +      switch (view_format) {
> +      case PIPE_FORMAT_NV12:
> +         /* we need one additional sampler: */
> +         states[++last_used] = sampler;
> +         break;
> +      case PIPE_FORMAT_IYUV:
> +         /* we need two additional samplers: */
> +         states[++last_used] = sampler;
> +         states[++last_used] = sampler;
> +         break;
> +      default:
> +         break;
> +      }
> +
> +      /* TODO The OES_EGL_image_external spec allows YUV external images to
> +       * consume multiple sampler slots (and even provides a way to query
> +       * this)..  but we should fail w/ a gl error somewhere sooner if the
> +       * user exceeds this..
> +       */
> +      assert(last_used < PIPE_MAX_SAMPLERS);
> +   }
> +
> +   *num_samplers = MAX2(*num_samplers, last_used + 1);
> +
>     cso_set_samplers(st->cso_context, shader_stage, *num_samplers, states);
>  }
>
> diff --git a/src/mesa/state_tracker/st_atom_shader.c b/src/mesa/state_tracker/st_atom_shader.c
> index 7a23469..154069d 100644
> --- a/src/mesa/state_tracker/st_atom_shader.c
> +++ b/src/mesa/state_tracker/st_atom_shader.c
> @@ -51,6 +51,7 @@
>  #include "st_context.h"
>  #include "st_atom.h"
>  #include "st_program.h"
> +#include "st_texture.h"
>
>
>  /** Compress the fog function enums into a 2-bit value */
> @@ -142,6 +143,32 @@ update_fp( struct st_context *st )
>        }
>     }
>
> +   if (unlikely(stfp->Base.Base.ExternalSamplersUsed)) {
> +      struct gl_context *ctx = st->ctx;
> +      unsigned mask = stfp->Base.Base.ExternalSamplersUsed;
> +      while (mask) {
> +         unsigned unit = u_bit_scan(&mask);
> +         unsigned texUnit = stfp->Base.Base.SamplerUnits[unit];
> +         struct gl_texture_object *texObj = ctx->Texture.Unit[texUnit]._Current;
> +         struct st_texture_object *stObj = st_texture_object(texObj);
> +         enum pipe_format view_format;
> +
> +         view_format =
> +            stObj->surface_based ? stObj->surface_format : stObj->pt->format;
> +
> +         switch (view_format) {
> +         case PIPE_FORMAT_NV12:
> +            key.lower_nv12 |= (1 << unit);
> +            break;
> +         case PIPE_FORMAT_IYUV:
> +            key.lower_iyuv |= (1 << unit);
> +            break;
> +         default:
> +            break;
> +         }
> +      }
> +   }
> +
>     st->fp_variant = st_get_fp_variant(st, stfp, &key);
>
>     st_reference_fragprog(st, &st->fp, stfp);
> diff --git a/src/mesa/state_tracker/st_atom_texture.c b/src/mesa/state_tracker/st_atom_texture.c
> index b647117..909e724 100644
> --- a/src/mesa/state_tracker/st_atom_texture.c
> +++ b/src/mesa/state_tracker/st_atom_texture.c
> @@ -405,6 +405,15 @@ update_single_texture(struct st_context *st,
>        }
>     }
>
> +   switch (view_format) {
> +   case PIPE_FORMAT_NV12:
> +   case PIPE_FORMAT_IYUV:
> +      view_format = PIPE_FORMAT_R8_UNORM;
> +      break;
> +   default:
> +      break;
> +   }
> +
>     *sampler_view =
>        st_get_texture_sampler_view_from_stobj(st, stObj, view_format,
>                                               glsl_version);
> @@ -423,7 +432,8 @@ update_textures(struct st_context *st,
>  {
>     const GLuint old_max = *num_textures;
>     GLbitfield samplers_used = prog->SamplersUsed;
> -   GLuint unit;
> +   GLbitfield external_samplers_used = prog->ExternalSamplersUsed;
> +   GLuint unit, last_used = 0;
>     struct gl_shader_program *shader =
>        st->ctx->_Shader->CurrentProgram[mesa_shader];
>     unsigned glsl_version = shader ? shader->Version : 0;
> @@ -454,9 +464,68 @@ update_textures(struct st_context *st,
>           break;
>        }
>
> +      if (sampler_view)
> +         last_used = unit;
> +
>        pipe_sampler_view_reference(&(sampler_views[unit]), sampler_view);
>     }
>
> +   /* For any external samplers with multiplaner YUV, stuff the additional
> +    * sampler views we need at the end.
> +    *
> +    * Trying to cache the sampler view in the stObj looks painful, so just
> +    * re-create the sampler view for the extra planes each time.  Main use
> +    * case is video playback (ie. fps games wouldn't be using this) so I
> +    * guess no point to try to optimize this feature.
> +    */
> +   while (unlikely(external_samplers_used)) {
> +      struct gl_context *ctx = st->ctx;
> +      GLuint unit = u_bit_scan(&external_samplers_used);
> +      const GLuint texUnit = prog->SamplerUnits[unit];
> +      struct gl_texture_object *texObj = ctx->Texture.Unit[texUnit]._Current;
> +      struct st_texture_object *stObj = st_texture_object(texObj);
> +      enum pipe_format view_format;
> +      struct pipe_sampler_view tmpl;
> +
> +      if (!texObj)
> +         continue;
> +
> +      /* use original view as template: */
> +      tmpl = *sampler_views[unit];
> +
> +      view_format =
> +         stObj->surface_based ? stObj->surface_format : stObj->pt->format;
> +
> +      switch (view_format) {
> +      case PIPE_FORMAT_NV12:
> +         /* we need one additional R8G8 view: */
> +         tmpl.format = PIPE_FORMAT_RG88_UNORM;
> +         tmpl.swizzle_g = PIPE_SWIZZLE_Y;   /* tmpl from Y plane is R8 */
> +         sampler_views[++last_used] =
> +               st->pipe->create_sampler_view(st->pipe, stObj->pt->next, &tmpl);
> +         break;
> +      case PIPE_FORMAT_IYUV:
> +         /* we need two additional R8 views: */
> +         tmpl.format = PIPE_FORMAT_R8_UNORM;
> +         sampler_views[++last_used] =
> +               st->pipe->create_sampler_view(st->pipe, stObj->pt->next, &tmpl);
> +         sampler_views[++last_used] =
> +               st->pipe->create_sampler_view(st->pipe, stObj->pt->next->next, &tmpl);
> +         break;
> +      default:
> +         break;
> +      }
> +
> +      /* TODO The OES_EGL_image_external spec allows YUV external images to
> +       * consume multiple sampler slots (and even provides a way to query
> +       * this)..  but we should fail w/ a gl error somewhere sooner if the
> +       * user exceeds this..
> +       */
> +      assert(last_used < PIPE_MAX_SAMPLERS);
> +   }
> +
> +   *num_textures = MAX2(*num_textures, last_used + 1);
> +
>     cso_set_sampler_views(st->cso_context,
>                           shader_stage,
>                           *num_textures,
> diff --git a/src/mesa/state_tracker/st_cb_eglimage.c b/src/mesa/state_tracker/st_cb_eglimage.c
> index 1782d15..7bea565 100644
> --- a/src/mesa/state_tracker/st_cb_eglimage.c
> +++ b/src/mesa/state_tracker/st_cb_eglimage.c
> @@ -119,6 +119,24 @@ st_bind_surface(struct gl_context *ctx, GLenum target,
>
>     texFormat = st_pipe_format_to_mesa_format(ps->format);
>
> +   /* TODO RequiredTextureImageUnits should probably be reset back
> +    * to 1 somewhere if different texture is bound??
> +    */
> +   if (texFormat == MESA_FORMAT_NONE) {
> +      switch (ps->format) {
> +      case PIPE_FORMAT_NV12:
> +         texFormat = MESA_FORMAT_R_UNORM8;
> +         texObj->RequiredTextureImageUnits = 2;
> +         break;
> +      case PIPE_FORMAT_IYUV:
> +         texFormat = MESA_FORMAT_R_UNORM8;
> +         texObj->RequiredTextureImageUnits = 3;
> +         break;
> +      default:
> +         unreachable("bad YUV format!");
> +      }
> +   }
> +
>     _mesa_init_teximage_fields(ctx, texImage,
>                                ps->width, ps->height, 1, 0, internalFormat,
>                                texFormat);
> diff --git a/src/mesa/state_tracker/st_context.c b/src/mesa/state_tracker/st_context.c
> index ddc11a4..0e3b491 100644
> --- a/src/mesa/state_tracker/st_context.c
> +++ b/src/mesa/state_tracker/st_context.c
> @@ -254,11 +254,19 @@ void st_invalidate_state(struct gl_context * ctx, GLbitfield new_state)
>        st->active_states = st_get_active_states(ctx);
>     }
>
> -   if (new_state & _NEW_TEXTURE)
> +   if (new_state & _NEW_TEXTURE) {
>        st->dirty |= st->active_states &
>                     (ST_NEW_SAMPLER_VIEWS |
>                      ST_NEW_SAMPLERS |
>                      ST_NEW_IMAGE_UNITS);
> +      // TODO we need to do this for all shader stages
> +      if (st->fp && st->fp->Base.Base.ExternalSamplersUsed) {
> +         /* TODO check if external imgs have actually changed # of
> +          * samplers used (ie. between RGB / 2-plane YUV / 3-plane YUV)
> +          */
> +         st->dirty |= ST_NEW_FS_STATE;
> +      }

You don't want to use st->fp here, because it comes from the previous
draw call, not the current state. ctx->FragmentProgram._Current is the
correct variable here.

> +   }
>
>     if (new_state & _NEW_PROGRAM_CONSTANTS)
>        st->dirty |= st->active_states & ST_NEW_CONSTANTS;
> diff --git a/src/mesa/state_tracker/st_glsl_to_nir.cpp b/src/mesa/state_tracker/st_glsl_to_nir.cpp
> index 307bf3e..ac9cc9d 100644
> --- a/src/mesa/state_tracker/st_glsl_to_nir.cpp
> +++ b/src/mesa/state_tracker/st_glsl_to_nir.cpp
> @@ -422,6 +422,7 @@ st_nir_get_mesa_program(struct gl_context *ctx,
>
>     prog->SamplersUsed = shader->active_samplers;
>     prog->ShadowSamplers = shader->shadow_samplers;
> +   prog->ExternalSamplersUsed = gl_external_samplers(shader);
>     _mesa_update_shader_textures_used(shader_program, prog);
>
>     _mesa_reference_program(ctx, &shader->Program, prog);
> diff --git a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
> index b7e47db..3f1f8fc 100644
> --- a/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
> +++ b/src/mesa/state_tracker/st_glsl_to_tgsi.cpp
> @@ -4346,6 +4346,10 @@ count_resources(glsl_to_tgsi_visitor *v, gl_program *prog)
>              }
>           }
>        }
> +
> +      if (inst->tex_target == TEXTURE_EXTERNAL_INDEX)
> +         prog->ExternalSamplersUsed |= 1 << inst->sampler.index;
> +
>        if (inst->buffer.file != PROGRAM_UNDEFINED && (
>                  is_resource_instruction(inst->op) ||
>                  inst->op == TGSI_OPCODE_STORE)) {
> diff --git a/src/mesa/state_tracker/st_manager.c b/src/mesa/state_tracker/st_manager.c
> index e2da054..fece5d5 100644
> --- a/src/mesa/state_tracker/st_manager.c
> +++ b/src/mesa/state_tracker/st_manager.c
> @@ -845,6 +845,7 @@ st_manager_get_egl_image_surface(struct st_context *st, void *eglimg)
>        return NULL;
>
>     u_surface_default_template(&surf_tmpl, stimg.texture);
> +   surf_tmpl.format = stimg.format;
>     surf_tmpl.u.tex.level = stimg.level;
>     surf_tmpl.u.tex.first_layer = stimg.layer;
>     surf_tmpl.u.tex.last_layer = stimg.layer;
> diff --git a/src/mesa/state_tracker/st_program.c b/src/mesa/state_tracker/st_program.c
> index 03a685c..e6b1017 100644
> --- a/src/mesa/state_tracker/st_program.c
> +++ b/src/mesa/state_tracker/st_program.c
> @@ -53,6 +53,7 @@
>  #include "st_cb_bitmap.h"
>  #include "st_cb_drawpixels.h"
>  #include "st_context.h"
> +#include "st_tgsi_lower_yuv.h"
>  #include "st_program.h"
>  #include "st_mesa_to_tgsi.h"
>  #include "st_atifs_to_tgsi.h"
> @@ -1020,6 +1021,10 @@ st_create_fp_variant(struct st_context *st,
>           NIR_PASS_V(tgsi.ir.nir, nir_lower_drawpixels, &options);
>        }
>
> +      if (unlikely(key->lower_nv12 || key->lower_iyuv)) {
> +         assert(0);  // TODO
> +      }
> +
>        st_finalize_nir(st, &stfp->Base.Base, tgsi.ir.nir);
>
>        variant->driver_shader = pipe->create_fs_state(pipe, &tgsi);

Did you forget to drop this hunk?

> @@ -1118,6 +1123,19 @@ st_create_fp_variant(struct st_context *st,
>           fprintf(stderr, "mesa: cannot create a shader for glDrawPixels\n");
>     }
>
> +   if (unlikely(key->lower_nv12 || key->lower_iyuv)) {
> +      const struct tgsi_token *tokens;
> +      unsigned first_extra_sampler = ffs(~stfp->Base.Base.SamplersUsed) - 1;
> +
> +      /* samplers inserted would conflict, but this should be unpossible: */
> +      assert(!(key->bitmap || key->drawpixels));
> +
> +      tokens = st_tgsi_lower_yuv(tgsi.tokens, first_extra_sampler,
> +                                 key->lower_nv12, key->lower_iyuv);
> +      tgsi_free_tokens(tgsi.tokens);
> +      tgsi.tokens = tokens;
> +   }

What if SamplersUsed has holes, e.g. SamplersUsed = 1011011b.

Marek


More information about the mesa-dev mailing list