xref: /aosp_15_r20/external/libva/va/win32/va_win32.c (revision 54e60f844a168e9a219354de272cd517ee8cd4b7)
1 /*
2  * Copyright © Microsoft Corporation
3  * Copyright (c) 2023 Emil Velikov
4  *
5  * Permission is hereby granted, free of charge, to any person obtaining a
6  * copy of this software and associated documentation files (the "Software"),
7  * to deal in the Software without restriction, including without limitation
8  * the rights to use, copy, modify, merge, publish, distribute, sublicense,
9  * and/or sell copies of the Software, and to permit persons to whom the
10  * Software is furnished to do so, subject to the following conditions:
11  *
12  * The above copyright notice and this permission notice (including the next
13  * paragraph) shall be included in all copies or substantial portions of the
14  * Software.
15  *
16  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17  * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18  * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
19  * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20  * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
21  * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
22  * IN THE SOFTWARE.
23  */
24 
25 #include "sysdeps.h"
26 #include "va.h"
27 #include "va_backend.h"
28 #include "va_internal.h"
29 #include "va_trace.h"
30 #include "va_win32.h"
31 #include "compat_win32.h"
32 
33 /*
34  * Initialize default driver to the VAOn12 driver implementation
35  * which will be selected when provided with an adapter LUID which
36  * does not have a registered VA driver
37 */
38 const char VAAPI_DEFAULT_DRIVER_NAME[] = "vaon12";
39 
40 typedef struct _VADisplayContextWin32 {
41     char registry_driver_name[MAX_PATH];
42     bool registry_driver_available_flag;
43 } VADisplayContextWin32;
44 
LoadDriverNameFromRegistry(const LUID * adapter_luid,VADisplayContextWin32 * pWin32Ctx)45 static void LoadDriverNameFromRegistry(const LUID* adapter_luid, VADisplayContextWin32* pWin32Ctx)
46 {
47     HMODULE hGdi32 = LoadLibraryA("gdi32.dll");
48     if (!hGdi32)
49         return;
50 
51     D3DKMT_OPENADAPTERFROMLUID OpenArgs = { .AdapterLuid = *adapter_luid };
52     D3DDDI_QUERYREGISTRY_INFO RegistryInfo = {
53         .QueryType = D3DDDI_QUERYREGISTRY_ADAPTERKEY,
54         .QueryFlags.TranslatePath = true,
55         .ValueName = L"VAAPIDriverName",
56         .ValueType = REG_SZ,
57     };
58     D3DDDI_QUERYREGISTRY_INFO *pRegistryInfo = &RegistryInfo;
59 #ifndef _WIN64
60     BOOL isWowProcess = false;
61     if (IsWow64Process(GetCurrentProcess(), &isWowProcess) && isWowProcess)
62         wcscpy(RegistryInfo.ValueName, L"VAAPIDriverNameWow");
63 #endif
64     D3DKMT_QUERYADAPTERINFO QAI = {
65         .Type = KMTQAITYPE_QUERYREGISTRY,
66         .pPrivateDriverData = &RegistryInfo,
67         .PrivateDriverDataSize = sizeof(RegistryInfo),
68     };
69 
70     PFND3DKMT_OPENADAPTERFROMLUID pfnOpenAdapterFromLuid = (PFND3DKMT_OPENADAPTERFROMLUID)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromLuid");
71     PFND3DKMT_CLOSEADAPTER pfnCloseAdapter = (PFND3DKMT_CLOSEADAPTER)GetProcAddress(hGdi32, "D3DKMTCloseAdapter");
72     PFND3DKMT_QUERYADAPTERINFO pfnQueryAdapterInfo = (PFND3DKMT_QUERYADAPTERINFO)GetProcAddress(hGdi32, "D3DKMTQueryAdapterInfo");
73     if (!pfnOpenAdapterFromLuid || !pfnCloseAdapter || !pfnQueryAdapterInfo)
74         goto cleanup;
75 
76     if (!NT_SUCCESS(pfnOpenAdapterFromLuid(&OpenArgs)))
77         goto cleanup;
78 
79     QAI.hAdapter = OpenArgs.hAdapter;
80     if (!NT_SUCCESS(pfnQueryAdapterInfo(&QAI)) ||
81         pRegistryInfo->Status != D3DDDI_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW)
82         goto cleanup;
83 
84     size_t RegistryInfoSize = sizeof(RegistryInfo) + RegistryInfo.OutputValueSize;
85     pRegistryInfo = malloc(RegistryInfoSize);
86     if (!pRegistryInfo)
87         goto cleanup;
88 
89     memcpy(pRegistryInfo, &RegistryInfo, sizeof(RegistryInfo));
90     QAI.pPrivateDriverData = pRegistryInfo;
91     QAI.PrivateDriverDataSize = RegistryInfoSize;
92     if (!NT_SUCCESS(pfnQueryAdapterInfo(&QAI)) ||
93         pRegistryInfo->Status != D3DDDI_QUERYREGISTRY_STATUS_SUCCESS)
94         goto cleanup;
95 
96     if (!WideCharToMultiByte(CP_ACP, 0, pRegistryInfo->OutputString,
97                              RegistryInfo.OutputValueSize / sizeof(wchar_t),
98                              pWin32Ctx->registry_driver_name,
99                              sizeof(pWin32Ctx->registry_driver_name),
100                              NULL, NULL))
101         goto cleanup;
102 
103     pWin32Ctx->registry_driver_available_flag = true;
104 
105 cleanup:
106     if (pRegistryInfo && pRegistryInfo != &RegistryInfo)
107         free(pRegistryInfo);
108     if (pfnCloseAdapter && OpenArgs.hAdapter) {
109         D3DKMT_CLOSEADAPTER Close = { OpenArgs.hAdapter };
110         /* The explicit negation is a no-op, yet required to silence the
111          * Wunused-result warning.
112          */
113         (void) !pfnCloseAdapter(&Close);
114     }
115     FreeLibrary(hGdi32);
116 }
117 
va_DisplayContextDestroy(VADisplayContextP pDisplayContext)118 static void va_DisplayContextDestroy(
119     VADisplayContextP pDisplayContext
120 )
121 {
122     if (pDisplayContext == NULL)
123         return;
124 
125     if (pDisplayContext->pDriverContext
126         && pDisplayContext->pDriverContext->native_dpy)
127         free(pDisplayContext->pDriverContext->native_dpy);
128 
129     free(pDisplayContext->pDriverContext);
130     free(pDisplayContext->opaque);
131     free(pDisplayContext);
132 }
133 
va_DisplayContextGetDriverNames(VADisplayContextP pDisplayContext,char ** drivers,unsigned * num_drivers)134 static VAStatus va_DisplayContextGetDriverNames(
135     VADisplayContextP pDisplayContext,
136     char **drivers,
137     unsigned *num_drivers
138 )
139 {
140     const LUID * const adapter = pDisplayContext->pDriverContext->native_dpy;
141     const VADisplayContextWin32 * const pWin32Ctx = pDisplayContext->opaque;
142     unsigned count = 0;
143 
144     /* Always prefer the adapter registered driver name as first option */
145     if (adapter && pWin32Ctx->registry_driver_available_flag) {
146         drivers[count] = _strdup(pWin32Ctx->registry_driver_name);
147         count++;
148     }
149     /* Provide the default driver name as a fallback option */
150     if (*num_drivers > count) {
151         drivers[count] = _strdup(VAAPI_DEFAULT_DRIVER_NAME);
152         count++;
153     }
154 
155     *num_drivers = count;
156 
157     return VA_STATUS_SUCCESS;
158 }
159 
vaGetDisplayWin32(const LUID * adapter_luid)160 VADisplay vaGetDisplayWin32(
161     /* Can be null for adapter autoselection in the VA driver */
162     const LUID* adapter_luid
163 )
164 {
165     VADisplayContextP pDisplayContext;
166     VADriverContextP  pDriverContext;
167 
168     pDisplayContext = va_newDisplayContext();
169     if (!pDisplayContext)
170         return NULL;
171 
172     pDisplayContext->vaDestroy       = va_DisplayContextDestroy;
173     pDisplayContext->vaGetDriverNames = va_DisplayContextGetDriverNames;
174     pDisplayContext->opaque = calloc(1, sizeof(VADisplayContextWin32));
175     if (!pDisplayContext->opaque) {
176         va_DisplayContextDestroy(pDisplayContext);
177         return NULL;
178     }
179 
180     VADisplayContextWin32* pWin32Ctx = (VADisplayContextWin32*) pDisplayContext->opaque;
181     if (adapter_luid) {
182         /* Load the preferred driver name from the driver registry if available */
183         LoadDriverNameFromRegistry(adapter_luid, pWin32Ctx);
184 #ifdef _DEBUG
185         if (pWin32Ctx->registry_driver_available_flag) {
186             fprintf(stderr, "VA_Win32: Found driver %s in the registry for LUID %ld %ld \n", pWin32Ctx->registry_driver_name, adapter_luid->LowPart, adapter_luid->HighPart);
187         } else {
188             fprintf(stderr, "VA_Win32: Couldn't find a driver in the registry for LUID %ld %ld. Using default driver: %s \n", adapter_luid->LowPart, adapter_luid->HighPart, VAAPI_DEFAULT_DRIVER_NAME);
189         }
190 #endif // _DEBUG
191     }
192 
193     pDriverContext = va_newDriverContext(pDisplayContext);
194     if (!pDriverContext) {
195         va_DisplayContextDestroy(pDisplayContext);
196         return NULL;
197     }
198 
199     pDriverContext->display_type = VA_DISPLAY_WIN32;
200 
201     if (adapter_luid) {
202         /* Copy LUID information to driver context */
203         pDriverContext->native_dpy   = calloc(1, sizeof(*adapter_luid));
204         memcpy(pDriverContext->native_dpy, adapter_luid, sizeof(*adapter_luid));
205     }
206 
207     return (VADisplay)pDisplayContext;
208 }
209