[Mesa-stable] [PATCH v2] st/mesa: fix the layer of VDPAU surface samplers

Nicolai Hähnle nhaehnle at gmail.com
Fri Nov 4 12:28:57 UTC 2016


From: Nicolai Hähnle <nicolai.haehnle at amd.com>

A (latent) bug in VDPAU interop was exposed by commit
e5cc84dd43be066c1dd418e32f5ad258e31a150a.

Before that commit, the st_vdpau code created samplers with
first_layer == last_layer == 1 that the general texture handling code
would immediately delete and re-create, because the layer does not match
the information in the GL texture object.

This was correct behavior at least in the DMABUF case, because the imported
resource is supposed to have the correct offset already applied.  In the
non-DMABUF case, this was just plain wrong but apparently nobody noticed.

After that commit, the state tracker assumes that an existing sampler is
correct at all times.  Existing samplers are supposed to be deleted when
they may become invalid, and they will be created on-demand.  This meant
that the sampler with first_layer == last_layer == 1 stuck around, leading
to rendering artefacts (on radeonsi), command stream failures (on r600), and
assertions (in debug builds everywhere).

This patch fixes the problem by simply not creating a sampler at all in
st_vdpau_map_surface.  We rely on the generic texture code to do the right
thing, adding the layer_override to make the non-DMABUF case work.

v2: add the layer_override

Bugzilla: https://bugs.freedesktop.org/show_bug.cgi?id=98512
Cc: 13.0 <mesa-stable at lists.freedesktop.org>
Cc: Christian König <deathsimple at vodafone.de>
Cc: Ilia Mirkin <imirkin at alum.mit.edu>
--
This fixes the problem on radeon, but it would be good to get some testing
on Nouveau as well. According to Christian, testing nouveau with Kodi should
do the trick, probably mpv --hwdec=vdpau --vo=opengl should also work. Errors
may only be noticeable as bad (de-)interlacing.
---
 src/mesa/state_tracker/st_sampler_view.c | 15 +++++++++++----
 src/mesa/state_tracker/st_texture.h      |  9 +++++++++
 src/mesa/state_tracker/st_vdpau.c        | 20 +++++++-------------
 3 files changed, 27 insertions(+), 17 deletions(-)

diff --git a/src/mesa/state_tracker/st_sampler_view.c b/src/mesa/state_tracker/st_sampler_view.c
index 9fe0bfe..2b2fa8b 100644
--- a/src/mesa/state_tracker/st_sampler_view.c
+++ b/src/mesa/state_tracker/st_sampler_view.c
@@ -423,22 +423,26 @@ st_create_texture_sampler_view_from_stobj(struct st_context *st,
       size = MIN2(stObj->pt->width0 - base, (unsigned)stObj->base.BufferSize);
       if (!size)
          return NULL;
 
       templ.u.buf.offset = base;
       templ.u.buf.size = size;
    } else {
       templ.u.tex.first_level = stObj->base.MinLevel + stObj->base.BaseLevel;
       templ.u.tex.last_level = last_level(stObj);
       assert(templ.u.tex.first_level <= templ.u.tex.last_level);
-      templ.u.tex.first_layer = stObj->base.MinLayer;
-      templ.u.tex.last_layer = last_layer(stObj);
+      if (stObj->layer_override) {
+         templ.u.tex.first_layer = templ.u.tex.last_layer = stObj->layer_override;
+      } else {
+         templ.u.tex.first_layer = stObj->base.MinLayer;
+         templ.u.tex.last_layer = last_layer(stObj);
+      }
       assert(templ.u.tex.first_layer <= templ.u.tex.last_layer);
       templ.target = gl_target_to_pipe(stObj->base.Target);
    }
 
    templ.swizzle_r = GET_SWZ(swizzle, 0);
    templ.swizzle_g = GET_SWZ(swizzle, 1);
    templ.swizzle_b = GET_SWZ(swizzle, 2);
    templ.swizzle_a = GET_SWZ(swizzle, 3);
 
    return st->pipe->create_sampler_view(st->pipe, stObj->pt, &templ);
@@ -471,22 +475,25 @@ st_get_texture_sampler_view_from_stobj(struct st_context *st,
          unsigned base = stObj->base.BufferOffset;
          unsigned size = MIN2(stObj->pt->width0 - base,
                               (unsigned) stObj->base.BufferSize);
          assert(view->u.buf.offset == base);
          assert(view->u.buf.size == size);
       }
       else {
          assert(stObj->base.MinLevel + stObj->base.BaseLevel ==
                 view->u.tex.first_level);
          assert(last_level(stObj) == view->u.tex.last_level);
-         assert(stObj->base.MinLayer == view->u.tex.first_layer);
-         assert(last_layer(stObj) == view->u.tex.last_layer);
+         assert(stObj->layer_override || stObj->base.MinLayer == view->u.tex.first_layer);
+         assert(stObj->layer_override || last_layer(stObj) == view->u.tex.last_layer);
+         assert(!stObj->layer_override ||
+                (stObj->layer_override == view->u.tex.first_layer &&
+                 stObj->layer_override == view->u.tex.last_layer));
       }
    }
    else {
       /* create new sampler view */
       enum pipe_format format = get_sampler_view_format(st, stObj, samp);
 
       *sv = st_create_texture_sampler_view_from_stobj(st, stObj,
                                                       format, glsl_version);
 
    }
diff --git a/src/mesa/state_tracker/st_texture.h b/src/mesa/state_tracker/st_texture.h
index 730843a..0ce7989 100644
--- a/src/mesa/state_tracker/st_texture.h
+++ b/src/mesa/state_tracker/st_texture.h
@@ -101,20 +101,29 @@ struct st_texture_object
     * cannot be reallocated and the format can only be changed with a sampler
     * view or a surface.
     */
    GLboolean surface_based;
 
    /* If surface_based is true, this format should be used for all sampler
     * views and surfaces instead of pt->format.
     */
    enum pipe_format surface_format;
 
+   /* When non-zero, samplers should use this layer instead of the one
+    * specified by the GL state.
+    *
+    * This is used for VDPAU interop, where imported pipe_resources may be
+    * array textures (containing layers with different fields) even though the
+    * GL state describes one non-array texture per field.
+    */
+   uint layer_override;
+
    /** The glsl version of the shader seen during the previous validation */
    unsigned prev_glsl_version;
    /** The value of the sampler's sRGBDecode state at the previous validation */
    GLenum prev_sRGBDecode;
 };
 
 
 static inline struct st_texture_image *
 st_texture_image(struct gl_texture_image *img)
 {
diff --git a/src/mesa/state_tracker/st_vdpau.c b/src/mesa/state_tracker/st_vdpau.c
index 7912057..0273815 100644
--- a/src/mesa/state_tracker/st_vdpau.c
+++ b/src/mesa/state_tracker/st_vdpau.c
@@ -182,34 +182,36 @@ static void
 st_vdpau_map_surface(struct gl_context *ctx, GLenum target, GLenum access,
                      GLboolean output, struct gl_texture_object *texObj,
                      struct gl_texture_image *texImage,
                      const void *vdpSurface, GLuint index)
 {
    struct st_context *st = st_context(ctx);
    struct st_texture_object *stObj = st_texture_object(texObj);
    struct st_texture_image *stImage = st_texture_image(texImage);
 
    struct pipe_resource *res;
-   struct pipe_sampler_view templ, **sampler_view;
    mesa_format texFormat;
+   uint layer_override = 0;
 
    if (output) {
       res = st_vdpau_output_surface_dma_buf(ctx, vdpSurface);
 
       if (!res)
          res = st_vdpau_output_surface_gallium(ctx, vdpSurface);
 
    } else {
       res = st_vdpau_video_surface_dma_buf(ctx, vdpSurface, index);
 
-      if (!res)
+      if (!res) {
          res = st_vdpau_video_surface_gallium(ctx, vdpSurface, index);
+         layer_override = index & 1;
+      }
    }
 
    if (!res) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV");
       return;
    }
 
    /* do we have different screen objects ? */
    if (res->screen != st->pipe->screen) {
       _mesa_error(ctx, GL_INVALID_OPERATION, "VDPAUMapSurfacesNV");
@@ -226,51 +228,43 @@ st_vdpau_map_surface(struct gl_context *ctx, GLenum target, GLenum access,
    texFormat = st_pipe_format_to_mesa_format(res->format);
 
    _mesa_init_teximage_fields(ctx, texImage,
                               res->width0, res->height0, 1, 0, GL_RGBA,
                               texFormat);
 
    pipe_resource_reference(&stObj->pt, res);
    st_texture_release_all_sampler_views(st, stObj);
    pipe_resource_reference(&stImage->pt, res);
 
-   u_sampler_view_default_template(&templ, res, res->format);
-   templ.u.tex.first_layer = index & 1;
-   templ.u.tex.last_layer = index & 1;
-   templ.swizzle_r = GET_SWZ(stObj->base._Swizzle, 0);
-   templ.swizzle_g = GET_SWZ(stObj->base._Swizzle, 1);
-   templ.swizzle_b = GET_SWZ(stObj->base._Swizzle, 2);
-   templ.swizzle_a = GET_SWZ(stObj->base._Swizzle, 3);
-
-   sampler_view = st_texture_get_sampler_view(st, stObj);
-   *sampler_view = st->pipe->create_sampler_view(st->pipe, res, &templ);
-
    stObj->surface_format = res->format;
+   stObj->layer_override = layer_override;
 
    _mesa_dirty_texobj(ctx, texObj);
    pipe_resource_reference(&res, NULL);
 }
 
 static void
 st_vdpau_unmap_surface(struct gl_context *ctx, GLenum target, GLenum access,
                        GLboolean output, struct gl_texture_object *texObj,
                        struct gl_texture_image *texImage,
                        const void *vdpSurface, GLuint index)
 {
    struct st_context *st = st_context(ctx);
    struct st_texture_object *stObj = st_texture_object(texObj);
    struct st_texture_image *stImage = st_texture_image(texImage);
 
    pipe_resource_reference(&stObj->pt, NULL);
    st_texture_release_all_sampler_views(st, stObj);
    pipe_resource_reference(&stImage->pt, NULL);
 
+   stObj->layer_override = 0;
+
    _mesa_dirty_texobj(ctx, texObj);
 
    st_flush(st, NULL, 0);
 }
 
 #endif
 
 void
 st_init_vdpau_functions(struct dd_function_table *functions)
 {
-- 
2.7.4



More information about the mesa-stable mailing list