/* * 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 #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 = LoadLibraryA("gdi32.dll"); if (h == NULL) return ret; if(GetProcAddress(h, "D3DKMTSubmitPresentBltToHwQueue")) // OS Version check { LoaderEnumAdapters2 EnumAdapters; NTSTATUS status = STATUS_SUCCESS; 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_UTF8, 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) { char cszLibraryName[MAX_PATH]; result = WideCharToMultiByte( CP_UTF8, 0, pQueryArgs->output_string, -1, cszLibraryName, MAX_PATH, NULL, NULL); if (!result) { KHR_ICD_TRACE("WideCharToMultiByte status != SUCCESS\n"); } else { 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; }