xref: /aosp_15_r20/external/OpenCL-ICD-Loader/loader/windows/icd_windows_dxgk.c (revision 1cddb830dba8aa7c1cc1039338e56b3b9fa24952)
1 /*
2  * Copyright (c) 2017-2020 The Khronos Group Inc.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  *     http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  *
16  * OpenCL is a trademark of Apple Inc. used under license by Khronos.
17  */
18 
19 #include "icd.h"
20 #include "icd_windows_dxgk.h"
21 
22 #include <windows.h>
23 #include "adapter.h"
24 
25 #ifndef NTSTATUS
26 typedef LONG NTSTATUS;
27 #define STATUS_SUCCESS  ((NTSTATUS)0x00000000L)
28 #define STATUS_BUFFER_TOO_SMALL ((NTSTATUS)0xC0000023)
29 #define NT_SUCCESS(status) (((NTSTATUS)(status)) >= 0)
30 #endif
31 
khrIcdOsVendorsEnumerateDXGK(void)32 bool khrIcdOsVendorsEnumerateDXGK(void)
33 {
34     bool ret = false;
35     int result = 0;
36 
37     // Get handle to GDI Runtime
38     HMODULE h = LoadLibraryA("gdi32.dll");
39     if (h == NULL)
40         return ret;
41 
42     if(GetProcAddress(h, "D3DKMTSubmitPresentBltToHwQueue")) // OS Version check
43     {
44         LoaderEnumAdapters2 EnumAdapters;
45         NTSTATUS status = STATUS_SUCCESS;
46 
47         EnumAdapters.adapter_count = 0;
48         EnumAdapters.adapters = NULL;
49         PFN_LoaderEnumAdapters2 pEnumAdapters2 = (PFN_LoaderEnumAdapters2)GetProcAddress(h, "D3DKMTEnumAdapters2");
50         if (!pEnumAdapters2)
51         {
52             KHR_ICD_TRACE("GetProcAddress failed for D3DKMTEnumAdapters2\n");
53             goto out;
54         }
55         PFN_LoaderQueryAdapterInfo pQueryAdapterInfo = (PFN_LoaderQueryAdapterInfo)GetProcAddress(h, "D3DKMTQueryAdapterInfo");
56         if (!pQueryAdapterInfo)
57         {
58             KHR_ICD_TRACE("GetProcAddress failed for D3DKMTQueryAdapterInfo\n");
59             goto out;
60         }
61         while (1)
62         {
63             EnumAdapters.adapter_count = 0;
64             EnumAdapters.adapters = NULL;
65             status = pEnumAdapters2(&EnumAdapters);
66             if (status == STATUS_BUFFER_TOO_SMALL)
67             {
68                 // Number of Adapters increased between calls, retry;
69                 continue;
70             }
71             else if (!NT_SUCCESS(status))
72             {
73                 KHR_ICD_TRACE("D3DKMTEnumAdapters2 status != SUCCESS\n");
74                 goto out;
75             }
76             break;
77         }
78         EnumAdapters.adapters = malloc(sizeof(*EnumAdapters.adapters)*(EnumAdapters.adapter_count));
79         if (EnumAdapters.adapters == NULL)
80         {
81             KHR_ICD_TRACE("Allocation failure for adapters buffer\n");
82             goto out;
83         }
84         status = pEnumAdapters2(&EnumAdapters);
85         if (!NT_SUCCESS(status))
86         {
87             KHR_ICD_TRACE("D3DKMTEnumAdapters2 status != SUCCESS\n");
88             goto out;
89         }
90         const char* cszOpenCLRegKeyName = getOpenCLRegKeyName();
91         const int szOpenCLRegKeyName = (int)(strlen(cszOpenCLRegKeyName) + 1)*sizeof(cszOpenCLRegKeyName[0]);
92         for (UINT AdapterIndex = 0; AdapterIndex < EnumAdapters.adapter_count; AdapterIndex++)
93         {
94             LoaderQueryRegistryInfo queryArgs = {0};
95             LoaderQueryRegistryInfo* pQueryArgs = &queryArgs;
96             LoaderQueryRegistryInfo* pQueryBuffer = NULL;
97             queryArgs.query_type = LOADER_QUERY_REGISTRY_ADAPTER_KEY;
98             queryArgs.query_flags.translate_path = TRUE;
99             queryArgs.value_type = REG_SZ;
100             result = MultiByteToWideChar(
101                 CP_UTF8,
102                 0,
103                 cszOpenCLRegKeyName,
104                 szOpenCLRegKeyName,
105                 queryArgs.value_name,
106                 ARRAYSIZE(queryArgs.value_name));
107             if (!result)
108             {
109                 KHR_ICD_TRACE("MultiByteToWideChar status != SUCCESS\n");
110                 continue;
111             }
112             LoaderQueryAdapterInfo queryAdapterInfo = {0};
113             queryAdapterInfo.handle = EnumAdapters.adapters[AdapterIndex].handle;
114             queryAdapterInfo.type = LOADER_QUERY_TYPE_REGISTRY;
115             queryAdapterInfo.private_data = &queryArgs;
116             queryAdapterInfo.private_data_size = sizeof(queryArgs);
117             status = pQueryAdapterInfo(&queryAdapterInfo);
118             if (!NT_SUCCESS(status))
119             {
120                 // Try a different value type.  Some vendors write the key as a multi-string type.
121                 queryArgs.value_type = REG_MULTI_SZ;
122                 status = pQueryAdapterInfo(&queryAdapterInfo);
123                 if (NT_SUCCESS(status))
124                 {
125                     KHR_ICD_TRACE("Accepting multi-string registry key type\n");
126                 }
127                 else
128                 {
129                     // Continue trying to get as much info on each adapter as possible.
130                     // It's too late to return FALSE and claim WDDM2_4 enumeration is not available here.
131                     continue;
132                 }
133             }
134             if (NT_SUCCESS(status) && pQueryArgs->status == LOADER_QUERY_REGISTRY_STATUS_BUFFER_OVERFLOW)
135             {
136                 ULONG queryBufferSize = sizeof(LoaderQueryRegistryInfo) + queryArgs.output_value_size;
137                 pQueryBuffer = malloc(queryBufferSize);
138                 if (pQueryBuffer == NULL)
139                     continue;
140                 memcpy(pQueryBuffer, &queryArgs, sizeof(LoaderQueryRegistryInfo));
141                 queryAdapterInfo.private_data = pQueryBuffer;
142                 queryAdapterInfo.private_data_size = queryBufferSize;
143                 status = pQueryAdapterInfo(&queryAdapterInfo);
144                 pQueryArgs = pQueryBuffer;
145             }
146             if (NT_SUCCESS(status) && pQueryArgs->status == LOADER_QUERY_REGISTRY_STATUS_SUCCESS)
147             {
148                 char cszLibraryName[MAX_PATH];
149                 result = WideCharToMultiByte(
150                     CP_UTF8,
151                     0,
152                     pQueryArgs->output_string,
153                     -1,
154                     cszLibraryName,
155                     MAX_PATH,
156                     NULL,
157                     NULL);
158                 if (!result)
159                 {
160                     KHR_ICD_TRACE("WideCharToMultiByte status != SUCCESS\n");
161                 }
162                 else
163                 {
164                     ret |= adapterAdd(cszLibraryName, EnumAdapters.adapters[AdapterIndex].luid);
165                 }
166             }
167             else if (status == (NTSTATUS)STATUS_INVALID_PARAMETER)
168             {
169                 free(pQueryBuffer);
170                 goto out;
171             }
172             free(pQueryBuffer);
173         }
174 out:
175       free(EnumAdapters.adapters);
176     }
177 
178     FreeLibrary(h);
179 
180     return ret;
181 }
182