From: Elizabeth Figura <zfigura@codeweavers.com> --- configure.ac | 15 +++++ dlls/wined3d/Makefile.in | 4 ++ dlls/wined3d/decoder.c | 24 +++++++ dlls/wined3d/unixlib.h | 44 +++++++++++++ dlls/wined3d/va.c | 139 +++++++++++++++++++++++++++++++++++++++ 5 files changed, 226 insertions(+) create mode 100644 dlls/wined3d/unixlib.h create mode 100644 dlls/wined3d/va.c diff --git a/configure.ac b/configure.ac index ee0b1c483d4..ad0eb7ead6a 100644 --- a/configure.ac +++ b/configure.ac @@ -59,6 +59,7 @@ AC_ARG_WITH(sdl, AS_HELP_STRING([--without-sdl],[do not use SDL])) AC_ARG_WITH(udev, AS_HELP_STRING([--without-udev],[do not use udev (plug and play support)])) AC_ARG_WITH(usb, AS_HELP_STRING([--without-usb],[do not use the libusb library])) AC_ARG_WITH(v4l2, AS_HELP_STRING([--without-v4l2],[do not use v4l2 (video capture)])) +AC_ARG_WITH(va, AS_HELP_STRING([--without-va],[do not use VA-API (hardware decode)])) AC_ARG_WITH(vulkan, AS_HELP_STRING([--without-vulkan],[do not use Vulkan])) AC_ARG_WITH(wayland, AS_HELP_STRING([--without-wayland],[do not build the Wayland driver])) AC_ARG_WITH(xcomposite,AS_HELP_STRING([--without-xcomposite],[do not use the Xcomposite extension]), @@ -1618,6 +1619,20 @@ fi WINE_NOTICE_WITH(v4l2,[test "x$ac_cv_lib_soname_v4l2" = "x"], [libv4l2 ${notice_platform}development files not found.]) +dnl **** Check for libva **** +if test "x$with_va" != "xno" +then + WINE_PACKAGE_FLAGS(VA,[libva libva-drm],[-lva-drm -lva],,, + [AC_CHECK_HEADER([va/va_drm.h], + [AC_CHECK_FUNC(vaGetDisplayDRM, + [AC_DEFINE(HAVE_VA, 1, [Define to 1 if you have the 'va' library (-lva).])], + [VA_LIBS=""])], + [VA_LIBS=""])]) +fi +WINE_NOTICE_WITH(va,[test "$ac_cv_lib_va_drm_vaGetDisplayDRM" != "yes"], + [libva-drm ${notice_platform}development files not found, VA video acceleration won't be supported.], + [enable_wineva]) + dnl **** Check for libgphoto2 **** if test "x$with_gphoto" != "xno" then diff --git a/dlls/wined3d/Makefile.in b/dlls/wined3d/Makefile.in index bbf8f260b02..ecf9c264e75 100644 --- a/dlls/wined3d/Makefile.in +++ b/dlls/wined3d/Makefile.in @@ -1,7 +1,10 @@ MODULE = wined3d.dll +UNIXLIB = wined3d.so IMPORTLIB = wined3d IMPORTS = $(VKD3D_PE_LIBS) dxguid opengl32 user32 gdi32 advapi32 EXTRAINCL = $(VKD3D_PE_CFLAGS) +UNIX_CFLAGS = $(VA_CFLAGS) +UNIX_LIBS = -lwin32u $(VA_LIBS) VER_FILEDESCRIPTION_STR = "Wine D3D" @@ -36,6 +39,7 @@ SOURCES = \ texture_gl.c \ texture_vk.c \ utils.c \ + va.c \ vertexdeclaration.c \ view.c \ wined3d_main.c diff --git a/dlls/wined3d/decoder.c b/dlls/wined3d/decoder.c index 6a7ca54554f..2cb1c5fdbfb 100644 --- a/dlls/wined3d/decoder.c +++ b/dlls/wined3d/decoder.c @@ -18,6 +18,7 @@ #include "wined3d_private.h" #include "wined3d_vk.h" +#include "unixlib.h" WINE_DEFAULT_DEBUG_CHANNEL(d3d); @@ -1369,15 +1370,38 @@ static struct wined3d_decoder_va_vk *wined3d_decoder_va_vk(struct wined3d_decode static void wined3d_decoder_va_vk_get_profiles(struct wined3d_adapter *adapter, unsigned int *count, GUID *profiles) { + struct va_get_profiles_vk_params params; + NTSTATUS status; + *count = 0; + + /* We are under wined3d_mutex, so this is thread safe. */ + if ((status = __wine_init_unix_call())) + { + WARN("Failed to load Unix library, status %#lx.\n", status); + return; + } + + params.physical_device = (uintptr_t)wined3d_adapter_vk(adapter)->physical_device; + params.count = (uintptr_t)count; + params.profiles = (uintptr_t)profiles; + WINE_UNIX_CALL(unix_va_get_profiles_vk, ¶ms); } static HRESULT wined3d_decoder_va_vk_create(struct wined3d_device *device, const struct wined3d_decoder_desc *desc, struct wined3d_decoder **decoder) { struct wined3d_decoder_va_vk *object; + NTSTATUS status; HRESULT hr; + /* We are under wined3d_mutex, so this is thread safe. */ + if ((status = __wine_init_unix_call())) + { + WARN("Failed to load Unix library, status %#lx.\n", status); + return E_FAIL; + } + if (!(object = calloc(1, sizeof(*object)))) return E_OUTOFMEMORY; if (FAILED(hr = wined3d_decoder_init(&object->d, device, desc, false))) diff --git a/dlls/wined3d/unixlib.h b/dlls/wined3d/unixlib.h new file mode 100644 index 00000000000..45630418d08 --- /dev/null +++ b/dlls/wined3d/unixlib.h @@ -0,0 +1,44 @@ +/* + * Copyright 2024 Elizabeth Figura for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __WINE_WINED3D_UNIXLIB_H +#define __WINE_WINED3D_UNIXLIB_H + +/* We cannot put these definitions in wined3d_private.h, because + * wined3d_private.h uses vkd3d-shader definitions, and we cannot access + * vkd3d_shader.h from the Unix side. */ + +#define COBJMACROS +#include <stdint.h> +#include "objbase.h" +#include "wine/wined3d.h" +#include "wine/unixlib.h" + +struct va_get_profiles_vk_params +{ + UINT64 physical_device; /* VkPhysicalDevice */ + UINT64 count; /* unsigned int * */ + UINT64 profiles; /* GUID * */ +}; + +enum unix_funcs +{ + unix_va_get_profiles_vk, +}; + +#endif diff --git a/dlls/wined3d/va.c b/dlls/wined3d/va.c new file mode 100644 index 00000000000..bfb8d51522f --- /dev/null +++ b/dlls/wined3d/va.c @@ -0,0 +1,139 @@ +/* + * Copyright 2024 Elizabeth Figura for CodeWeavers + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#if 0 +#pragma makedep unix +#endif + +#include "config.h" + +#ifdef HAVE_VA + +#include "initguid.h" +#include "unixlib.h" +#include "dxva.h" +#include <errno.h> +#include <fcntl.h> +#include <inttypes.h> +#include <sys/stat.h> +#include <unistd.h> +#include <va/va.h> +#include <va/va_drm.h> +#include <va/va_drmcommon.h> +#include "ntgdi.h" +#include "wine/vulkan_driver.h" +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(d3d); + +static NTSTATUS open_va_display(UINT64 handle, VADisplay *ret_display, int *ret_fd) +{ + VkPhysicalDeviceDrmPropertiesEXT drm_properties = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRM_PROPERTIES_EXT}; + VkPhysicalDeviceProperties2 properties = {.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2}; + const struct vulkan_physical_device *device = vulkan_physical_device_from_handle((VkPhysicalDevice)handle); + int major, minor, fd; + VADisplay display; + VAStatus status; + char *path; + + if (!device->extensions.has_VK_EXT_physical_device_drm) + return E_NOTIMPL; + + properties.pNext = &drm_properties; + device->instance->p_vkGetPhysicalDeviceProperties2KHR(device->host.physical_device, &properties); + + if (drm_properties.hasPrimary) + { + asprintf(&path, "/dev/dri/card%"PRIu64, drm_properties.primaryMinor); + } + else if (drm_properties.hasRender) + { + asprintf(&path, "/dev/dri/renderD%"PRIu64, drm_properties.primaryMinor); + } + else + { + ERR("Vulkan device has neither a primary nor render node.\n"); + return E_FAIL; + } + + if ((fd = open(path, O_RDWR | O_CLOEXEC)) < 0) + { + ERR("Failed to open %s: %s\n", path, strerror(errno)); + free(path); + return E_FAIL; + } + free(path); + + display = vaGetDisplayDRM(fd); + if ((status = vaInitialize(display, &major, &minor)) != VA_STATUS_SUCCESS) + { + ERR("Failed to initialize VA, error %#x.\n", status); + close(fd); + return E_FAIL; + } + + *ret_display = display; + *ret_fd = fd; + return S_OK; +} + +static NTSTATUS va_get_profiles_vk(void *args) +{ + struct va_get_profiles_vk_params *params = args; + unsigned int *count = (unsigned int *)(uintptr_t)params->count; + GUID *profiles = (GUID *)(uintptr_t)params->profiles; + VAProfile *va_profiles; + int drm_fd, max_count; + VADisplay display; + NTSTATUS status; + + if ((status = open_va_display(params->physical_device, &display, &drm_fd))) + return status; + + max_count = vaMaxNumProfiles(display); + va_profiles = malloc(max_count * sizeof(*va_profiles)); + vaQueryConfigProfiles(display, va_profiles, &max_count); + + for (int i = 0; i < max_count; ++i) + { + if (va_profiles[i] == VAProfileH264High) + { + profiles[(*count)++] = DXVA_ModeH264_VLD_NoFGT; + /* FIXME: Native GPUs also support DXVA2_ModeH264_VLD_Stereo_NoFGT + * and DXVA2_ModeH264_VLD_Stereo_Progressive_NoFGT. */ + } + } + + free(va_profiles); + vaTerminate(display); + close(drm_fd); + + return S_OK; +} + +const unixlib_entry_t __wine_unix_call_funcs[] = +{ + [unix_va_get_profiles_vk] = va_get_profiles_vk, +}; + +const unixlib_entry_t __wine_unix_call_wow64_funcs[] = +{ + [unix_va_get_profiles_vk] = va_get_profiles_vk, +}; + +#endif -- GitLab https://gitlab.winehq.org/wine/wine/-/merge_requests/11535