Depending on driver, display can be initialized but fails on query calls. Part-of: <https://gitlab.freedesktop.org/gstreamer/gstreamer/-/merge_requests/4149>
		
			
				
	
	
		
			327 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
			
		
		
	
	
			327 lines
		
	
	
		
			8.6 KiB
		
	
	
	
		
			C++
		
	
	
	
	
	
| /* GStreamer
 | |
|  * Copyright (C) 2020 Igalia, S.L.
 | |
|  *     Author: Víctor Jáquez <vjaquez@igalia.com>
 | |
|  * Copyright (C) 2023 Seungha Yang <seungha@centricular.com>
 | |
|  *
 | |
|  * This library is free software; you can redistribute it and/or
 | |
|  * modify it under the terms of the GNU Library General Public
 | |
|  * License as published by the Free Software Foundation; either
 | |
|  * version 2 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
 | |
|  * Library General Public License for more details.
 | |
|  *
 | |
|  * You should have received a copy of the GNU Library 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.
 | |
|  */
 | |
| 
 | |
| /**
 | |
|  * SECTION:gstvadisplaywin32
 | |
|  * @title: GstVaDisplayWin32
 | |
|  * @short_description: VADisplay from a Win32 Direct3D12 backend
 | |
|  * @sources:
 | |
|  * - gstvadisplay_win32.h
 | |
|  *
 | |
|  * This is a #GstVaDisplay subclass to instantiate for Win32 Direct3D12 backend.
 | |
|  *
 | |
|  * Since: 1.24
 | |
|  */
 | |
| 
 | |
| #ifdef HAVE_CONFIG_H
 | |
| #include "config.h"
 | |
| #endif
 | |
| 
 | |
| #ifndef INITGUID
 | |
| #include <initguid.h>
 | |
| #endif
 | |
| 
 | |
| #include "gstvadisplay_win32.h"
 | |
| #include <wrl.h>
 | |
| #include <dxgi.h>
 | |
| #include <va/va_win32.h>
 | |
| #include <string>
 | |
| #include <vector>
 | |
| 
 | |
| /* *INDENT-OFF* */
 | |
| using namespace Microsoft::WRL;
 | |
| 
 | |
| extern "C" {
 | |
| GST_DEBUG_CATEGORY_EXTERN (gst_va_display_debug);
 | |
| #define GST_CAT_DEFAULT gst_va_display_debug
 | |
| }
 | |
| /* *INDENT-ON* */
 | |
| 
 | |
| /**
 | |
|  * GstVaDisplayWin32:
 | |
|  *
 | |
|  * Since: 1.24
 | |
|  */
 | |
| struct _GstVaDisplayWin32
 | |
| {
 | |
|   GstVaDisplay parent;
 | |
| 
 | |
|   gchar *adapter_luid_str;
 | |
|   gint64 adapter_luid;
 | |
|   guint device_id;
 | |
|   guint vendor_id;
 | |
|   gchar *desc;
 | |
| };
 | |
| 
 | |
| /**
 | |
|  * GstVaDisplayWin32Class:
 | |
|  *
 | |
|  * Since: 1.24
 | |
|  */
 | |
| struct _GstVaDisplayWin32Class
 | |
| {
 | |
|   GstVaDisplayClass parent_class;
 | |
| };
 | |
| 
 | |
| enum
 | |
| {
 | |
|   PROP_0,
 | |
|   PROP_PATH,
 | |
|   PROP_ADAPTER_LUID,
 | |
|   PROP_DEVICE_ID,
 | |
|   PROP_VENDOR_ID,
 | |
|   PROP_DESC,
 | |
| };
 | |
| 
 | |
| static void gst_va_display_win32_finalize (GObject * object);
 | |
| static void gst_va_display_win32_get_property (GObject * object, guint prop_id,
 | |
|     GValue * value, GParamSpec * pspec);
 | |
| static void gst_va_display_win32_set_property (GObject * object, guint prop_id,
 | |
|     const GValue * value, GParamSpec * pspec);
 | |
| static gpointer gst_va_display_win32_create_va_display (GstVaDisplay * display);
 | |
| 
 | |
| #define gst_va_display_win32_parent_class parent_class
 | |
| G_DEFINE_TYPE (GstVaDisplayWin32, gst_va_display_win32, GST_TYPE_VA_DISPLAY);
 | |
| 
 | |
| static void
 | |
| gst_va_display_win32_class_init (GstVaDisplayWin32Class * klass)
 | |
| {
 | |
|   GObjectClass *object_class = G_OBJECT_CLASS (klass);
 | |
|   GstVaDisplayClass *display_class = GST_VA_DISPLAY_CLASS (klass);
 | |
|   GParamFlags construct_only_flags = (GParamFlags)
 | |
|       (G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS | G_PARAM_CONSTRUCT_ONLY);
 | |
| 
 | |
|   object_class->get_property = gst_va_display_win32_get_property;
 | |
|   object_class->set_property = gst_va_display_win32_set_property;
 | |
|   object_class->finalize = gst_va_display_win32_finalize;
 | |
| 
 | |
|   g_object_class_install_property (object_class, PROP_PATH,
 | |
|       g_param_spec_string ("path", "Path",
 | |
|           "String representation of DXGI Adapter LUID",
 | |
|           nullptr, construct_only_flags));
 | |
|   g_object_class_install_property (object_class, PROP_ADAPTER_LUID,
 | |
|       g_param_spec_int64 ("adapter-luid", "Adapter LUID",
 | |
|           "DXGI Adapter LUID",
 | |
|           G_MININT64, G_MAXINT64, 0, construct_only_flags));
 | |
|   g_object_class_install_property (object_class, PROP_DEVICE_ID,
 | |
|       g_param_spec_uint ("device-id", "Device Id",
 | |
|           "DXGI Device ID", 0, G_MAXUINT32, 0, construct_only_flags));
 | |
|   g_object_class_install_property (object_class, PROP_VENDOR_ID,
 | |
|       g_param_spec_uint ("vendor-id", "Vendor Id",
 | |
|           "DXGI Vendor ID", 0, G_MAXUINT32, 0, construct_only_flags));
 | |
|   g_object_class_override_property (object_class, PROP_DESC, "description");
 | |
| 
 | |
|   display_class->create_va_display =
 | |
|       GST_DEBUG_FUNCPTR (gst_va_display_win32_create_va_display);
 | |
| }
 | |
| 
 | |
| static void
 | |
| gst_va_display_win32_init (GstVaDisplayWin32 * self)
 | |
| {
 | |
| }
 | |
| 
 | |
| static void
 | |
| gst_va_display_win32_get_property (GObject * object, guint prop_id,
 | |
|     GValue * value, GParamSpec * pspec)
 | |
| {
 | |
|   GstVaDisplayWin32 *self = GST_VA_DISPLAY_WIN32 (object);
 | |
| 
 | |
|   switch (prop_id) {
 | |
|     case PROP_PATH:
 | |
|       g_value_set_string (value, self->adapter_luid_str);
 | |
|       break;
 | |
|     case PROP_ADAPTER_LUID:
 | |
|       g_value_set_int64 (value, self->adapter_luid);
 | |
|       break;
 | |
|     case PROP_DEVICE_ID:
 | |
|       g_value_set_uint (value, self->device_id);
 | |
|       break;
 | |
|     case PROP_VENDOR_ID:
 | |
|       g_value_set_uint (value, self->vendor_id);
 | |
|       break;
 | |
|     case PROP_DESC:
 | |
|       g_value_set_string (value, self->desc);
 | |
|       break;
 | |
|     default:
 | |
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | |
|       break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| gst_va_display_win32_set_property (GObject * object, guint prop_id,
 | |
|     const GValue * value, GParamSpec * pspec)
 | |
| {
 | |
|   GstVaDisplayWin32 *self = GST_VA_DISPLAY_WIN32 (object);
 | |
| 
 | |
|   switch (prop_id) {
 | |
|     case PROP_PATH:
 | |
|       self->adapter_luid_str = g_value_dup_string (value);
 | |
|       break;
 | |
|     case PROP_ADAPTER_LUID:
 | |
|       self->adapter_luid = g_value_get_int64 (value);
 | |
|       break;
 | |
|     case PROP_DEVICE_ID:
 | |
|       self->device_id = g_value_get_uint (value);
 | |
|       break;
 | |
|     case PROP_VENDOR_ID:
 | |
|       self->vendor_id = g_value_get_uint (value);
 | |
|       break;
 | |
|     case PROP_DESC:
 | |
|       self->desc = g_value_dup_string (value);
 | |
|       break;
 | |
|     default:
 | |
|       G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
 | |
|       break;
 | |
|   }
 | |
| }
 | |
| 
 | |
| static void
 | |
| gst_va_display_win32_finalize (GObject * object)
 | |
| {
 | |
|   GstVaDisplayWin32 *self = GST_VA_DISPLAY_WIN32 (object);
 | |
| 
 | |
|   g_free (self->adapter_luid_str);
 | |
|   g_free (self->desc);
 | |
| 
 | |
|   G_OBJECT_CLASS (parent_class)->finalize (object);
 | |
| }
 | |
| 
 | |
| static gpointer
 | |
| gst_va_display_win32_create_va_display (GstVaDisplay * display)
 | |
| {
 | |
|   GstVaDisplayWin32 *self = GST_VA_DISPLAY_WIN32 (display);
 | |
|   LARGE_INTEGER val;
 | |
|   LUID luid;
 | |
| 
 | |
|   val.QuadPart = self->adapter_luid;
 | |
|   luid.LowPart = val.LowPart;
 | |
|   luid.HighPart = val.HighPart;
 | |
| 
 | |
|   return vaGetDisplayWin32 (&luid);
 | |
| }
 | |
| 
 | |
| /**
 | |
|  * gst_va_display_win32_new:
 | |
|  * @adapter_luid: DXGI adapter luid
 | |
|  *
 | |
|  * Creates a new #GstVaDisplay from Win32 Direct3D backend
 | |
|  *
 | |
|  * Returns: (transfer full): a newly allocated #GstVaDisplay if the
 | |
|  *     specified Win32 backend could be opened and initialized;
 | |
|  *     otherwise %NULL is returned.
 | |
|  *
 | |
|  * Since: 1.24
 | |
|  */
 | |
| GstVaDisplay *
 | |
| gst_va_display_win32_new (const gchar * adapter_luid)
 | |
| {
 | |
|   GstVaDisplayWin32 *self;
 | |
|   HRESULT hr;
 | |
|   ComPtr < IDXGIFactory1 > factory;
 | |
|   DXGI_ADAPTER_DESC desc;
 | |
|   gint64 adapter_luid_i64;
 | |
|   gchar *desc_str;
 | |
|   gint max_profiles, max_entry_points;
 | |
|   gint num_profiles;
 | |
|   VAStatus status;
 | |
|   VADisplay dpy;
 | |
|   std::vector < VAEntrypoint > entry_points;
 | |
|   std::vector < VAProfile > profiles;
 | |
| 
 | |
|   g_return_val_if_fail (adapter_luid != nullptr, nullptr);
 | |
| 
 | |
|   /* *INDENT-OFF* */
 | |
|   try {
 | |
|     adapter_luid_i64 = std::stoll (adapter_luid);
 | |
|   } catch (...) {
 | |
|     return nullptr;
 | |
|   }
 | |
|   /* *INDENT-ON* */
 | |
| 
 | |
|   hr = CreateDXGIFactory1 (IID_PPV_ARGS (&factory));
 | |
|   if (FAILED (hr))
 | |
|     return nullptr;
 | |
| 
 | |
|   for (guint i = 0;; i++) {
 | |
|     ComPtr < IDXGIAdapter > adapter;
 | |
|     LARGE_INTEGER val;
 | |
| 
 | |
|     hr = factory->EnumAdapters (i, &adapter);
 | |
|     if (FAILED (hr))
 | |
|       return nullptr;
 | |
| 
 | |
|     hr = adapter->GetDesc (&desc);
 | |
|     if (FAILED (hr))
 | |
|       continue;
 | |
| 
 | |
|     val.LowPart = desc.AdapterLuid.LowPart;
 | |
|     val.HighPart = desc.AdapterLuid.HighPart;
 | |
| 
 | |
|     if (val.QuadPart == adapter_luid_i64)
 | |
|       break;
 | |
|   }
 | |
| 
 | |
|   desc_str = g_utf16_to_utf8 ((gunichar2 *) desc.Description,
 | |
|       -1, nullptr, nullptr, nullptr);
 | |
| 
 | |
|   self = (GstVaDisplayWin32 *) g_object_new (gst_va_display_win32_get_type (),
 | |
|       "path", adapter_luid, "adapter-luid", adapter_luid_i64, "device-id",
 | |
|       desc.DeviceId, "vendor-id", desc.VendorId, nullptr);
 | |
|   self->desc = desc_str;
 | |
|   if (!gst_va_display_initialize (GST_VA_DISPLAY (self)))
 | |
|     goto error;
 | |
| 
 | |
|   /* Validate device */
 | |
|   dpy = gst_va_display_get_va_dpy (GST_VA_DISPLAY (self));
 | |
| 
 | |
|   max_profiles = vaMaxNumProfiles (dpy);
 | |
|   if (max_profiles <= 0)
 | |
|     goto error;
 | |
| 
 | |
|   max_entry_points = vaMaxNumEntrypoints (dpy);
 | |
|   if (max_entry_points <= 0)
 | |
|     goto error;
 | |
| 
 | |
|   profiles.resize (max_profiles);
 | |
| 
 | |
|   status = vaQueryConfigProfiles (dpy, &profiles[0], &num_profiles);
 | |
|   if (status != VA_STATUS_SUCCESS || num_profiles <= 0)
 | |
|     goto error;
 | |
| 
 | |
|   entry_points.resize (max_entry_points);
 | |
|   for (guint i = 0; i < num_profiles; i++) {
 | |
|     gint num_entry_poinits;
 | |
|     status = vaQueryConfigEntrypoints (dpy, profiles[i], &entry_points[0],
 | |
|         &num_entry_poinits);
 | |
|     if (status != VA_STATUS_SUCCESS)
 | |
|       goto error;
 | |
|   }
 | |
| 
 | |
|   gst_object_ref_sink (self);
 | |
| 
 | |
|   return GST_VA_DISPLAY (self);
 | |
| 
 | |
| error:
 | |
|   gst_object_unref (self);
 | |
|   return nullptr;
 | |
| }
 |