frontends/va: Derive image from interlaced buffers in some cases
authorThong Thai <thong.thai@amd.com>
Sat, 15 Aug 2020 18:36:45 +0000 (14:36 -0400)
committerMarge Bot <eric+marge@anholt.net>
Tue, 15 Sep 2020 14:58:26 +0000 (14:58 +0000)
Add an allowlist to make an exception when deriving images from
interlaced buffers. Normally, the function should fail if the surface
needs to be modified to derive the image. But some applications do not
follow the fall-back method of using vaCreateImage + vaPutImage as
mentioned in the VAAPI documentation, so we have to make an exception.

Signed-off-by: Thong Thai <thong.thai@amd.com>
Reviewed-by: Leo Liu <leo.liu@amd.com>
Part-of: <https://gitlab.freedesktop.org/mesa/mesa/-/merge_requests/5942>

src/gallium/frontends/va/image.c

index 3d6e091..8c0f03e 100644 (file)
@@ -32,6 +32,7 @@
 #include "util/u_handle_table.h"
 #include "util/u_surface.h"
 #include "util/u_video.h"
+#include "util/u_process.h"
 
 #include "vl/vl_winsys.h"
 #include "vl/vl_video_buffer.h"
@@ -208,6 +209,17 @@ vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
    unsigned stride = 0;
    unsigned offset = 0;
 
+   /* This function is used by some programs to test for hardware decoding, but on
+    * AMD devices, the buffers default to interlaced, which causes this function to fail.
+    * Some programs expect this function to fail, while others, assume this means
+    * hardware acceleration is not available and give up without trying the fall-back 
+    * vaCreateImage + vaPutImage 
+    */
+   const char *proc = util_get_process_name();
+   const char *derive_interlaced_allowlist[] = {
+         "vlc",
+   };
+
    if (!ctx)
       return VA_STATUS_ERROR_INVALID_CONTEXT;
 
@@ -226,6 +238,15 @@ vlVaDeriveImage(VADriverContextP ctx, VASurfaceID surface, VAImage *image)
    if (!surf || !surf->buffer)
       return VA_STATUS_ERROR_INVALID_SURFACE;
 
+   if (surf->buffer->interlaced) {
+      for (i = 0; i < ARRAY_SIZE(derive_interlaced_allowlist); i++)
+         if ((strcmp(derive_interlaced_allowlist[i], proc) == 0))
+            break;
+
+      if (i >= ARRAY_SIZE(derive_interlaced_allowlist))
+         return VA_STATUS_ERROR_OPERATION_FAILED;
+   }
+
    surfaces = surf->buffer->get_surfaces(surf->buffer);
    if (!surfaces || !surfaces[0]->texture)
       return VA_STATUS_ERROR_ALLOCATION_FAILED;