shithub: dav1d

Download patch

ref: 02312cae6c45a58d1b275ad80eb6c41271415c3b
parent: d3a1ebad5226e2510ca65ef02e148967511df7b3
author: Ronald S. Bultje <[email protected]>
date: Fri Dec 7 05:38:19 EST 2018

Implement --cpumask to mask out CPU features

Fixes #198.

Usage: --cpumask=0xf or --cpumask=ssse3 will select up to and
including SSSE3 (so SSE+SSE2+SSE3+SSSE3).

--- a/tools/dav1d_cli_parse.c
+++ b/tools/dav1d_cli_parse.c
@@ -39,11 +39,12 @@
 #endif
 
 #include "dav1d_cli_parse.h"
+#include "src/cpu.h"
 
 static const char short_opts[] = "i:o:vql:s:";
 
 enum {
-    ARG_DEMUXER,
+    ARG_DEMUXER = 256,
     ARG_MUXER,
     ARG_FRAME_THREADS,
     ARG_TILE_THREADS,
@@ -51,6 +52,7 @@
     ARG_FILM_GRAIN,
     ARG_OPPOINT,
     ARG_ALL_LAYERS,
+    ARG_CPU_MASK,
 };
 
 static const struct option long_opts[] = {
@@ -68,9 +70,19 @@
     { "filmgrain",      1, NULL, ARG_FILM_GRAIN },
     { "oppoint",        1, NULL, ARG_OPPOINT },
     { "alllayers",      1, NULL, ARG_ALL_LAYERS },
+    { "cpumask",        1, NULL, ARG_CPU_MASK },
     { NULL,             0, NULL, 0 },
 };
 
+#if ARCH_AARCH64 || ARCH_ARM
+#define ALLOWED_CPU_MASKS " or 'neon'"
+#elif ARCH_X86
+#define ALLOWED_CPU_MASKS \
+    ", 'sse2', 'ssse3', 'sse41', 'avx2' or 'avx512'"
+#else
+#define ALLOWED_CPU_MASKS "not yet implemented for this architecture"
+#endif
+
 static void usage(const char *const app, const char *const reason, ...) {
     if (reason) {
         va_list args;
@@ -95,7 +107,8 @@
             " --filmgrain          enable film grain application (default: 1, except if muxer is md5)\n"
             " --oppoint $num:      select an operating point of a scalable AV1 bitstream (0 - 32)\n"
             " --alllayers $num:    output all spatial layers of a scalable AV1 bitstream (default: 1)\n"
-            " --verify $md5:       verify decoded md5. implies --muxer md5, no output\n");
+            " --verify $md5:       verify decoded md5. implies --muxer md5, no output\n"
+            " --cpumask $mask:     restrict permitted CPU instruction sets (0" ALLOWED_CPU_MASKS "; default: -1)\n");
     exit(1);
 }
 
@@ -121,11 +134,78 @@
 
 static unsigned parse_unsigned(char *optarg, const int option, const char *app) {
     char *end;
-    const double res = strtoul(optarg, &end, 0);
+    const unsigned res = strtoul(optarg, &end, 0);
     if (*end || end == optarg) error(app, optarg, option, "an integer");
     return res;
 }
 
+typedef struct EnumParseTable {
+    const char *str;
+    const int val;
+} EnumParseTable;
+
+#if ARCH_X86
+enum CpuMask {
+    X86_CPU_MASK_SSE    = DAV1D_X86_CPU_FLAG_SSE,
+    X86_CPU_MASK_SSE2   = DAV1D_X86_CPU_FLAG_SSE2   | X86_CPU_MASK_SSE,
+    X86_CPU_MASK_SSE3   = DAV1D_X86_CPU_FLAG_SSE3   | X86_CPU_MASK_SSE2,
+    X86_CPU_MASK_SSSE3  = DAV1D_X86_CPU_FLAG_SSSE3  | X86_CPU_MASK_SSE3,
+    X86_CPU_MASK_SSE41  = DAV1D_X86_CPU_FLAG_SSE41  | X86_CPU_MASK_SSSE3,
+    X86_CPU_MASK_SSE42  = DAV1D_X86_CPU_FLAG_SSE42  | X86_CPU_MASK_SSE41,
+    X86_CPU_MASK_AVX    = DAV1D_X86_CPU_FLAG_AVX    | X86_CPU_MASK_SSE42,
+    X86_CPU_MASK_AVX2   = DAV1D_X86_CPU_FLAG_AVX2   | X86_CPU_MASK_AVX,
+    X86_CPU_MASK_AVX512 = DAV1D_X86_CPU_FLAG_AVX512 | X86_CPU_MASK_AVX2,
+};
+#endif
+
+static const EnumParseTable cpu_mask_tbl[] = {
+#if ARCH_AARCH64 || ARCH_ARM
+    { "neon", DAV1D_ARM_CPU_FLAG_NEON },
+#elif ARCH_X86
+    { "sse2",   X86_CPU_MASK_SSE },
+    { "ssse3",  X86_CPU_MASK_SSSE3 },
+    { "sse41",  X86_CPU_MASK_SSE41 },
+    { "avx2",   X86_CPU_MASK_AVX2 },
+    { "avx512", X86_CPU_MASK_AVX512 },
+#endif
+    { 0 },
+};
+
+static unsigned parse_enum(char *optarg, const EnumParseTable *const tbl,
+                           const int option, const char *app)
+{
+    char str[1024];
+
+    strcpy(str, "any of ");
+    for (int n = 0; tbl[n].str; n++) {
+        if (!strcmp(tbl[n].str, optarg))
+            return tbl[n].val;
+
+        if (n) {
+            if (!tbl[n + 1].str)
+                strcat(str, " or ");
+            else
+                strcat(str, ", ");
+        }
+        strcat(str, tbl[n].str);
+    }
+
+    char *end;
+    unsigned res;
+    if (!strncmp(optarg, "0x", 2)) {
+        res = strtoul(&optarg[2], &end, 16);
+    } else {
+        res = strtoul(optarg, &end, 0);
+    }
+
+    if (*end || end == optarg) {
+        strcat(str, ", a hexadecimal (starting with 0x), or an integer");
+        error(app, optarg, option, str);
+    }
+
+    return res;
+}
+
 void parse(const int argc, char *const *const argv,
            CLISettings *const cli_settings, Dav1dSettings *const lib_settings)
 {
@@ -185,6 +265,10 @@
         case 'v':
             fprintf(stderr, "%s\n", dav1d_version());
             exit(0);
+        case ARG_CPU_MASK:
+            dav1d_set_cpu_flags_mask(parse_enum(optarg, cpu_mask_tbl,
+                                                ARG_CPU_MASK, argv[0]));
+            break;
         default:
             usage(argv[0], NULL);
         }