OSDN Git Service

Add va_MessagingInit().
[android-x86/hardware-intel-common-libva.git] / va / va.c
diff --git a/va/va.c b/va/va.c
index 2eea02b..0a129a9 100644 (file)
--- a/va/va.c
+++ b/va/va.c
@@ -26,6 +26,7 @@
 #include "sysdeps.h"
 #include "va.h"
 #include "va_backend.h"
+#include "va_backend_vpp.h"
 #include "va_trace.h"
 #include "va_fool.h"
 
 #include <string.h>
 #include <dlfcn.h>
 #include <unistd.h>
+#ifdef ANDROID
+#include <cutils/log.h>
+/* support versions < JellyBean */
+#ifndef ALOGE
+#define ALOGE LOGE
+#endif
+#ifndef ALOGI
+#define ALOGI LOGI
+#endif
+#endif
 
 #define DRIVER_EXTENSION       "_drv_video.so"
 
 #define CHECK_MAXIMUM(s, ctx, var) if (!va_checkMaximum(ctx->max_##var, #var)) s = VA_STATUS_ERROR_UNKNOWN;
 #define CHECK_STRING(s, ctx, var) if (!va_checkString(ctx->str_##var, #var)) s = VA_STATUS_ERROR_UNKNOWN;
 
-extern int trace_flag;
-#define VA_TRACE(trace_func,...)                \
-    if (trace_flag) {                           \
-        trace_func(__VA_ARGS__);                \
-    }
-
-extern int fool_decode;
-extern int fool_encode;
-#define VA_FOOL(fool_func,...)                 \
-    if (fool_decode || fool_encode) {          \
-        ret = fool_func(__VA_ARGS__);          \
-    }
-
 /*
  * read a config "env" for libva.conf or from environment setting
- * liva.conf has higher priority
+ * libva.conf has higher priority
  * return 0: the "env" is set, and the value is copied into env_value
  *        1: the env is not set
  */
@@ -72,23 +70,24 @@ int va_parseConfig(char *env, char *env_value)
     char oneline[1024];
     FILE *fp=NULL;
 
-
     if (env == NULL)
         return 1;
     
     fp = fopen("/etc/libva.conf", "r");
     while (fp && (fgets(oneline, 1024, fp) != NULL)) {
-       if (strlen(oneline) == 1)
-           continue;
+        if (strlen(oneline) == 1)
+            continue;
         token = strtok_r(oneline, "=\n", &saveptr);
-       value = strtok_r(NULL, "=\n", &saveptr);
+        value = strtok_r(NULL, "=\n", &saveptr);
 
-       if (NULL == token || NULL == value)
-           continue;
+        if (NULL == token || NULL == value)
+            continue;
 
         if (strcmp(token, env) == 0) {
-            if (env_value)
+            if (env_value) {
                 strncpy(env_value,value, 1024);
+                env_value[1023] = '\0';
+            }
 
             fclose(fp);
 
@@ -99,10 +98,12 @@ int va_parseConfig(char *env, char *env_value)
         fclose(fp);
 
     /* no setting in config file, use env setting */
-    if (getenv(env)) {
-        if (env_value)
-            strncpy(env_value, getenv(env), 1024);
-
+    value = getenv(env);
+    if (value) {
+        if (env_value) {
+            strncpy(env_value, value, 1024);
+            env_value[1023] = '\0';
+        }
         return 0;
     }
     
@@ -115,54 +116,159 @@ int vaDisplayIsValid(VADisplay dpy)
     return pDisplayContext && (pDisplayContext->vadpy_magic == VA_DISPLAY_MAGIC) && pDisplayContext->vaIsValid(pDisplayContext);
 }
 
+static void default_log_error(const char *buffer)
+{
+# ifdef ANDROID
+    ALOGE("%s", buffer);
+# else
+    fprintf(stderr, "libva error: %s", buffer);
+# endif
+}
+
+static void default_log_info(const char *buffer)
+{
+# ifdef ANDROID
+    ALOGI("%s", buffer);
+# else
+    fprintf(stderr, "libva info: %s", buffer);
+# endif
+}
+
+static vaMessageCallback va_log_error = default_log_error;
+static vaMessageCallback va_log_info = default_log_info;
+
+/**
+ * Set the callback for error messages, or NULL for no logging.
+ * Returns the previous one, or NULL if it was disabled.
+ */
+vaMessageCallback vaSetErrorCallback(vaMessageCallback callback)
+{
+    vaMessageCallback old_callback = va_log_error;
+    va_log_error = callback;
+    return old_callback;
+}
+
+/**
+ * Set the callback for info messages, or NULL for no logging.
+ * Returns the previous one, or NULL if it was disabled.
+ */
+vaMessageCallback vaSetInfoCallback(vaMessageCallback callback)
+{
+    vaMessageCallback old_callback = va_log_info;
+    va_log_info = callback;
+    return old_callback;
+}
+
+void va_MessagingInit()
+{
+#if ENABLE_VA_MESSAGING
+    char env_value[1024];
+
+    if (va_parseConfig("LIBVA_MESSAGING_LEVEL", &env_value[0]) == 0) {
+        if (strcmp(env_value, "0") == 0) {
+            vaSetInfoCallback(NULL);
+            vaSetErrorCallback(NULL);
+        }
+
+        if (strcmp(env_value, "1") == 0) {
+            vaSetInfoCallback(NULL);
+        }
+    }
+#endif
+}
+
 void va_errorMessage(const char *msg, ...)
 {
+#if ENABLE_VA_MESSAGING
+    char buf[512], *dynbuf;
     va_list args;
+    int n, len;
+
+    if (va_log_error == NULL)
+        return;
 
-    fprintf(stderr, "libva error: ");
     va_start(args, msg);
-    vfprintf(stderr, msg, args);
+    len = vsnprintf(buf, sizeof(buf), msg, args);
     va_end(args);
+
+    if (len >= (int)sizeof(buf)) {
+        dynbuf = malloc(len + 1);
+        if (!dynbuf)
+            return;
+        va_start(args, msg);
+        n = vsnprintf(dynbuf, len + 1, msg, args);
+        va_end(args);
+        if (n == len)
+            va_log_error(dynbuf);
+        free(dynbuf);
+    }
+    else if (len > 0)
+        va_log_error(buf);
+#endif
 }
 
 void va_infoMessage(const char *msg, ...)
 {
+#if ENABLE_VA_MESSAGING
+    char buf[512], *dynbuf;
     va_list args;
+    int n, len;
+
+    if (va_log_info == NULL)
+        return;
 
-    fprintf(stderr, "libva: ");
     va_start(args, msg);
-    vfprintf(stderr, msg, args);
+    len = vsnprintf(buf, sizeof(buf), msg, args);
     va_end(args);
+
+    if (len >= (int)sizeof(buf)) {
+        dynbuf = malloc(len + 1);
+        if (!dynbuf)
+            return;
+        va_start(args, msg);
+        n = vsnprintf(dynbuf, len + 1, msg, args);
+        va_end(args);
+        if (n == len)
+            va_log_info(dynbuf);
+        free(dynbuf);
+    }
+    else if (len > 0)
+        va_log_info(buf);
+#endif
 }
 
-static Bool va_checkVtable(void *ptr, char *function)
+static bool va_checkVtable(void *ptr, char *function)
 {
-    if (!ptr)
-    {
+    if (!ptr) {
         va_errorMessage("No valid vtable entry for va%s\n", function);
-        return False;
+        return false;
     }
-    return True;
+    return true;
 }
 
-static Bool va_checkMaximum(int value, char *variable)
+static bool va_checkMaximum(int value, char *variable)
 {
-    if (!value)
-    {
+    if (!value) {
         va_errorMessage("Failed to define max_%s in init\n", variable);
-        return False;
+        return false;
     }
-    return True;
+    return true;
 }
 
-static Bool va_checkString(const char* value, char *variable)
+static bool va_checkString(const char* value, char *variable)
 {
-    if (!value)
-    {
+    if (!value) {
         va_errorMessage("Failed to define str_%s in init\n", variable);
-        return False;
+        return false;
     }
-    return True;
+    return true;
+}
+
+static inline int
+va_getDriverInitName(char *name, int namelen, int major, int minor)
+{
+    int ret = snprintf(name, namelen, "__vaDriverInit_%d_%d", major, minor);
+    return ret > 0 && ret < namelen;
 }
 
 static VAStatus va_getDriverName(VADisplay dpy, char **driver_name)
@@ -181,23 +287,25 @@ static VAStatus va_openDriver(VADisplay dpy, char *driver_name)
     char *driver_dir;
     
     if (geteuid() == getuid())
-    {
         /* don't allow setuid apps to use LIBVA_DRIVERS_PATH */
         search_path = getenv("LIBVA_DRIVERS_PATH");
-    }
     if (!search_path)
-    {
         search_path = VA_DRIVERS_PATH;
-    }
 
     search_path = strdup((const char *)search_path);
-    driver_dir = strtok_r((const char *)search_path, ":", &saveptr);
-    while(driver_dir)
-    {
+    driver_dir = strtok_r(search_path, ":", &saveptr);
+    while (driver_dir) {
         void *handle = NULL;
         char *driver_path = (char *) malloc( strlen(driver_dir) +
                                              strlen(driver_name) +
                                              strlen(DRIVER_EXTENSION) + 2 );
+        if (!driver_path) {
+            va_errorMessage("%s L%d Out of memory!n",
+                                __FUNCTION__, __LINE__);
+            free(search_path);    
+            return VA_STATUS_ERROR_ALLOCATION_FAILED;
+        }
+
         strncpy( driver_path, driver_dir, strlen(driver_dir) + 1);
         strncat( driver_path, "/", strlen("/") );
         strncat( driver_path, driver_name, strlen(driver_name) );
@@ -209,26 +317,50 @@ static VAStatus va_openDriver(VADisplay dpy, char *driver_name)
 #else
         handle = dlopen( driver_path, RTLD_NOW| RTLD_GLOBAL);
 #endif
-        if (!handle)
-        {
+        if (!handle) {
             /* Don't give errors for non-existing files */
             if (0 == access( driver_path, F_OK))
-            {  
                 va_errorMessage("dlopen of %s failed: %s\n", driver_path, dlerror());
+        } else {
+            VADriverInit init_func = NULL;
+            char init_func_s[256];
+            int i;
+
+            static const struct {
+                int major;
+                int minor;
+            } compatible_versions[] = {
+                { VA_MAJOR_VERSION, VA_MINOR_VERSION },
+                { 0, 39 },
+                { 0, 38 },
+                { 0, 37 },
+                { 0, 36 },
+                { 0, 35 },
+                { 0, 34 },
+                { 0, 33 },
+                { 0, 32 },
+                { -1, }
+            };
+
+            for (i = 0; compatible_versions[i].major >= 0; i++) {
+                if (va_getDriverInitName(init_func_s, sizeof(init_func_s),
+                                         compatible_versions[i].major,
+                                         compatible_versions[i].minor)) {
+                    init_func = (VADriverInit)dlsym(handle, init_func_s);
+                    if (init_func) {
+                        va_infoMessage("Found init function %s\n", init_func_s);
+                        break;
+                    }
+                }
             }
-        }
-        else
-        {
-            VADriverInit init_func;
-            init_func = (VADriverInit) dlsym(handle, VA_DRIVER_INIT_FUNC_S);
-            if (!init_func)
-            {
-                va_errorMessage("%s has no function %s\n", driver_path, VA_DRIVER_INIT_FUNC_S);
+
+            if (compatible_versions[i].major < 0) {
+                va_errorMessage("%s has no function %s\n",
+                                driver_path, init_func_s);
                 dlclose(handle);
-            }
-            else
-            {
+            } else {
                 struct VADriverVTable *vtable = ctx->vtable;
+                struct VADriverVTableVPP *vtable_vpp = ctx->vtable_vpp;
 
                 vaStatus = VA_STATUS_SUCCESS;
                 if (!vtable) {
@@ -238,11 +370,19 @@ static VAStatus va_openDriver(VADisplay dpy, char *driver_name)
                 }
                 ctx->vtable = vtable;
 
-                if (VA_STATUS_SUCCESS == vaStatus)
+                if (!vtable_vpp) {
+                    vtable_vpp = calloc(1, sizeof(*vtable_vpp));
+                    if (vtable_vpp)
+                        vtable_vpp->version = VA_DRIVER_VTABLE_VPP_VERSION;
+                    else
+                        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
+                }
+                ctx->vtable_vpp = vtable_vpp;
+
+                if (init_func && VA_STATUS_SUCCESS == vaStatus)
                     vaStatus = (*init_func)(ctx);
 
-                if (VA_STATUS_SUCCESS == vaStatus)
-                {
+                if (VA_STATUS_SUCCESS == vaStatus) {
                     CHECK_MAXIMUM(vaStatus, ctx, profiles);
                     CHECK_MAXIMUM(vaStatus, ctx, entrypoints);
                     CHECK_MAXIMUM(vaStatus, ctx, attributes);
@@ -291,15 +431,12 @@ static VAStatus va_openDriver(VADisplay dpy, char *driver_name)
                     CHECK_VTABLE(vaStatus, ctx, GetDisplayAttributes);
                     CHECK_VTABLE(vaStatus, ctx, SetDisplayAttributes);
                 }
-                if (VA_STATUS_SUCCESS != vaStatus)
-                {
+                if (VA_STATUS_SUCCESS != vaStatus) {
                     va_errorMessage("%s init failed\n", driver_path);
                     dlclose(handle);
                 }
                 if (VA_STATUS_SUCCESS == vaStatus)
-                {
                     ctx->handle = handle;
-                }
                 free(driver_path);
                 break;
             }
@@ -317,7 +454,7 @@ static VAStatus va_openDriver(VADisplay dpy, char *driver_name)
 VAPrivFunc vaGetLibFunc(VADisplay dpy, const char *func)
 {
     VADriverContextP ctx;
-    if( !vaDisplayIsValid(dpy) )
+    if (!vaDisplayIsValid(dpy))
         return NULL;
     ctx = CTX(dpy);
 
@@ -333,8 +470,7 @@ VAPrivFunc vaGetLibFunc(VADisplay dpy, const char *func)
  */
 const char *vaErrorStr(VAStatus error_status)
 {
-    switch(error_status)
-    {
+    switch(error_status) {
         case VA_STATUS_SUCCESS:
             return "success (no error)";
         case VA_STATUS_ERROR_OPERATION_FAILED:
@@ -381,12 +517,79 @@ const char *vaErrorStr(VAStatus error_status)
             return "surface is in displaying (may by overlay)" ;
         case VA_STATUS_ERROR_INVALID_IMAGE_FORMAT:
             return "invalid VAImageFormat";
+        case VA_STATUS_ERROR_INVALID_VALUE:
+            return "an invalid/unsupported value was supplied";
+        case VA_STATUS_ERROR_UNSUPPORTED_FILTER:
+            return "the requested filter is not supported";
+        case VA_STATUS_ERROR_INVALID_FILTER_CHAIN:
+            return "an invalid filter chain was supplied";
         case VA_STATUS_ERROR_UNKNOWN:
             return "unknown libva error";
     }
     return "unknown libva error / description missing";
 }
-      
+
+const static char *prefer_driver_list[4] = {
+    "i965",
+    "hybrid",
+    "pvr",
+    "iHD",
+};
+
+VAStatus vaSetDriverName(
+    VADisplay dpy,
+    char *driver_name
+)
+{
+    VADriverContextP ctx;
+    VAStatus vaStatus = VA_STATUS_SUCCESS;
+    char *override_driver_name = NULL;
+    int i, found;
+    ctx = CTX(dpy);
+
+    if (geteuid() != getuid()) {
+        vaStatus = VA_STATUS_ERROR_OPERATION_FAILED;
+        va_errorMessage("no permission to vaSetDriverName\n");
+        return vaStatus;
+    }
+
+    if (strlen(driver_name) == 0 || strlen(driver_name) >=256) {
+        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
+        va_errorMessage("vaSetDriverName returns %s\n",
+                         vaErrorStr(vaStatus));
+        return vaStatus;
+    }
+
+    found = 0;
+    for (i = 0; i < sizeof(prefer_driver_list) / sizeof(char *); i++) {
+        if (strlen(prefer_driver_list[i]) != strlen(driver_name))
+            continue;
+        if (!strncmp(prefer_driver_list[i], driver_name, strlen(driver_name))) {
+            found = 1;
+            break;
+        }
+    }
+
+    if (!found) {
+        vaStatus = VA_STATUS_ERROR_INVALID_PARAMETER;
+        va_errorMessage("vaSetDriverName returns %s. Incorrect parameter\n",
+                         vaErrorStr(vaStatus));
+        return vaStatus;
+    }
+
+    override_driver_name = strdup(driver_name);
+
+    if (!override_driver_name) {
+        vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
+        va_errorMessage("vaSetDriverName returns %s. Out of Memory\n",
+                         vaErrorStr(vaStatus));
+        return vaStatus;
+    }
+
+    ctx->override_driver_name = override_driver_name;
+    return VA_STATUS_SUCCESS;
+}
+
 VAStatus vaInitialize (
     VADisplay dpy,
     int *major_version,         /* out */
@@ -396,40 +599,65 @@ VAStatus vaInitialize (
     const char *driver_name_env = NULL;
     char *driver_name = NULL;
     VAStatus vaStatus;
+    VADriverContextP ctx;
 
     CHECK_DISPLAY(dpy);
 
+    ctx = CTX(dpy);
+
     va_TraceInit(dpy);
 
     va_FoolInit(dpy);
 
-    va_infoMessage("libva version %s\n", VA_VERSION_S);
+    va_MessagingInit();
+
+    va_infoMessage("VA-API version %s\n", VA_VERSION_S);
+
+    vaStatus = va_getDriverName(dpy, &driver_name);
+
+    if (!ctx->override_driver_name) {
+        va_infoMessage("va_getDriverName() returns %d\n", vaStatus);
+
+        driver_name_env = getenv("LIBVA_DRIVER_NAME");
+    } else if (vaStatus == VA_STATUS_SUCCESS) {
+        if (driver_name)
+            free(driver_name);
+
+        driver_name = strdup(ctx->override_driver_name);
+        if (!driver_name) {
+            vaStatus = VA_STATUS_ERROR_ALLOCATION_FAILED;
+            va_errorMessage("vaInitialize() failed with %s, out of memory\n",
+                        vaErrorStr(vaStatus));
+            return vaStatus;
+        }
+        va_infoMessage("User requested driver '%s'\n", driver_name);
+    }
 
-    driver_name_env = getenv("LIBVA_DRIVER_NAME");
-    if (driver_name_env && geteuid() == getuid())
-    {
+    if (driver_name_env && (geteuid() == getuid())) {
         /* Don't allow setuid apps to use LIBVA_DRIVER_NAME */
+        if (driver_name) /* memory is allocated in va_getDriverName */
+            free(driver_name);
+        
         driver_name = strdup(driver_name_env);
         vaStatus = VA_STATUS_SUCCESS;
         va_infoMessage("User requested driver '%s'\n", driver_name);
     }
-    else
-    {
-        vaStatus = va_getDriverName(dpy, &driver_name);
-        va_infoMessage("va_getDriverName() returns %d\n", vaStatus);
-    }
 
-    if (VA_STATUS_SUCCESS == vaStatus)
-    {
+    if ((VA_STATUS_SUCCESS == vaStatus) && (driver_name != NULL)) {
         vaStatus = va_openDriver(dpy, driver_name);
         va_infoMessage("va_openDriver() returns %d\n", vaStatus);
 
         *major_version = VA_MAJOR_VERSION;
         *minor_version = VA_MINOR_VERSION;
-    }
+    } else
+        va_errorMessage("va_getDriverName() failed with %s,driver_name=%s\n",
+                        vaErrorStr(vaStatus), driver_name);
 
     if (driver_name)
         free(driver_name);
+    
+    VA_TRACE_LOG(va_TraceInitialize, dpy, major_version, minor_version);
+
     return vaStatus;
 }
 
@@ -455,14 +683,23 @@ VAStatus vaTerminate (
   }
   free(old_ctx->vtable);
   old_ctx->vtable = NULL;
+  free(old_ctx->vtable_vpp);
+  old_ctx->vtable_vpp = NULL;
 
-  if (VA_STATUS_SUCCESS == vaStatus)
-      pDisplayContext->vaDestroy(pDisplayContext);
+  if (old_ctx->override_driver_name) {
+      free(old_ctx->override_driver_name);
+      old_ctx->override_driver_name = NULL;
+  }
+
+  VA_TRACE_LOG(va_TraceTerminate, dpy);
 
   va_TraceEnd(dpy);
 
   va_FoolEnd(dpy);
 
+  if (VA_STATUS_SUCCESS == vaStatus)
+      pDisplayContext->vaDestroy(pDisplayContext);
+
   return vaStatus;
 }
 
@@ -478,7 +715,7 @@ const char *vaQueryVendorString (
     VADisplay dpy
 )
 {
-  if( !vaDisplayIsValid(dpy) )
+  if (!vaDisplayIsValid(dpy))
       return NULL;
   
   return CTX(dpy)->str_vendor;
@@ -490,7 +727,7 @@ int vaMaxNumProfiles (
     VADisplay dpy
 )
 {
-  if( !vaDisplayIsValid(dpy) )
+  if (!vaDisplayIsValid(dpy))
       return 0;
   
   return CTX(dpy)->max_profiles;
@@ -501,7 +738,7 @@ int vaMaxNumEntrypoints (
     VADisplay dpy
 )
 {
-  if( !vaDisplayIsValid(dpy) )
+  if (!vaDisplayIsValid(dpy))
       return 0;
   
   return CTX(dpy)->max_entrypoints;
@@ -513,7 +750,7 @@ int vaMaxNumConfigAttributes (
     VADisplay dpy
 )
 {
-  if( !vaDisplayIsValid(dpy) )
+  if (!vaDisplayIsValid(dpy))
       return 0;
   
   return CTX(dpy)->max_attributes;
@@ -572,16 +809,15 @@ VAStatus vaCreateConfig (
 {
   VADriverContextP ctx;
   VAStatus vaStatus = VA_STATUS_SUCCESS;
-  int ret = 0;
   
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
 
-  VA_FOOL(va_FoolCreateConfig, dpy, profile, entrypoint, attrib_list, num_attribs, config_id);
-  
-  vaStatus =  ctx->vtable->vaCreateConfig ( ctx, profile, entrypoint, attrib_list, num_attribs, config_id );
+  vaStatus = ctx->vtable->vaCreateConfig ( ctx, profile, entrypoint, attrib_list, num_attribs, config_id );
 
-  VA_TRACE(va_TraceCreateConfig, dpy, profile, entrypoint, attrib_list, num_attribs, config_id);
+  /* record the current entrypoint for further trace/fool determination */
+  VA_TRACE_ALL(va_TraceCreateConfig, dpy, profile, entrypoint, attrib_list, num_attribs, config_id);
+  VA_FOOL_FUNC(va_FoolCreateConfig, dpy, profile, entrypoint, attrib_list, num_attribs, config_id);
   
   return vaStatus;
 }
@@ -592,10 +828,16 @@ VAStatus vaDestroyConfig (
 )
 {
   VADriverContextP ctx;
+  VAStatus vaStatus = VA_STATUS_SUCCESS;
+
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
 
-  return ctx->vtable->vaDestroyConfig ( ctx, config_id );
+  vaStatus = ctx->vtable->vaDestroyConfig ( ctx, config_id );
+
+  VA_TRACE_ALL(va_TraceDestroyConfig, dpy, config_id);
+
+  return vaStatus;
 }
 
 VAStatus vaQueryConfigAttributes (
@@ -614,29 +856,204 @@ VAStatus vaQueryConfigAttributes (
   return ctx->vtable->vaQueryConfigAttributes( ctx, config_id, profile, entrypoint, attrib_list, num_attribs);
 }
 
-VAStatus vaCreateSurfaces (
-    VADisplay dpy,
-    int width,
-    int height,
-    int format,
-    int num_surfaces,
-    VASurfaceID *surfaces      /* out */
+/* XXX: this is a slow implementation that will be removed */
+static VAStatus
+va_impl_query_surface_attributes(
+    VADriverContextP    ctx,
+    VAConfigID          config,
+    VASurfaceAttrib    *out_attribs,
+    unsigned int       *out_num_attribs_ptr
 )
 {
-  VADriverContextP ctx;
-  VAStatus vaStatus;
-  int ret = 0;
-  
-  CHECK_DISPLAY(dpy);
-  ctx = CTX(dpy);
+    VASurfaceAttrib *attribs = NULL;
+    unsigned int num_attribs, n;
+    VASurfaceAttrib *out_attrib;
+    unsigned int out_num_attribs;
+    VAImageFormat *image_formats = NULL;
+    int num_image_formats, i;
+    VAStatus va_status;
+
+    /* List of surface attributes to query */
+    struct va_surface_attrib_map {
+        VASurfaceAttribType type;
+        VAGenericValueType  value_type;
+    };
+    static const struct va_surface_attrib_map attribs_map[] = {
+        { VASurfaceAttribMinWidth,      VAGenericValueTypeInteger },
+        { VASurfaceAttribMaxWidth,      VAGenericValueTypeInteger },
+        { VASurfaceAttribMinHeight,     VAGenericValueTypeInteger },
+        { VASurfaceAttribMaxHeight,     VAGenericValueTypeInteger },
+        { VASurfaceAttribMemoryType,    VAGenericValueTypeInteger },
+        { VASurfaceAttribNone, }
+    };
+
+    if (!out_attribs || !out_num_attribs_ptr)
+        return VA_STATUS_ERROR_INVALID_PARAMETER;
+    if (!ctx->vtable->vaGetSurfaceAttributes)
+        return VA_STATUS_ERROR_UNIMPLEMENTED;
+
+    num_image_formats = ctx->max_image_formats;
+    image_formats = malloc(num_image_formats * sizeof(*image_formats));
+    if (!image_formats) {
+        va_status = VA_STATUS_ERROR_ALLOCATION_FAILED;
+        goto end;
+    }
 
-  vaStatus = ctx->vtable->vaCreateSurfaces( ctx, width, height, format, num_surfaces, surfaces );
+    va_status = ctx->vtable->vaQueryImageFormats(
+        ctx, image_formats, &num_image_formats);
+    if (va_status != VA_STATUS_SUCCESS)
+        goto end;
 
-  VA_TRACE(va_TraceCreateSurface, dpy, width, height, format, num_surfaces, surfaces);
+    num_attribs = VASurfaceAttribCount + num_image_formats;
+    attribs = malloc(num_attribs * sizeof(*attribs));
+    if (!attribs) {
+        va_status = VA_STATUS_ERROR_ALLOCATION_FAILED;
+        goto end;
+    }
 
-  VA_FOOL(va_FoolCreateSurfaces, dpy, width, height, format, num_surfaces, surfaces);
-  
-  return vaStatus;
+    /* Initialize with base surface attributes, except pixel-formats */
+    for (n = 0; attribs_map[n].type != VASurfaceAttribNone; n++) {
+        VASurfaceAttrib * const attrib = &attribs[n];
+        attrib->type = attribs_map[n].type;
+        attrib->flags = VA_SURFACE_ATTRIB_GETTABLE;
+        attrib->value.type = attribs_map[n].value_type;
+    }
+
+    /* Append image formats */
+    for (i = 0; i < num_image_formats; i++) {
+        VASurfaceAttrib * const attrib = &attribs[n];
+        attrib->type = VASurfaceAttribPixelFormat;
+        attrib->flags = VA_SURFACE_ATTRIB_GETTABLE|VA_SURFACE_ATTRIB_SETTABLE;
+        attrib->value.type = VAGenericValueTypeInteger;
+        attrib->value.value.i = image_formats[i].fourcc;
+        if (++n == num_attribs) {
+            va_status = VA_STATUS_ERROR_ALLOCATION_FAILED;
+            goto end;
+        }
+    }
+    num_attribs = n;
+
+    va_status = ctx->vtable->vaGetSurfaceAttributes(
+        ctx, config, attribs, num_attribs);
+    if (va_status != VA_STATUS_SUCCESS)
+        goto end;
+
+    /* Remove invalid entries */
+    out_num_attribs = 0;
+    for (n = 0; n < num_attribs; n++) {
+        VASurfaceAttrib * const attrib = &attribs[n];
+
+        if (attrib->flags == VA_SURFACE_ATTRIB_NOT_SUPPORTED)
+            continue;
+
+        // Accept all surface attributes that are not pixel-formats
+        if (attrib->type != VASurfaceAttribPixelFormat) {
+            out_num_attribs++;
+            continue;
+        }
+
+        // Drop invalid pixel-format attribute
+        if (!attrib->value.value.i) {
+            attrib->flags = VA_SURFACE_ATTRIB_NOT_SUPPORTED;
+            continue;
+        }
+
+        // Check for duplicates
+        int is_duplicate = 0;
+        for (i = n - 1; i >= 0 && !is_duplicate; i--) {
+            const VASurfaceAttrib * const prev_attrib = &attribs[i];
+            if (prev_attrib->type != VASurfaceAttribPixelFormat)
+                break;
+            is_duplicate = prev_attrib->value.value.i == attrib->value.value.i;
+        }
+        if (is_duplicate)
+            attrib->flags = VA_SURFACE_ATTRIB_NOT_SUPPORTED;
+        else
+            out_num_attribs++;
+    }
+
+    if (*out_num_attribs_ptr < out_num_attribs) {
+        *out_num_attribs_ptr = out_num_attribs;
+        va_status = VA_STATUS_ERROR_MAX_NUM_EXCEEDED;
+        goto end;
+    }
+
+    out_attrib = out_attribs;
+    for (n = 0; n < num_attribs; n++) {
+        const VASurfaceAttrib * const attrib = &attribs[n];
+        if (attrib->flags == VA_SURFACE_ATTRIB_NOT_SUPPORTED)
+            continue;
+        *out_attrib++ = *attrib;
+    }
+
+end:
+    free(attribs);
+    free(image_formats);
+    return va_status;
+}
+
+VAStatus
+vaQuerySurfaceAttributes(
+    VADisplay           dpy,
+    VAConfigID          config,
+    VASurfaceAttrib    *attrib_list,
+    unsigned int       *num_attribs
+)
+{
+    VADriverContextP ctx;
+    VAStatus vaStatus;
+
+    CHECK_DISPLAY(dpy);
+    ctx = CTX(dpy);
+    if (!ctx)
+        return VA_STATUS_ERROR_INVALID_DISPLAY;
+
+    if (!ctx->vtable->vaQuerySurfaceAttributes)
+        vaStatus = va_impl_query_surface_attributes(ctx, config,
+                                                    attrib_list, num_attribs);
+    else
+        vaStatus = ctx->vtable->vaQuerySurfaceAttributes(ctx, config,
+                                                         attrib_list, num_attribs);
+
+    VA_TRACE_LOG(va_TraceQuerySurfaceAttributes, dpy, config, attrib_list, num_attribs);
+
+    return vaStatus;
+}
+
+VAStatus
+vaCreateSurfaces(
+    VADisplay           dpy,
+    unsigned int        format,
+    unsigned int        width,
+    unsigned int        height,
+    VASurfaceID        *surfaces,
+    unsigned int        num_surfaces,
+    VASurfaceAttrib    *attrib_list,
+    unsigned int        num_attribs
+)
+{
+    VADriverContextP ctx;
+    VAStatus vaStatus;
+
+    CHECK_DISPLAY(dpy);
+    ctx = CTX(dpy);
+    if (!ctx)
+        return VA_STATUS_ERROR_INVALID_DISPLAY;
+
+    if (ctx->vtable->vaCreateSurfaces2)
+        vaStatus = ctx->vtable->vaCreateSurfaces2(ctx, format, width, height,
+                                              surfaces, num_surfaces,
+                                              attrib_list, num_attribs);
+    else if (attrib_list && num_attribs > 0)
+        vaStatus = VA_STATUS_ERROR_ATTR_NOT_SUPPORTED;
+    else
+        vaStatus = ctx->vtable->vaCreateSurfaces(ctx, width, height, format,
+                                                 num_surfaces, surfaces);
+    VA_TRACE_LOG(va_TraceCreateSurfaces,
+                 dpy, width, height, format, num_surfaces, surfaces,
+                 attrib_list, num_attribs);
+
+    return vaStatus;
 }
 
 
@@ -647,10 +1064,17 @@ VAStatus vaDestroySurfaces (
 )
 {
   VADriverContextP ctx;
+  VAStatus vaStatus;
+  
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
 
-  return ctx->vtable->vaDestroySurfaces( ctx, surface_list, num_surfaces );
+  VA_TRACE_LOG(va_TraceDestroySurfaces,
+               dpy, surface_list, num_surfaces);
+  
+  vaStatus = ctx->vtable->vaDestroySurfaces( ctx, surface_list, num_surfaces );
+  
+  return vaStatus;
 }
 
 VAStatus vaCreateContext (
@@ -673,7 +1097,8 @@ VAStatus vaCreateContext (
   vaStatus = ctx->vtable->vaCreateContext( ctx, config_id, picture_width, picture_height,
                                       flag, render_targets, num_render_targets, context );
 
-  VA_TRACE(va_TraceCreateContext, dpy, config_id, picture_width, picture_height, flag, render_targets, num_render_targets, context);
+  /* keep current encode/decode resoluton */
+  VA_TRACE_ALL(va_TraceCreateContext, dpy, config_id, picture_width, picture_height, flag, render_targets, num_render_targets, context);
 
   return vaStatus;
 }
@@ -684,10 +1109,16 @@ VAStatus vaDestroyContext (
 )
 {
   VADriverContextP ctx;
+  VAStatus vaStatus;
+
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
 
-  return ctx->vtable->vaDestroyContext( ctx, context );
+  vaStatus = ctx->vtable->vaDestroyContext( ctx, context );
+
+  VA_TRACE_ALL(va_TraceDestroyContext, dpy, context);
+
+  return vaStatus;
 }
 
 VAStatus vaCreateBuffer (
@@ -701,15 +1132,19 @@ VAStatus vaCreateBuffer (
 )
 {
   VADriverContextP ctx;
+  VAStatus vaStatus;
+  
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
-  int ret = 0;
-  
-  VA_FOOL(va_FoolCreateBuffer, dpy, context, type, size, num_elements, data, buf_id);
-  if (ret)
-      return VA_STATUS_SUCCESS;
+
+  VA_FOOL_FUNC(va_FoolCreateBuffer, dpy, context, type, size, num_elements, data, buf_id);
+
+  vaStatus = ctx->vtable->vaCreateBuffer( ctx, context, type, size, num_elements, data, buf_id);
+
+  VA_TRACE_LOG(va_TraceCreateBuffer,
+               dpy, context, type, size, num_elements, data, buf_id);
   
-  return ctx->vtable->vaCreateBuffer( ctx, context, type, size, num_elements, data, buf_id);
+  return vaStatus;
 }
 
 VAStatus vaBufferSetNumElements (
@@ -722,6 +1157,8 @@ VAStatus vaBufferSetNumElements (
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
 
+  VA_FOOL_FUNC(va_FoolCheckContinuity, dpy);
+  
   return ctx->vtable->vaBufferSetNumElements( ctx, buf_id, num_elements );
 }
 
@@ -734,19 +1171,15 @@ VAStatus vaMapBuffer (
 {
   VADriverContextP ctx;
   VAStatus va_status;
-  int ret = 0;
   
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
   
-  VA_FOOL(va_FoolMapBuffer, dpy, buf_id, pbuf);
-  if (ret)
-      return VA_STATUS_SUCCESS;
+  VA_FOOL_FUNC(va_FoolMapBuffer, dpy, buf_id, pbuf);
   
   va_status = ctx->vtable->vaMapBuffer( ctx, buf_id, pbuf );
 
-  if (va_status == VA_STATUS_SUCCESS)
-      VA_TRACE(va_TraceMapBuffer, dpy, buf_id, pbuf);
+  VA_TRACE_ALL(va_TraceMapBuffer, dpy, buf_id, pbuf);
   
   return va_status;
 }
@@ -759,12 +1192,9 @@ VAStatus vaUnmapBuffer (
   VADriverContextP ctx;
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
-  int ret = 0;
-  
-  VA_FOOL(va_FoolUnmapBuffer, dpy, buf_id);
-  if (ret)
-      return VA_STATUS_SUCCESS;
-  
+
+  VA_FOOL_FUNC(va_FoolCheckContinuity, dpy);
+
   return ctx->vtable->vaUnmapBuffer( ctx, buf_id );
 }
 
@@ -777,6 +1207,11 @@ VAStatus vaDestroyBuffer (
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
 
+  VA_FOOL_FUNC(va_FoolCheckContinuity, dpy);
+
+  VA_TRACE_LOG(va_TraceDestroyBuffer,
+               dpy, buffer_id);
+  
   return ctx->vtable->vaDestroyBuffer( ctx, buffer_id );
 }
 
@@ -790,10 +1225,41 @@ VAStatus vaBufferInfo (
 )
 {
   VADriverContextP ctx;
+  
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
 
-  return ctx->vtable->vaBufferInfo( ctx, context, buf_id, type, size, num_elements );
+  VA_FOOL_FUNC(va_FoolBufferInfo, dpy, buf_id, type, size, num_elements);
+  
+  return ctx->vtable->vaBufferInfo( ctx, buf_id, type, size, num_elements );
+}
+
+/* Locks buffer for external API usage */
+VAStatus
+vaAcquireBufferHandle(VADisplay dpy, VABufferID buf_id, VABufferInfo *buf_info)
+{
+    VADriverContextP ctx;
+
+    CHECK_DISPLAY(dpy);
+    ctx = CTX(dpy);
+
+    if (!ctx->vtable->vaAcquireBufferHandle)
+        return VA_STATUS_ERROR_UNIMPLEMENTED;
+    return ctx->vtable->vaAcquireBufferHandle(ctx, buf_id, buf_info);
+}
+
+/* Unlocks buffer after usage from external API */
+VAStatus
+vaReleaseBufferHandle(VADisplay dpy, VABufferID buf_id)
+{
+    VADriverContextP ctx;
+
+    CHECK_DISPLAY(dpy);
+    ctx = CTX(dpy);
+
+    if (!ctx->vtable->vaReleaseBufferHandle)
+        return VA_STATUS_ERROR_UNIMPLEMENTED;
+    return ctx->vtable->vaReleaseBufferHandle(ctx, buf_id);
 }
 
 VAStatus vaBeginPicture (
@@ -803,18 +1269,17 @@ VAStatus vaBeginPicture (
 )
 {
   VADriverContextP ctx;
-  int ret = 0;
-  
+  VAStatus va_status;
+
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
 
-  VA_TRACE(va_TraceBeginPicture, dpy, context, render_target);
-
-  VA_FOOL(va_FoolBeginPicture, dpy, context, render_target);
-  if (ret)
-      return VA_STATUS_SUCCESS;
-
-  return ctx->vtable->vaBeginPicture( ctx, context, render_target );
+  VA_TRACE_ALL(va_TraceBeginPicture, dpy, context, render_target);
+  VA_FOOL_FUNC(va_FoolCheckContinuity, dpy);
+  
+  va_status = ctx->vtable->vaBeginPicture( ctx, context, render_target );
+  
+  return va_status;
 }
 
 VAStatus vaRenderPicture (
@@ -825,16 +1290,12 @@ VAStatus vaRenderPicture (
 )
 {
   VADriverContextP ctx;
-  int ret = 0;
-  
+
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
 
-  VA_FOOL(va_FoolRenderPicture, dpy, context, buffers, num_buffers);
-  if (ret)
-      return VA_STATUS_SUCCESS;
-
-  VA_TRACE(va_TraceRenderPicture, dpy, context, buffers, num_buffers);
+  VA_TRACE_LOG(va_TraceRenderPicture, dpy, context, buffers, num_buffers);
+  VA_FOOL_FUNC(va_FoolCheckContinuity, dpy);
 
   return ctx->vtable->vaRenderPicture( ctx, context, buffers, num_buffers );
 }
@@ -844,22 +1305,18 @@ VAStatus vaEndPicture (
     VAContextID context
 )
 {
-  VAStatus va_status;
+  VAStatus va_status = VA_STATUS_SUCCESS;
   VADriverContextP ctx;
-  int ret = 0;
-  
+
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
 
-  VA_FOOL(va_FoolEndPicture, dpy, context);
-  if (ret) {
-      VA_TRACE(va_TraceEndPicture, dpy, context);
-      return VA_STATUS_SUCCESS;
-  }
-  
+  VA_FOOL_FUNC(va_FoolCheckContinuity, dpy);
+
   va_status = ctx->vtable->vaEndPicture( ctx, context );
-  
-  VA_TRACE(va_TraceEndPicture, dpy, context);
+
+  /* dump surface content */
+  VA_TRACE_ALL(va_TraceEndPicture, dpy, context, 1);
 
   return va_status;
 }
@@ -871,17 +1328,12 @@ VAStatus vaSyncSurface (
 {
   VAStatus va_status;
   VADriverContextP ctx;
-  int ret = 0;
-  
+
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
 
-  VA_FOOL(va_FoolSyncSurface, dpy, render_target);
-  if (ret)
-      return VA_STATUS_SUCCESS;
-  
   va_status = ctx->vtable->vaSyncSurface( ctx, render_target );
-  VA_TRACE(va_TraceSyncSurface, dpy, render_target);
+  VA_TRACE_LOG(va_TraceSyncSurface, dpy, render_target);
 
   return va_status;
 }
@@ -899,7 +1351,7 @@ VAStatus vaQuerySurfaceStatus (
 
   va_status = ctx->vtable->vaQuerySurfaceStatus( ctx, render_target, status );
 
-  VA_TRACE(va_TraceQuerySurfaceStatus, dpy, render_target, status);
+  VA_TRACE_LOG(va_TraceQuerySurfaceStatus, dpy, render_target, status);
 
   return va_status;
 }
@@ -918,7 +1370,7 @@ VAStatus vaQuerySurfaceError (
 
   va_status = ctx->vtable->vaQuerySurfaceError( ctx, surface, error_status, error_info );
 
-  VA_TRACE(va_TraceQuerySurfaceError, dpy, surface, error_status, error_info);
+  VA_TRACE_LOG(va_TraceQuerySurfaceError, dpy, surface, error_status, error_info);
 
   return va_status;
 }
@@ -928,7 +1380,7 @@ int vaMaxNumImageFormats (
     VADisplay dpy
 )
 {
-  if( !vaDisplayIsValid(dpy) )
+  if (!vaDisplayIsValid(dpy))
       return 0;
   
   return CTX(dpy)->max_image_formats;
@@ -1094,7 +1546,7 @@ int vaMaxNumSubpictureFormats (
     VADisplay dpy
 )
 {
-  if( !vaDisplayIsValid(dpy) )
+  if (!vaDisplayIsValid(dpy))
       return 0;
   
   return CTX(dpy)->max_subpic_formats;
@@ -1115,15 +1567,10 @@ VAStatus vaQuerySubpictureFormats (
 )
 {
   VADriverContextP ctx;
-  int ret = 0;
-  
+
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
-  
-  VA_FOOL(va_FoolQuerySubpictureFormats, dpy, format_list, flags, num_formats);
-  if (ret)
-      return VA_STATUS_SUCCESS;
-  
+
   return ctx->vtable->vaQuerySubpictureFormats ( ctx, format_list, flags, num_formats);
 }
 
@@ -1269,12 +1716,12 @@ int vaMaxNumDisplayAttributes (
 {
   int tmp;
     
-  if( !vaDisplayIsValid(dpy) )
+  if (!vaDisplayIsValid(dpy))
       return 0;
   
   tmp = CTX(dpy)->max_display_attributes;
 
-  VA_TRACE(va_TraceMaxNumDisplayAttributes, dpy, tmp);
+  VA_TRACE_LOG(va_TraceMaxNumDisplayAttributes, dpy, tmp);
   
   return tmp;
 }
@@ -1292,14 +1739,13 @@ VAStatus vaQueryDisplayAttributes (
 )
 {
   VADriverContextP ctx;
-  CHECK_DISPLAY(dpy);
-  ctx = CTX(dpy);
-
   VAStatus va_status;
   
+  CHECK_DISPLAY(dpy);
+  ctx = CTX(dpy);
   va_status = ctx->vtable->vaQueryDisplayAttributes ( ctx, attr_list, num_attributes );
 
-  VA_TRACE(va_TraceQueryDisplayAttributes, dpy, attr_list, num_attributes);
+  VA_TRACE_LOG(va_TraceQueryDisplayAttributes, dpy, attr_list, num_attributes);
 
   return va_status;
   
@@ -1318,14 +1764,13 @@ VAStatus vaGetDisplayAttributes (
 )
 {
   VADriverContextP ctx;
+  VAStatus va_status;
+
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
-
-  VAStatus va_status;
-  
   va_status = ctx->vtable->vaGetDisplayAttributes ( ctx, attr_list, num_attributes );
 
-  VA_TRACE(va_TraceGetDisplayAttributes, dpy, attr_list, num_attributes);
+  VA_TRACE_LOG(va_TraceGetDisplayAttributes, dpy, attr_list, num_attributes);
   
   return va_status;
 }
@@ -1343,13 +1788,14 @@ VAStatus vaSetDisplayAttributes (
 )
 {
   VADriverContextP ctx;
+  VAStatus va_status;
   CHECK_DISPLAY(dpy);
   ctx = CTX(dpy);
 
-  VA_TRACE(va_TraceSetDisplayAttributes, dpy, attr_list, num_attributes);
-
+  va_status = ctx->vtable->vaSetDisplayAttributes ( ctx, attr_list, num_attributes );
+  VA_TRACE_LOG(va_TraceSetDisplayAttributes, dpy, attr_list, num_attributes);
   
-  return ctx->vtable->vaSetDisplayAttributes ( ctx, attr_list, num_attributes );
+  return va_status;
 }
 
 VAStatus vaLockSurface(VADisplay dpy,
@@ -1383,3 +1829,79 @@ VAStatus vaUnlockSurface(VADisplay dpy,
 
   return ctx->vtable->vaUnlockSurface( ctx, surface );
 }
+
+/* Video Processing */
+#define VA_VPP_INIT_CONTEXT(ctx, dpy) do {              \
+        CHECK_DISPLAY(dpy);                             \
+        ctx = CTX(dpy);                                 \
+        if (!ctx)                                       \
+            return VA_STATUS_ERROR_INVALID_DISPLAY;     \
+    } while (0)
+
+#define VA_VPP_INVOKE(dpy, func, args) do {             \
+        if (!ctx->vtable_vpp->va##func)                 \
+            return VA_STATUS_ERROR_UNIMPLEMENTED;       \
+        status = ctx->vtable_vpp->va##func args;        \
+    } while (0)
+
+VAStatus
+vaQueryVideoProcFilters(
+    VADisplay           dpy,
+    VAContextID         context,
+    VAProcFilterType   *filters,
+    unsigned int       *num_filters
+)
+{
+    VADriverContextP ctx;
+    VAStatus status;
+
+    VA_VPP_INIT_CONTEXT(ctx, dpy);
+    VA_VPP_INVOKE(
+        ctx,
+        QueryVideoProcFilters,
+        (ctx, context, filters, num_filters)
+    );
+    return status;
+}
+
+VAStatus
+vaQueryVideoProcFilterCaps(
+    VADisplay           dpy,
+    VAContextID         context,
+    VAProcFilterType    type,
+    void               *filter_caps,
+    unsigned int       *num_filter_caps
+)
+{
+    VADriverContextP ctx;
+    VAStatus status;
+
+    VA_VPP_INIT_CONTEXT(ctx, dpy);
+    VA_VPP_INVOKE(
+        ctx,
+        QueryVideoProcFilterCaps,
+        (ctx, context, type, filter_caps, num_filter_caps)
+    );
+    return status;
+}
+
+VAStatus
+vaQueryVideoProcPipelineCaps(
+    VADisplay           dpy,
+    VAContextID         context,
+    VABufferID         *filters,
+    unsigned int        num_filters,
+    VAProcPipelineCaps *pipeline_caps
+)
+{
+    VADriverContextP ctx;
+    VAStatus status;
+
+    VA_VPP_INIT_CONTEXT(ctx, dpy);
+    VA_VPP_INVOKE(
+        ctx,
+        QueryVideoProcPipelineCaps,
+        (ctx, context, filters, num_filters, pipeline_caps)
+    );
+    return status;
+}