blob: 5dc985c606821123257818634e9366d5ace880d1 [file] [log] [blame]
/*
* Copyright (c) 2017-2020 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
* OpenCL is a trademark of Apple Inc. used under license by Khronos.
*/
#include "icd.h"
#include "icd_windows_dxgk.h"
#include <windows.h>
#include "adapter.h"
#ifndef NTSTATUS
typedef LONG NTSTATUS;
#define STATUS_SUCCESS ((NTSTATUS)0x00000000L)
#define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023)
#define NT_SUCCESS(status) (((NTSTATUS)(status)) >= 0)
#endif
bool khrIcdOsVendorsEnumerateDXGK(void)
{
bool ret = false;
int result = 0;
// Get handle to GDI Runtime
HMODULE h = LoadLibrary("gdi32.dll");
if (h == NULL)
return ret;
if(GetProcAddress(h, "D3DKMTSubmitPresentBltToHwQueue")) // OS Version check
{
LoaderEnumAdapters2 EnumAdapters;
NTSTATUS status = STATUS_SUCCESS;
char cszLibraryName[MAX_PATH] = { 0 };
EnumAdapters.adapter_count = 0;
EnumAdapters.adapters = NULL;
PFN_LoaderEnumAdapters2 pEnumAdapters2 = (PFN_LoaderEnumAdapters2)GetProcAddress(h, "D3DKMTEnumAdapters2");
if (!pEnumAdapters2)
{
KHR_ICD_TRACE("GetProcAddress failed for D3DKMTEnumAdapters2\n");
goto out;
}
PFN_LoaderQueryAdapterInfo pQueryAdapterInfo = (PFN_LoaderQueryAdapterInfo)GetProcAddress(h, "D3DKMTQueryAdapterInfo");
if (!pQueryAdapterInfo)
{
KHR_ICD_TRACE("GetProcAddress failed for D3DKMTQueryAdapterInfo\n");
goto out;
}
while (1)
{
EnumAdapters.adapter_count = 0;
EnumAdapters.adapters = NULL;
status = pEnumAdapters2(&EnumAdapters);
if (status == STATUS_BUFFER_TOO_SMALL)
{
// Number of Adapters increased between calls, retry;
continue;
}
else if (!NT_SUCCESS(status))
{
KHR_ICD_TRACE("D3DKMTEnumAdapters2 status != SUCCESS\n");
goto out;
}
break;
}
EnumAdapters.adapters = malloc(sizeof(*EnumAdapters.adapters)*(EnumAdapters.adapter_count));
if (EnumAdapters.adapters == NULL)
{
KHR_ICD_TRACE("Allocation failure for adapters buffer\n");
goto out;
}
status = pEnumAdapters2(&EnumAdapters);
if (!NT_SUCCESS(status))
{
KHR_ICD_TRACE("D3DKMTEnumAdapters2 status != SUCCESS\n");
goto out;
}
const char* cszOpenCLRegKeyName = getOpenCLRegKeyName();
const int szOpenCLRegKeyName = (int)(strlen(cszOpenCLRegKeyName) + 1)*sizeof(cszOpenCLRegKeyName[0]);
for (UINT AdapterIndex = 0; AdapterIndex < EnumAdapters.adapter_count; AdapterIndex++)
{
LoaderQueryRegistryInfo queryArgs = {0};
LoaderQueryRegistryInfo* pQueryArgs = &queryArgs;
LoaderQueryRegistryInfo* pQueryBuffer = NULL;
queryArgs.query_type = LOADER_QUERY_REGISTRY_ADAPTER_KEY;
queryArgs.query_flags.translate_path = TRUE;
queryArgs.value_type = REG_SZ;
result = MultiByteToWideChar(
CP_ACP,
0,
cszOpenCLRegKeyName,
szOpenCLRegKeyName,
queryArgs.value_name,
ARRAYSIZE(queryArgs.value_name));
if (!result)
{
KHR_ICD_TRACE("MultiByteToWideChar status != SUCCESS\n");
continue;
}
LoaderQueryAdapterInfo queryAdapterInfo = {0};
queryAdapterInfo.handle = EnumAdapters.adapters[AdapterIndex].handle;
queryAdapterInfo.type = LOADER_QUERY_TYPE_REGISTRY;
queryAdapterInfo.private_data = &queryArgs;
queryAdapterInfo.private_data_size = sizeof(queryArgs);
status = pQueryAdapterInfo(&queryAdapterInfo);
if (!NT_SUCCESS(status))
{
// Try a different value type. Some vendors write the key as a multi-string type.
queryArgs.value_type = REG_MULTI_SZ;
status = pQueryAdapterInfo(&queryAdapterInfo);
if (NT_SUCCESS(status))
{
KHR_ICD_TRACE("Accepting multi-string registry key type\n");
}
else
{
// Continue trying to get as much info on each adapter as possible.
// It's too late to return FALSE and claim WDDM2_4 enumeration is not available here.
continue;
}
}
if (NT_SUCCESS(status) && pQueryArgs->status == LOADER_QUERY_REGISTRY_STATUS_BUFFER_OVERFLOW)
{
ULONG queryBufferSize = sizeof(LoaderQueryRegistryInfo) + queryArgs.output_value_size;
pQueryBuffer = malloc(queryBufferSize);
if (pQueryBuffer == NULL)
continue;
memcpy(pQueryBuffer, &queryArgs, sizeof(LoaderQueryRegistryInfo));
queryAdapterInfo.private_data = pQueryBuffer;
queryAdapterInfo.private_data_size = queryBufferSize;
status = pQueryAdapterInfo(&queryAdapterInfo);
pQueryArgs = pQueryBuffer;
}
if (NT_SUCCESS(status) && pQueryArgs->status == LOADER_QUERY_REGISTRY_STATUS_SUCCESS)
{
wchar_t* pWchar = pQueryArgs->output_string;
memset(cszLibraryName, 0, sizeof(cszLibraryName));
{
size_t len;
wcstombs_s(&len, cszLibraryName, sizeof(cszLibraryName), pWchar, sizeof(cszLibraryName));
KHR_ICD_ASSERT(len == (sizeof(cszLibraryName) - 1));
ret |= adapterAdd(cszLibraryName, EnumAdapters.adapters[AdapterIndex].luid);
}
}
else if (status == (NTSTATUS)STATUS_INVALID_PARAMETER)
{
free(pQueryBuffer);
goto out;
}
free(pQueryBuffer);
}
out:
free(EnumAdapters.adapters);
}
FreeLibrary(h);
return ret;
}