diff --git a/.github/workflows/EnterDevShell.ps1 b/.github/workflows/EnterDevShell.ps1 new file mode 100644 index 00000000..e4640a98 --- /dev/null +++ b/.github/workflows/EnterDevShell.ps1 @@ -0,0 +1,38 @@ +param( + [Parameter()] + [String]$architecture +) + +function EnterDevShellEnv { + + param( + [Parameter()] + [String]$arch + ) + + $vsw = Get-Command 'vswhere' + $VSFfavors = 'Community','Professional','Enterprise','BuildTools' | %{ "Microsoft.VisualStudio.Product.$_" } + $vs = & $vsw.Path -products $VSFfavors -latest -format json | ConvertFrom-Json + $tools_dir = Join-Path $vs.installationPath 'Common7' 'Tools' + # Try the root tools dir + $devshell = Join-Path $tools_dir 'Microsoft.VisualStudio.DevShell.dll' + # Try finding it under vsdevshell + if (!(Test-Path $devshell -Type Leaf)) { + $devshell = Join-Path $tools_dir 'vsdevshell' 'Microsoft.VisualStudio.DevShell.dll' + } + # Fail if didn't find the DevShell library + if (!(Test-Path $devshell -Type Leaf)) { + throw "error: cannot find Microsoft.VisualStudio.DevShell.dll" + } + Import-Module $devshell + Enter-VsDevShell -VsInstanceId $vs.instanceId -SkipAutomaticLocation -DevCmdArguments "-arch=$arch -no_logo" +} + +# Enter VsDevShell, capture the environment difference and export it to github env +$env_before = @{} +Get-ChildItem env: | %{ $env_before.Add($_.Name, $_.Value) } +EnterDevShellEnv -arch "$architecture" +$env_after = @{} +Get-ChildItem env: | %{ $env_after.Add($_.Name, $_.Value) } +$env_diff = $env_after.GetEnumerator() | where { -not $env_before.ContainsKey($_.Name) -or $env_before[$_.Name] -ne $_.Value } +$env_diff | %{ echo "$($_.Name)=$($_.Value)" >> $env:GITHUB_ENV } diff --git a/.github/workflows/windows.yml b/.github/workflows/windows.yml new file mode 100644 index 00000000..8667fded --- /dev/null +++ b/.github/workflows/windows.yml @@ -0,0 +1,101 @@ +name: windows + +on: + push: + paths-ignore: + - '.github/workflows/**' + - '!.github/workflows/windows.yml' + - '!.github/workflows/EnterDevShell.ps1' + pull_request: + paths-ignore: + - '.github/workflows/**' + - '!.github/workflows/windows.yml' + - '!.github/workflows/EnterDevShell.ps1' + +jobs: + windows-msvc: + runs-on: windows-2022 + steps: + - name: checkout libva + uses: actions/checkout@v2 + with: + repository: intel/libva + path: libva + - name: checkout libva-utils + uses: actions/checkout@v2 + with: + path: libva-utils + - name: 'Setup Python' + uses: actions/setup-python@v2 + with: + python-version: '3.x' + - name: Install Meson + run: pip install meson + - name: Install pkg-config + shell: pwsh + run: | + Invoke-RestMethod -Uri https://download.gnome.org/binaries/win32/dependencies/pkg-config_0.26-1_win32.zip -OutFile pkg-config_0.26-1_win32.zip + Expand-Archive pkg-config_0.26-1_win32.zip + Invoke-RestMethod -Uri http://ftp.gnome.org/pub/gnome/binaries/win32/glib/2.28/glib_2.28.8-1_win32.zip -OutFile glib_2.28.8-1_win32.zip + Expand-Archive glib_2.28.8-1_win32.zip + Invoke-RestMethod -Uri http://ftp.gnome.org/pub/gnome/binaries/win32/dependencies/gettext-runtime_0.18.1.1-2_win32.zip -OutFile gettext-runtime_0.18.1.1-2_win32.zip + Expand-Archive gettext-runtime_0.18.1.1-2_win32.zip + mkdir pkg-config + cp pkg-config_0.26-1_win32\bin\* pkg-config\ + cp gettext-runtime_0.18.1.1-2_win32\bin\* pkg-config\ + cp glib_2.28.8-1_win32\bin\* pkg-config\ + - name: Enter DevShell + run: 'libva-utils\.github\workflows\EnterDevShell.ps1 ${{ inputs.architecture }}' + shell: pwsh + - name: Build libva + run: | + cd libva + meson build + ninja -C build install + - name: Build libva-utils + run: | + $env:Path += ";" + $env:Path += Resolve-Path pkg-config\ + $env:Path += ";c:\bin\;c:\lib\" + $env:PKG_CONFIG_PATH = "C:\lib\pkgconfig" + del C:\Strawberry\perl\bin\pkg-config* + cd libva-utils + meson build -Dtests=true + ninja -C build install + + windows-mingw: + runs-on: windows-2022 + defaults: + run: + shell: msys2 {0} + steps: + - name: checkout libva + uses: actions/checkout@v2 + with: + repository: intel/libva + path: libva + - name: checkout libva-utils + uses: actions/checkout@v2 + with: + path: libva-utils + - name: 'Setup MSYS2' + uses: msys2/setup-msys2@v2 + with: + msystem: mingw64 + update: false + pacboy: >- + toolchain:p + meson:p + - name: Enter DevShell + run: 'libva-utils\.github\workflows\EnterDevShell.ps1 ${{ inputs.architecture }}' + shell: pwsh + - name: Build libva + run: | + cd libva + CC=gcc meson build + CC=gcc ninja -C build install + - name: Build libva-utils + run: | + cd libva-utils + CC=gcc meson build -Dtests=true + CC=gcc ninja -C build install diff --git a/common/meson.build b/common/meson.build index 384d41db..3d1da1e3 100644 --- a/common/meson.build +++ b/common/meson.build @@ -16,6 +16,11 @@ if use_wayland libva_display_deps += wayland_deps endif +if use_win32 + libva_display_src += [ 'va_display_win32.c' ] + libva_display_deps += win32_deps +endif + libva_display_lib = static_library('common', libva_display_src, dependencies: libva_display_deps, include_directories: include_directories('.')) diff --git a/common/va_display.c b/common/va_display.c index b7a85969..b98fdf73 100644 --- a/common/va_display.c +++ b/common/va_display.c @@ -36,12 +36,16 @@ extern const VADisplayHooks va_display_hooks_android; extern const VADisplayHooks va_display_hooks_wayland; extern const VADisplayHooks va_display_hooks_x11; extern const VADisplayHooks va_display_hooks_drm; +extern const VADisplayHooks va_display_hooks_win32; static const VADisplayHooks *g_display_hooks; static const VADisplayHooks *g_display_hooks_available[] = { #ifdef ANDROID &va_display_hooks_android, #else +#ifdef HAVE_VA_WIN32 + &va_display_hooks_win32, +#endif #ifdef HAVE_VA_WAYLAND &va_display_hooks_wayland, #endif diff --git a/common/va_display_win32.c b/common/va_display_win32.c new file mode 100644 index 00000000..ac08fbc7 --- /dev/null +++ b/common/va_display_win32.c @@ -0,0 +1,57 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#include +#include +#include +#include "va_display.h" + +static VADisplay +va_open_display_win32(void) +{ + // Choose default adapter on NULL + return vaGetDisplayWin32(NULL); +} + +static void +va_close_display_win32(VADisplay va_dpy) +{ +} + +static VAStatus +va_put_surface_win32( + VADisplay va_dpy, + VASurfaceID surface, + const VARectangle *src_rect, + const VARectangle *dst_rect +) +{ + return VA_STATUS_ERROR_OPERATION_FAILED; +} + +const VADisplayHooks va_display_hooks_win32 = { + "win32", + va_open_display_win32, + va_close_display_win32, + va_put_surface_win32, +}; diff --git a/getopt/getopt.h b/getopt/getopt.h new file mode 100644 index 00000000..92ae2a90 --- /dev/null +++ b/getopt/getopt.h @@ -0,0 +1,82 @@ +/* $OpenBSD: getopt.h,v 1.2 2008/06/26 05:42:04 ray Exp $ */ +/* $NetBSD: getopt.h,v 1.4 2000/07/07 10:43:54 ad Exp $ */ + +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef _GETOPT_H_ +#define _GETOPT_H_ + +/* + * GNU-like getopt_long() and 4.4BSD getsubopt()/optreset extensions + */ +#define no_argument 0 +#define required_argument 1 +#define optional_argument 2 + +#ifdef __cplusplus +extern "C" { +#endif + +struct option { + /* name of long option */ + const char *name; + /* + * one of no_argument, required_argument, and optional_argument: + * whether option takes an argument + */ + int has_arg; + /* if not NULL, set *flag to val when option found */ + int *flag; + /* if flag not NULL, value to set *flag to; else return value */ + int val; +}; + +int getopt_long(int, char * const *, const char *, + const struct option *, int *); +int getopt_long_only(int, char * const *, const char *, + const struct option *, int *); +#ifndef _GETOPT_DEFINED_ +#define _GETOPT_DEFINED_ +int getopt(int, char * const *, const char *); +int getsubopt(char **, char * const *, char **); + +extern char *optarg; /* getopt(3) external variables */ +extern int opterr; +extern int optind; +extern int optopt; +extern int optreset; +extern char *suboptarg; /* getsubopt(3) external variable */ +#endif + +#ifdef __cplusplus +} +#endif + +#endif /* !_GETOPT_H_ */ diff --git a/getopt/getopt_long.c b/getopt/getopt_long.c new file mode 100644 index 00000000..ccc53fdd --- /dev/null +++ b/getopt/getopt_long.c @@ -0,0 +1,511 @@ +/* $OpenBSD: getopt_long.c,v 1.24 2010/07/22 19:31:53 blambert Exp $ */ +/* $NetBSD: getopt_long.c,v 1.15 2002/01/31 22:43:40 tv Exp $ */ + +/* + * Copyright (c) 2002 Todd C. Miller + * + * Permission to use, copy, modify, and distribute this software for any + * purpose with or without fee is hereby granted, provided that the above + * copyright notice and this permission notice appear in all copies. + * + * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES + * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF + * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR + * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES + * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN + * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF + * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. + * + * Sponsored in part by the Defense Advanced Research Projects + * Agency (DARPA) and Air Force Research Laboratory, Air Force + * Materiel Command, USAF, under agreement number F39502-99-1-0512. + */ +/*- + * Copyright (c) 2000 The NetBSD Foundation, Inc. + * All rights reserved. + * + * This code is derived from software contributed to The NetBSD Foundation + * by Dieter Baron and Thomas Klausner. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED + * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR + * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS + * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#include +#include +#include +#include +#include + +int opterr = 1; /* if error message should be printed */ +int optind = 1; /* index into parent argv vector */ +int optopt = '?'; /* character checked for validity */ +int optreset; /* reset getopt */ +char *optarg; /* argument associated with option */ + +#define PRINT_ERROR ((opterr) && (*options != ':')) + +#define FLAG_PERMUTE 0x01 /* permute non-options to the end of argv */ +#define FLAG_ALLARGS 0x02 /* treat non-options as args to option "-1" */ +#define FLAG_LONGONLY 0x04 /* operate as getopt_long_only */ + +/* return values */ +#define BADCH (int)'?' +#define BADARG ((*options == ':') ? (int)':' : (int)'?') +#define INORDER (int)1 + +#define EMSG "" + +static int getopt_internal(int, char * const *, const char *, + const struct option *, int *, int); +static int parse_long_options(char * const *, const char *, + const struct option *, int *, int); +static int gcd(int, int); +static void permute_args(int, int, int, char * const *); + +static char *place = EMSG; /* option letter processing */ + +/* XXX: set optreset to 1 rather than these two */ +static int nonopt_start = -1; /* first non option argument (for permute) */ +static int nonopt_end = -1; /* first option after non options (for permute) */ + +/* Error messages */ +static const char recargchar[] = "option requires an argument -- %c"; +static const char recargstring[] = "option requires an argument -- %s"; +static const char ambig[] = "ambiguous option -- %.*s"; +static const char noarg[] = "option doesn't take an argument -- %.*s"; +static const char illoptchar[] = "unknown option -- %c"; +static const char illoptstring[] = "unknown option -- %s"; + +/* + * Compute the greatest common divisor of a and b. + */ +static int +gcd(int a, int b) +{ + int c; + + c = a % b; + while (c != 0) { + a = b; + b = c; + c = a % b; + } + + return (b); +} + +/* + * Exchange the block from nonopt_start to nonopt_end with the block + * from nonopt_end to opt_end (keeping the same order of arguments + * in each block). + */ +static void +permute_args(int panonopt_start, int panonopt_end, int opt_end, + char * const *nargv) +{ + int cstart, cyclelen, i, j, ncycle, nnonopts, nopts, pos; + char *swap; + + /* + * compute lengths of blocks and number and size of cycles + */ + nnonopts = panonopt_end - panonopt_start; + nopts = opt_end - panonopt_end; + ncycle = gcd(nnonopts, nopts); + cyclelen = (opt_end - panonopt_start) / ncycle; + + for (i = 0; i < ncycle; i++) { + cstart = panonopt_end+i; + pos = cstart; + for (j = 0; j < cyclelen; j++) { + if (pos >= panonopt_end) + pos -= nnonopts; + else + pos += nopts; + swap = nargv[pos]; + /* LINTED const cast */ + ((char **) nargv)[pos] = nargv[cstart]; + /* LINTED const cast */ + ((char **)nargv)[cstart] = swap; + } + } +} + +/* + * parse_long_options -- + * Parse long options in argc/argv argument vector. + * Returns -1 if short_too is set and the option does not match long_options. + */ +static int +parse_long_options(char * const *nargv, const char *options, + const struct option *long_options, int *idx, int short_too) +{ + char *current_argv, *has_equal; + size_t current_argv_len; + int i, match; + + current_argv = place; + match = -1; + + optind++; + + if ((has_equal = strchr(current_argv, '=')) != NULL) { + /* argument found (--option=arg) */ + current_argv_len = has_equal - current_argv; + has_equal++; + } else + current_argv_len = strlen(current_argv); + + for (i = 0; long_options[i].name; i++) { + /* find matching long option */ + if (strncmp(current_argv, long_options[i].name, + current_argv_len)) + continue; + + if (strlen(long_options[i].name) == current_argv_len) { + /* exact match */ + match = i; + break; + } + /* + * If this is a known short option, don't allow + * a partial match of a single character. + */ + if (short_too && current_argv_len == 1) + continue; + + if (match == -1) /* partial match */ + match = i; + else { + /* ambiguous abbreviation */ + if (PRINT_ERROR) + fprintf(stderr, ambig, (int)current_argv_len, + current_argv); + optopt = 0; + return (BADCH); + } + } + if (match != -1) { /* option found */ + if (long_options[match].has_arg == no_argument + && has_equal) { + if (PRINT_ERROR) + fprintf(stderr, noarg, (int)current_argv_len, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + return (BADARG); + } + if (long_options[match].has_arg == required_argument || + long_options[match].has_arg == optional_argument) { + if (has_equal) + optarg = has_equal; + else if (long_options[match].has_arg == + required_argument) { + /* + * optional argument doesn't use next nargv + */ + optarg = nargv[optind++]; + } + } + if ((long_options[match].has_arg == required_argument) + && (optarg == NULL)) { + /* + * Missing argument; leading ':' indicates no error + * should be generated. + */ + if (PRINT_ERROR) + fprintf(stderr, recargstring, + current_argv); + /* + * XXX: GNU sets optopt to val regardless of flag + */ + if (long_options[match].flag == NULL) + optopt = long_options[match].val; + else + optopt = 0; + --optind; + return (BADARG); + } + } else { /* unknown option */ + if (short_too) { + --optind; + return (-1); + } + if (PRINT_ERROR) + fprintf(stderr, illoptstring, current_argv); + optopt = 0; + return (BADCH); + } + if (idx) + *idx = match; + if (long_options[match].flag) { + *long_options[match].flag = long_options[match].val; + return (0); + } else + return (long_options[match].val); +} + +/* + * getopt_internal -- + * Parse argc/argv argument vector. Called by user level routines. + */ +static int +getopt_internal(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx, int flags) +{ + char *oli; /* option letter list index */ + int optchar, short_too; + static int posixly_correct = -1; + + if (options == NULL) + return (-1); + + /* + * Disable GNU extensions if POSIXLY_CORRECT is set or options + * string begins with a '+'. + */ + if (posixly_correct == -1) + posixly_correct = (getenv("POSIXLY_CORRECT") != NULL); + if (posixly_correct || *options == '+') + flags &= ~FLAG_PERMUTE; + else if (*options == '-') + flags |= FLAG_ALLARGS; + if (*options == '+' || *options == '-') + options++; + + /* + * XXX Some GNU programs (like cvs) set optind to 0 instead of + * XXX using optreset. Work around this braindamage. + */ + if (optind == 0) + optind = optreset = 1; + + optarg = NULL; + if (optreset) + nonopt_start = nonopt_end = -1; +start: + if (optreset || !*place) { /* update scanning pointer */ + optreset = 0; + if (optind >= nargc) { /* end of argument vector */ + place = EMSG; + if (nonopt_end != -1) { + /* do permutation, if we have to */ + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + else if (nonopt_start != -1) { + /* + * If we skipped non-options, set optind + * to the first of them. + */ + optind = nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + if (*(place = nargv[optind]) != '-' || + (place[1] == '\0' && strchr(options, '-') == NULL)) { + place = EMSG; /* found non-option */ + if (flags & FLAG_ALLARGS) { + /* + * GNU extension: + * return non-option as argument to option 1 + */ + optarg = nargv[optind++]; + return (INORDER); + } + if (!(flags & FLAG_PERMUTE)) { + /* + * If no permutation wanted, stop parsing + * at first non-option. + */ + return (-1); + } + /* do permutation */ + if (nonopt_start == -1) + nonopt_start = optind; + else if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + nonopt_start = optind - + (nonopt_end - nonopt_start); + nonopt_end = -1; + } + optind++; + /* process next argument */ + goto start; + } + if (nonopt_start != -1 && nonopt_end == -1) + nonopt_end = optind; + + /* + * If we have "-" do nothing, if "--" we are done. + */ + if (place[1] != '\0' && *++place == '-' && place[1] == '\0') { + optind++; + place = EMSG; + /* + * We found an option (--), so if we skipped + * non-options, we have to permute. + */ + if (nonopt_end != -1) { + permute_args(nonopt_start, nonopt_end, + optind, nargv); + optind -= nonopt_end - nonopt_start; + } + nonopt_start = nonopt_end = -1; + return (-1); + } + } + + /* + * Check long options if: + * 1) we were passed some + * 2) the arg is not just "-" + * 3) either the arg starts with -- we are getopt_long_only() + */ + if (long_options != NULL && place != nargv[optind] && + (*place == '-' || (flags & FLAG_LONGONLY))) { + short_too = 0; + if (*place == '-') + place++; /* --foo long option */ + else if (*place != ':' && strchr(options, *place) != NULL) + short_too = 1; /* could be short option too */ + + optchar = parse_long_options(nargv, options, long_options, + idx, short_too); + if (optchar != -1) { + place = EMSG; + return (optchar); + } + } + + if ((optchar = (int)*place++) == (int)':' || + (optchar == (int)'-' && *place != '\0') || + (oli = strchr(options, optchar)) == NULL) { + /* + * If the user specified "-" and '-' isn't listed in + * options, return -1 (non-option) as per POSIX. + * Otherwise, it is an unknown option character (or ':'). + */ + if (optchar == (int)'-' && *place == '\0') + return (-1); + if (!*place) + ++optind; + if (PRINT_ERROR) + fprintf(stderr, illoptchar, optchar); + optopt = optchar; + return (BADCH); + } + if (long_options != NULL && optchar == 'W' && oli[1] == ';') { + /* -W long-option */ + if (*place) /* no space */ + /* NOTHING */; + else if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + fprintf(stderr, recargchar, optchar); + optopt = optchar; + return (BADARG); + } else /* white space */ + place = nargv[optind]; + optchar = parse_long_options(nargv, options, long_options, + idx, 0); + place = EMSG; + return (optchar); + } + if (*++oli != ':') { /* doesn't take argument */ + if (!*place) + ++optind; + } else { /* takes (optional) argument */ + optarg = NULL; + if (*place) /* no white space */ + optarg = place; + else if (oli[1] != ':') { /* arg not optional */ + if (++optind >= nargc) { /* no arg */ + place = EMSG; + if (PRINT_ERROR) + fprintf(stderr, recargchar, optchar); + optopt = optchar; + return (BADARG); + } else + optarg = nargv[optind]; + } + place = EMSG; + ++optind; + } + /* dump back option letter */ + return (optchar); +} + +/* + * getopt -- + * Parse argc/argv argument vector. + * + * [eventually this will replace the BSD getopt] + */ +int +getopt(int nargc, char * const *nargv, const char *options) +{ + + /* + * We don't pass FLAG_PERMUTE to getopt_internal() since + * the BSD getopt(3) (unlike GNU) has never done this. + * + * Furthermore, since many privileged programs call getopt() + * before dropping privileges it makes sense to keep things + * as simple (and bug-free) as possible. + */ + return (getopt_internal(nargc, nargv, options, NULL, NULL, 0)); +} + +/* + * getopt_long -- + * Parse argc/argv argument vector. + */ +int +getopt_long(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE)); +} + +/* + * getopt_long_only -- + * Parse argc/argv argument vector. + */ +int +getopt_long_only(int nargc, char * const *nargv, const char *options, + const struct option *long_options, int *idx) +{ + + return (getopt_internal(nargc, nargv, options, long_options, idx, + FLAG_PERMUTE|FLAG_LONGONLY)); +} diff --git a/getopt/meson.build b/getopt/meson.build new file mode 100644 index 00000000..3ab3e904 --- /dev/null +++ b/getopt/meson.build @@ -0,0 +1,9 @@ +libgetopt = static_library( + 'getopt', + 'getopt_long.c', +) + +idep_getopt = declare_dependency( + link_with : libgetopt, + include_directories : include_directories('.', is_system : true), +) diff --git a/meson.build b/meson.build index a576a425..a3af7d8f 100644 --- a/meson.build +++ b/meson.build @@ -21,6 +21,7 @@ backends = '' # DRM use_drm = false +drm_deps=[] if get_option('drm') != 'false' require_drm = get_option('drm') == 'true' drm_deps = [ @@ -79,17 +80,35 @@ if get_option('wayland') != 'false' endif endif +# WIN32 +use_win32 = false +if get_option('win32') != 'false' + require_win32 = get_option('win32') == 'true' + use_win32 = dependency('libva-win32', required: require_win32).found() + if use_win32 + libva_utils_flags = [ '-DHAVE_VA_WIN32=1', '-DNOMINMAX'] + endif +endif + add_project_arguments(libva_utils_flags, language: ['c', 'cpp']) -subdir('common') -subdir('decode') -subdir('encode') -subdir('putsurface') +if use_win32 + subdir('getopt') + win32_deps = [ dependency('libva-win32', required: require_win32), idep_getopt ] +endif + +subdir('common') # Uses win32_deps subdir('vainfo') -subdir('videoprocess') -subdir('vendor/intel') -subdir('vendor/intel/sfcsample') + +if not use_win32 + subdir('decode') + subdir('encode') + subdir('putsurface') + subdir('videoprocess') + subdir('vendor/intel') + subdir('vendor/intel/sfcsample') +endif if get_option('tests') subdir('test') diff --git a/meson_options.txt b/meson_options.txt index 52f5c4a2..4263b5d9 100644 --- a/meson_options.txt +++ b/meson_options.txt @@ -10,6 +10,10 @@ option('wayland', type : 'combo', value : 'auto', choices: [ 'auto', 'true', 'false' ]) +option('win32', + type : 'combo', + value : 'auto', + choices: [ 'auto', 'true', 'false' ]) option('tests', type : 'boolean', value : false) diff --git a/test/compat_win32.h b/test/compat_win32.h new file mode 100644 index 00000000..4afd20a5 --- /dev/null +++ b/test/compat_win32.h @@ -0,0 +1,47 @@ +/* + * Copyright © Microsoft Corporation + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS + * IN THE SOFTWARE. + */ + +#ifndef _COMPAT_WIN32_H_ +#define _COMPAT_WIN32_H_ + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +inline int setenv(const char *varname, const char *value_string, int overwrite) +{ + return SetEnvironmentVariableA(varname, value_string); +} + +inline int unsetenv(const char *varname) +{ + return SetEnvironmentVariableA(varname, NULL); +} + +#ifdef __cplusplus +} +#endif + +#endif /* _COMPAT_WIN32_H_ */ diff --git a/test/meson.build b/test/meson.build index e90f17ab..ad2a2aae 100644 --- a/test/meson.build +++ b/test/meson.build @@ -5,14 +5,19 @@ gtest_src = [ gtest_inc = include_directories('gtest', 'gtest/include') test_flags = [ - '-DGTEST_HAS_PTHREAD=1', '-DGTEST_USE_OWN_TR1_TUPLE=0', '-DGTEST_LANG_CXX11=1', '-DGTEST_HAS_TR1_TUPLE=1', - '-DPTHREADS', '-std=c++11', ] +if not use_win32 + test_flags += [ + '-DGTEST_HAS_PTHREAD=1', + '-DPTHREADS', + ] +endif + gtest = static_library('gtest', gtest_src, cpp_args: test_flags, include_directories: gtest_inc) @@ -35,9 +40,17 @@ test_src = [ 'test_va_api_query_vendor.cpp', ] +tests_deps = [gtest_dep, dependency('threads')] + +if use_win32 + tests_deps += [ win32_deps ] +else + tests_deps += [ drm_deps ] +endif + tests = executable('test_va_api', test_src, cpp_args: test_flags, - dependencies: [ gtest_dep, drm_deps, dependency('threads'), ], + dependencies: tests_deps, install: true) test('test_va', tests) diff --git a/test/test_utils.h b/test/test_utils.h index c44f1248..1e9ca24b 100644 --- a/test/test_utils.h +++ b/test/test_utils.h @@ -39,18 +39,18 @@ struct Resolution { inline bool operator <=(const Resolution& other) const { - return (width <= other.width) and (height <= other.height); + return (width <= other.width) && (height <= other.height); } inline bool operator >=(const Resolution& other) const { - return (width >= other.width) and (height >= other.height); + return (width >= other.width) && (height >= other.height); } inline bool isWithin( const Resolution& minRes, const Resolution& maxRes) const { - return (*this >= minRes) and (*this <= maxRes); + return (*this >= minRes) && (*this <= maxRes); } friend std::ostream& operator <<(std::ostream& os, const Resolution& res) diff --git a/test/test_va_api_config_attribs.cpp b/test/test_va_api_config_attribs.cpp index 1e1ff794..d7bf02a2 100644 --- a/test/test_va_api_config_attribs.cpp +++ b/test/test_va_api_config_attribs.cpp @@ -95,7 +95,7 @@ TEST_P(VAAPIConfigAttribs, GetConfigAttribs) // should be consistent with supported attribute values returned by // vaGetConfigAttributes. - if (not isSupported(profile, entrypoint)) { + if (!isSupported(profile, entrypoint)) { skipTest(profile, entrypoint); return; } diff --git a/test/test_va_api_createbuffer.cpp b/test/test_va_api_createbuffer.cpp index 44e62d23..2dc0f6a7 100644 --- a/test/test_va_api_createbuffer.cpp +++ b/test/test_va_api_createbuffer.cpp @@ -206,7 +206,7 @@ TEST_P(VAAPICreateBuffer, CreateBufferWithOutData) // the minimum requirements. There's no need to create surfaces or attach // them to a VAConfigID. - if (not isSupported(profile, entrypoint)) { + if (!isSupported(profile, entrypoint)) { skipTest(profile, entrypoint); return; } diff --git a/test/test_va_api_createcontext.cpp b/test/test_va_api_createcontext.cpp index ddca1043..573ac423 100644 --- a/test/test_va_api_createcontext.cpp +++ b/test/test_va_api_createcontext.cpp @@ -78,7 +78,7 @@ TEST_P(VAAPICreateContext, CreateContext) // vaCreateContext requires a valid VAConfigID, vaCreateConfig requires a // supported profile and entrypoint - if (not isSupported(profile, entrypoint)) { + if (!isSupported(profile, entrypoint)) { skipTest(profile, entrypoint); return; } @@ -94,7 +94,7 @@ TEST_P(VAAPICreateContext, CreateContext) << "; current=" << resolution; SCOPED_TRACE(oss.str()); - if (not resolution.isWithin(minRes, maxRes)) { + if (!resolution.isWithin(minRes, maxRes)) { doCreateContext(resolution, VA_STATUS_ERROR_RESOLUTION_NOT_SUPPORTED); doDestroyContext(VA_STATUS_ERROR_INVALID_CONTEXT); } else { diff --git a/test/test_va_api_createsurfaces.cpp b/test/test_va_api_createsurfaces.cpp index 2b3c262b..2376b494 100644 --- a/test/test_va_api_createsurfaces.cpp +++ b/test/test_va_api_createsurfaces.cpp @@ -62,7 +62,7 @@ class VAAPISurfaceFixture for (const auto mask : masks) { // for all bitmasks if ((attrib.value & mask) == mask) { // supported value const ConfigAttributes attribs( - 1, {type : attrib.type, value : mask }); + 1, {/*type :*/ attrib.type, /*value :*/ mask }); SCOPED_TRACE(attribs.front()); createConfig(profile, entrypoint, attribs); test(attribs); @@ -104,7 +104,7 @@ class VAAPISurfaceFixture bitfield |= mask; if ((attrib.type == VASurfaceAttribMemoryType) - and (drmMemMask & mask) == mask) { + && (drmMemMask & mask) == mask) { // skip drm memory types for now as it requires much // more setup continue; @@ -147,7 +147,7 @@ class VAAPIQuerySurfaces TEST_P(VAAPIQuerySurfaces, QuerySurfacesWithConfigAttribs) { - if (not isSupported(profile, entrypoint)) { + if (!isSupported(profile, entrypoint)) { skipTest(profile, entrypoint); return; } @@ -162,7 +162,7 @@ TEST_P(VAAPIQuerySurfaces, QuerySurfacesWithConfigAttribs) TEST_P(VAAPIQuerySurfaces, QuerySurfacesNoConfigAttribs) { - if (not isSupported(profile, entrypoint)) { + if (!isSupported(profile, entrypoint)) { skipTest(profile, entrypoint); return; } @@ -200,7 +200,7 @@ class VAAPICreateSurfaces TEST_P(VAAPICreateSurfaces, CreateSurfacesWithConfigAttribs) { - if (not isSupported(profile, entrypoint)) { + if (!isSupported(profile, entrypoint)) { skipTest(profile, entrypoint); return; } @@ -234,7 +234,7 @@ TEST_P(VAAPICreateSurfaces, CreateSurfacesWithConfigAttribs) TEST_P(VAAPICreateSurfaces, CreateSurfacesNoConfigAttrib) { - if (not isSupported(profile, entrypoint)) { + if (!isSupported(profile, entrypoint)) { skipTest(profile, entrypoint); return; } @@ -252,7 +252,7 @@ TEST_P(VAAPICreateSurfaces, CreateSurfacesNoConfigAttrib) TEST_P(VAAPICreateSurfaces, CreateSurfacesNoAttrib) { - if (not isSupported(profile, entrypoint)) { + if (!isSupported(profile, entrypoint)) { skipTest(profile, entrypoint); return; } diff --git a/test/test_va_api_display_attribs.cpp b/test/test_va_api_display_attribs.cpp index 6fba72e2..bbcdbf35 100644 --- a/test/test_va_api_display_attribs.cpp +++ b/test/test_va_api_display_attribs.cpp @@ -99,7 +99,7 @@ TEST_F(VAAPIDisplayAttribs, QueryDisplayAttribs) vaQueryDisplayAttributes(m_vaDisplay, NULL, &numAttribs)); EXPECT_TRUE( - status == VaapiStatus(VA_STATUS_SUCCESS) or + status == VaapiStatus(VA_STATUS_SUCCESS) || status == VaapiStatus(VA_STATUS_ERROR_UNIMPLEMENTED)); if (status == VaapiStatus(VA_STATUS_SUCCESS)) { @@ -135,7 +135,7 @@ TEST_F(VAAPIDisplayAttribs, GetDisplayAttribs) m_attribs.resize(numAttribs); for (const auto& type : types) { - VADisplayAttribute attrib{type: type}; + VADisplayAttribute attrib{/*type:*/ type}; ASSERT_STATUS(vaGetDisplayAttributes(m_vaDisplay, &attrib, 1)); if (findDisplayAttribInQueryList(attrib.type)) { diff --git a/test/test_va_api_fixture.cpp b/test/test_va_api_fixture.cpp index 66f50c71..0896c01a 100644 --- a/test/test_va_api_fixture.cpp +++ b/test/test_va_api_fixture.cpp @@ -29,8 +29,14 @@ #include // for O_RDWR #include + +#if defined(_WIN32) +#include +#include +#else #include // for close() #include +#endif namespace VAAPI { @@ -42,14 +48,16 @@ VAStatus VAAPIFixtureSharedDisplay::s_initStatus = VA_STATUS_SUCCESS; VAAPIFixture::VAAPIFixture() : ::testing::Test::Test() , m_vaDisplay(NULL) - , m_restoreDriverName(getenv("LIBVA_DRIVER_NAME")) , m_drmHandle(-1) , m_configID(VA_INVALID_ID) , m_contextID(VA_INVALID_ID) , m_bufferID(VA_INVALID_ID) , m_skip("") { - return; + // If we do not copy the value and use the same pointer returned by getenv to restore the value + // in ~VAAPIFixture with setenv, we see garbage memory being set on Windows platforms. + char* libva_driver = getenv("LIBVA_DRIVER_NAME"); + if (libva_driver) m_restoreDriverName = libva_driver; } VAAPIFixture::~VAAPIFixture() @@ -62,19 +70,25 @@ VAAPIFixture::~VAAPIFixture() // Ensure LIBVA_DRIVER_NAME environment is restored to its original // setting so successive tests use the expected driver. unsetenv("LIBVA_DRIVER_NAME"); - if (m_restoreDriverName) - setenv("LIBVA_DRIVER_NAME", m_restoreDriverName, 1); + if (!m_restoreDriverName.empty()) + setenv("LIBVA_DRIVER_NAME", m_restoreDriverName.c_str(), 1); - if (not m_skip.empty()) { + if (!m_skip.empty()) { EXPECT_FALSE(HasFailure()) << "skip message is set, but something failed"; - if (not HasFailure()) { + if (!HasFailure()) { RecordProperty("skipped", true); std::cout << "[ SKIPPED ] " << m_skip << std::endl; } } } +#if defined(_WIN32) +static VADisplay getWin32Display(LUID* adapter) +{ + return vaGetDisplayWin32(adapter); +} +#else static VADisplay getDrmDisplay(int &fd) { typedef std::vector DevicePaths; @@ -97,11 +111,14 @@ static VADisplay getDrmDisplay(int &fd) return NULL; } - +#endif VADisplay VAAPIFixture::getDisplay() { +#if defined(_WIN32) + m_vaDisplay = getWin32Display(NULL); +#else m_vaDisplay = getDrmDisplay(m_drmHandle); - +#endif return m_vaDisplay; } @@ -136,7 +153,7 @@ void VAAPIFixture::queryConfigProfiles(Profiles& profiles) const EXPECT_STATUS( vaQueryConfigProfiles(m_vaDisplay, profiles.data(), &numProfiles)); - if (not HasFailure()) { + if (!HasFailure()) { ASSERT_LE(numProfiles, maxProfiles); ASSERT_GT(numProfiles, 0); profiles.resize(numProfiles); @@ -158,7 +175,7 @@ void VAAPIFixture::queryConfigEntrypoints(const VAProfile& profile, vaQueryConfigEntrypoints(m_vaDisplay, profile, entrypoints.data(), &numEntrypoints)); - if ((VA_STATUS_SUCCESS == expectation) and not HasFailure()) { + if ((VA_STATUS_SUCCESS == expectation) && !HasFailure()) { ASSERT_LE(numEntrypoints, maxEntrypoints); ASSERT_GT(numEntrypoints, 0); entrypoints.resize(numEntrypoints); @@ -203,7 +220,7 @@ void VAAPIFixture::getConfigAttributes(const VAProfile& profile, if (defaults) { // fill config attributes with default config attributes const auto op = [](const VAConfigAttribType & t) { - return VAConfigAttrib{type: t, value: VA_ATTRIB_NOT_SUPPORTED}; + return VAConfigAttrib{/*type:*/ t, /*value:*/ VA_ATTRIB_NOT_SUPPORTED}; }; std::transform(g_vaConfigAttribTypes.begin(), g_vaConfigAttribTypes.end(), std::back_inserter(attribs), op); @@ -499,8 +516,11 @@ VAAPIFixtureSharedDisplay::VAAPIFixtureSharedDisplay() : VAAPIFixture() { } void VAAPIFixtureSharedDisplay::SetUpTestSuite() { if (s_drmHandle < 0) { +#if defined(_WIN32) + s_vaDisplay = getWin32Display(NULL); +#else s_vaDisplay = getDrmDisplay(s_drmHandle); - +#endif int majorVersion, minorVersion; s_initStatus = vaInitialize(s_vaDisplay, &majorVersion, &minorVersion); } @@ -508,14 +528,15 @@ void VAAPIFixtureSharedDisplay::SetUpTestSuite() void VAAPIFixtureSharedDisplay::TearDownTestSuite() { - if (s_drmHandle >= 0) { + if (s_vaDisplay) { if (s_initStatus == VA_STATUS_SUCCESS) { vaTerminate(s_vaDisplay); s_vaDisplay = nullptr; } else { s_initStatus = VA_STATUS_SUCCESS; } - + } + if (s_drmHandle >= 0) { close(s_drmHandle); s_drmHandle = -1; } diff --git a/test/test_va_api_fixture.h b/test/test_va_api_fixture.h index 0a884204..65569fce 100644 --- a/test/test_va_api_fixture.h +++ b/test/test_va_api_fixture.h @@ -102,7 +102,7 @@ class VAAPIFixture : public ::testing::Test VADisplay m_vaDisplay; private: - char *m_restoreDriverName; + std::string m_restoreDriverName; int m_drmHandle; VAConfigID m_configID; diff --git a/test/test_va_api_get_create_config.cpp b/test/test_va_api_get_create_config.cpp index dd7bd267..18e69e21 100644 --- a/test/test_va_api_get_create_config.cpp +++ b/test/test_va_api_get_create_config.cpp @@ -92,7 +92,7 @@ TEST_P(VAAPIGetCreateConfig, CreateConfigWithAttributes) bitfield |= mask; createConfig(profile, entrypoint, ConfigAttributes( - 1, {type : attrib.type, value : mask })); + 1, {/*type :*/ attrib.type, /*value :*/ mask })); destroyConfig(); } else { // unsupported value @@ -102,7 +102,7 @@ TEST_P(VAAPIGetCreateConfig, CreateConfigWithAttributes) VA_STATUS_ERROR_INVALID_VALUE); createConfig(profile, entrypoint, ConfigAttributes( - 1, {type : attrib.type, value : mask}), + 1, {/*type :*/ attrib.type, /*value :*/ mask}), expectation); destroyConfig(VA_STATUS_ERROR_INVALID_CONFIG); } @@ -139,18 +139,18 @@ TEST_P(VAAPIGetCreateConfig, CreateConfigNoAttributes) TEST_P(VAAPIGetCreateConfig, CreateConfigPackedHeaders) { - if (not isSupported(profile, entrypoint)) { + if (!isSupported(profile, entrypoint)) { skipTest(profile, entrypoint); return; } - ConfigAttributes packedHeaders{{.type = VAConfigAttribEncPackedHeaders}}; + ConfigAttributes packedHeaders{{/*.type = */VAConfigAttribEncPackedHeaders}}; getConfigAttributes(profile, entrypoint, packedHeaders); for (uint32_t v(0x00); v < 0xff; ++v) { ConfigAttributes attribs = {{ - .type = VAConfigAttribEncPackedHeaders, - .value = v + /*.type = */VAConfigAttribEncPackedHeaders, + /*.value = */v } }; if ((VA_ATTRIB_NOT_SUPPORTED == packedHeaders.front().value) diff --git a/test/test_va_api_init_terminate.cpp b/test/test_va_api_init_terminate.cpp index a9c86812..98f59b41 100644 --- a/test/test_va_api_init_terminate.cpp +++ b/test/test_va_api_init_terminate.cpp @@ -23,6 +23,12 @@ */ #include "test_va_api_fixture.h" +#include +#include + +#if defined(_WIN32) +#include +#endif namespace VAAPI { diff --git a/vainfo/vainfo.c b/vainfo/vainfo.c index a8269f1e..a5fced89 100644 --- a/vainfo/vainfo.c +++ b/vainfo/vainfo.c @@ -26,7 +26,9 @@ #include #include #include +#if !defined(_WIN32) #include +#endif #include #include