blob: 350ee3a2775daf6d1c86bc286de1cf8fcac15ef3 [file] [log] [blame]
/*
* Copyright © Microsoft Corporation
* Copyright (c) 2023 Emil Velikov
*
* 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 "sysdeps.h"
#include "va.h"
#include "va_backend.h"
#include "va_internal.h"
#include "va_trace.h"
#include "va_win32.h"
#include "compat_win32.h"
/*
* Initialize default driver to the VAOn12 driver implementation
* which will be selected when provided with an adapter LUID which
* does not have a registered VA driver
*/
const char VAAPI_DEFAULT_DRIVER_NAME[] = "vaon12";
typedef struct _VADisplayContextWin32 {
char registry_driver_name[MAX_PATH];
bool registry_driver_available_flag;
} VADisplayContextWin32;
static void LoadDriverNameFromRegistry(const LUID* adapter_luid, VADisplayContextWin32* pWin32Ctx)
{
HMODULE hGdi32 = LoadLibraryA("gdi32.dll");
if (!hGdi32)
return;
D3DKMT_OPENADAPTERFROMLUID OpenArgs = { .AdapterLuid = *adapter_luid };
D3DDDI_QUERYREGISTRY_INFO RegistryInfo = {
.QueryType = D3DDDI_QUERYREGISTRY_ADAPTERKEY,
.QueryFlags.TranslatePath = true,
.ValueName = L"VAAPIDriverName",
.ValueType = REG_SZ,
};
D3DDDI_QUERYREGISTRY_INFO *pRegistryInfo = &RegistryInfo;
#ifndef _WIN64
BOOL isWowProcess = false;
if (IsWow64Process(GetCurrentProcess(), &isWowProcess) && isWowProcess)
wcscpy(RegistryInfo.ValueName, L"VAAPIDriverNameWow");
#endif
D3DKMT_QUERYADAPTERINFO QAI = {
.Type = KMTQAITYPE_QUERYREGISTRY,
.pPrivateDriverData = &RegistryInfo,
.PrivateDriverDataSize = sizeof(RegistryInfo),
};
PFND3DKMT_OPENADAPTERFROMLUID pfnOpenAdapterFromLuid = (PFND3DKMT_OPENADAPTERFROMLUID)GetProcAddress(hGdi32, "D3DKMTOpenAdapterFromLuid");
PFND3DKMT_CLOSEADAPTER pfnCloseAdapter = (PFND3DKMT_CLOSEADAPTER)GetProcAddress(hGdi32, "D3DKMTCloseAdapter");
PFND3DKMT_QUERYADAPTERINFO pfnQueryAdapterInfo = (PFND3DKMT_QUERYADAPTERINFO)GetProcAddress(hGdi32, "D3DKMTQueryAdapterInfo");
if (!pfnOpenAdapterFromLuid || !pfnCloseAdapter || !pfnQueryAdapterInfo)
goto cleanup;
if (!NT_SUCCESS(pfnOpenAdapterFromLuid(&OpenArgs)))
goto cleanup;
QAI.hAdapter = OpenArgs.hAdapter;
if (!NT_SUCCESS(pfnQueryAdapterInfo(&QAI)) ||
pRegistryInfo->Status != D3DDDI_QUERYREGISTRY_STATUS_BUFFER_OVERFLOW)
goto cleanup;
size_t RegistryInfoSize = sizeof(RegistryInfo) + RegistryInfo.OutputValueSize;
pRegistryInfo = malloc(RegistryInfoSize);
if (!pRegistryInfo)
goto cleanup;
memcpy(pRegistryInfo, &RegistryInfo, sizeof(RegistryInfo));
QAI.pPrivateDriverData = pRegistryInfo;
QAI.PrivateDriverDataSize = RegistryInfoSize;
if (!NT_SUCCESS(pfnQueryAdapterInfo(&QAI)) ||
pRegistryInfo->Status != D3DDDI_QUERYREGISTRY_STATUS_SUCCESS)
goto cleanup;
if (!WideCharToMultiByte(CP_ACP, 0, pRegistryInfo->OutputString,
RegistryInfo.OutputValueSize / sizeof(wchar_t),
pWin32Ctx->registry_driver_name,
sizeof(pWin32Ctx->registry_driver_name),
NULL, NULL))
goto cleanup;
pWin32Ctx->registry_driver_available_flag = true;
cleanup:
if (pRegistryInfo && pRegistryInfo != &RegistryInfo)
free(pRegistryInfo);
if (pfnCloseAdapter && OpenArgs.hAdapter) {
D3DKMT_CLOSEADAPTER Close = { OpenArgs.hAdapter };
/* The explicit negation is a no-op, yet required to silence the
* Wunused-result warning.
*/
(void) !pfnCloseAdapter(&Close);
}
FreeLibrary(hGdi32);
}
static void va_DisplayContextDestroy(
VADisplayContextP pDisplayContext
)
{
if (pDisplayContext == NULL)
return;
if (pDisplayContext->pDriverContext
&& pDisplayContext->pDriverContext->native_dpy)
free(pDisplayContext->pDriverContext->native_dpy);
free(pDisplayContext->pDriverContext);
free(pDisplayContext->opaque);
free(pDisplayContext);
}
static VAStatus va_DisplayContextGetDriverNames(
VADisplayContextP pDisplayContext,
char **drivers,
unsigned *num_drivers
)
{
const LUID * const adapter = pDisplayContext->pDriverContext->native_dpy;
const VADisplayContextWin32 * const pWin32Ctx = pDisplayContext->opaque;
unsigned count = 0;
/* Always prefer the adapter registered driver name as first option */
if (adapter && pWin32Ctx->registry_driver_available_flag) {
drivers[count] = _strdup(pWin32Ctx->registry_driver_name);
count++;
}
/* Provide the default driver name as a fallback option */
if (*num_drivers > count) {
drivers[count] = _strdup(VAAPI_DEFAULT_DRIVER_NAME);
count++;
}
*num_drivers = count;
return VA_STATUS_SUCCESS;
}
VADisplay vaGetDisplayWin32(
/* Can be null for adapter autoselection in the VA driver */
const LUID* adapter_luid
)
{
VADisplayContextP pDisplayContext;
VADriverContextP pDriverContext;
pDisplayContext = va_newDisplayContext();
if (!pDisplayContext)
return NULL;
pDisplayContext->vaDestroy = va_DisplayContextDestroy;
pDisplayContext->vaGetDriverNames = va_DisplayContextGetDriverNames;
pDisplayContext->opaque = calloc(1, sizeof(VADisplayContextWin32));
if (!pDisplayContext->opaque) {
va_DisplayContextDestroy(pDisplayContext);
return NULL;
}
VADisplayContextWin32* pWin32Ctx = (VADisplayContextWin32*) pDisplayContext->opaque;
if (adapter_luid) {
/* Load the preferred driver name from the driver registry if available */
LoadDriverNameFromRegistry(adapter_luid, pWin32Ctx);
#ifdef _DEBUG
if (pWin32Ctx->registry_driver_available_flag) {
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);
} else {
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);
}
#endif // _DEBUG
}
pDriverContext = va_newDriverContext(pDisplayContext);
if (!pDriverContext) {
va_DisplayContextDestroy(pDisplayContext);
return NULL;
}
pDriverContext->display_type = VA_DISPLAY_WIN32;
if (adapter_luid) {
/* Copy LUID information to driver context */
pDriverContext->native_dpy = calloc(1, sizeof(*adapter_luid));
memcpy(pDriverContext->native_dpy, adapter_luid, sizeof(*adapter_luid));
}
return (VADisplay)pDisplayContext;
}