blob: ef36f8cd0cc35a1ffd7632966b982cd8eee59583 [file] [log] [blame]
Adithya Srinivasan01364142019-07-02 15:52:49 -07001#!/usr/bin/env python3
2#
3# Copyright 2019 The Android Open Source Project
4#
5# Licensed under the Apache License, Version 2.0 (the "License");
6# you may not use this file except in compliance with the License.
7# You may obtain a copy of the License at
8#
9# http://www.apache.org/licenses/LICENSE-2.0
10#
11# Unless required by applicable law or agreed to in writing, software
12# distributed under the License is distributed on an "AS IS" BASIS,
13# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14# See the License for the specific language governing permissions and
15# limitations under the License.
16#
17# This script provides the functions for generating the
18# vulkan driver framework directly from the vulkan registry (vk.xml).
19
20import generator_common as gencom
21import os
22
23interceptedExtensions = [
24 'VK_ANDROID_native_buffer',
25 'VK_EXT_debug_report',
26 'VK_EXT_hdr_metadata',
27 'VK_EXT_swapchain_colorspace',
28 'VK_GOOGLE_display_timing',
29 'VK_KHR_android_surface',
30 'VK_KHR_incremental_present',
31 'VK_KHR_shared_presentable_image',
32 'VK_KHR_surface',
33 'VK_KHR_swapchain',
34 'VK_KHR_get_surface_capabilities2'
35]
36
37knownExtensions = interceptedExtensions + [
38 'VK_KHR_get_physical_device_properties2',
39 'VK_ANDROID_external_memory_android_hardware_buffer',
40 'VK_KHR_bind_memory2'
41]
42
43def defineProcHookType(f):
44 f.write ("""struct ProcHook {
45 enum Type {
46 GLOBAL,
47 INSTANCE,
48 DEVICE,
49 };
50 enum Extension {\n""")
51 for exts in knownExtensions:
52 f.write (gencom.clang_off_spaces*2 + exts[3:] + ',\n')
53 f.write ('\n')
54 f.write (gencom.clang_off_spaces*2 + """EXTENSION_CORE, // valid bit
55 EXTENSION_COUNT,
56 EXTENSION_UNKNOWN,
57 };
58
59 const char* name;
60 Type type;
61 Extension extension;
62
63 PFN_vkVoidFunction proc;
64 PFN_vkVoidFunction checked_proc; // always nullptr for non-device hooks
65};\n\n""")
66
67def isExtensionIntercepted(extensionName):
68 if extensionName in interceptedExtensions:
69 return True
70 return False
71
72def isDriverTableEntry(functionName):
73 switchCase = {
74 # Create functions of dispatchable objects
75 'vkCreateDevice' : True,
76 'vkGetDeviceQueue' : True,
77 'vkGetDeviceQueue2' : True,
78 'vkAllocateCommandBuffers' : True,
79
80 # Destroy functions of dispatchable objects
81 'vkDestroyInstance' : True,
82 'vkDestroyDevice' : True,
83
84 # Enumeration of extensions
85 'vkEnumerateDeviceExtensionProperties' : True,
86
87 # We cache physical devices in loader.cpp
88 'vkEnumeratePhysicalDevices' : True,
89 'vkEnumeratePhysicalDeviceGroups' : True,
90
91 'vkGetInstanceProcAddr' : True,
92 'vkGetDeviceProcAddr' : True,
93
Yiwei Zhang899d1752019-09-23 16:05:35 -070094 'vkQueueSubmit' : True,
95
Adithya Srinivasan01364142019-07-02 15:52:49 -070096 # VK_KHR_swapchain->VK_ANDROID_native_buffer translation
97 'vkCreateImage' : True,
98 'vkDestroyImage' : True,
99
100 'vkGetPhysicalDeviceProperties' : True,
101 'vkGetPhysicalDeviceProperties2' : True,
102 'vkGetPhysicalDeviceProperties2KHR' : True,
103
104 # VK_KHR_swapchain v69 requirement
105 'vkBindImageMemory2' : True,
106 'vkBindImageMemory2KHR' : True
107 }
108 if gencom.isFunctionSupported(functionName):
109 if functionName in switchCase:
110 return True
111 if functionName in gencom.extensionsDict:
112 if gencom.extensionsDict[functionName] == 'VK_ANDROID_native_buffer' or gencom.extensionsDict[functionName] == 'VK_EXT_debug_report':
113 return True
114 return False
115
116def isInstanceDriverTableEntry(functionName):
117 if isDriverTableEntry(functionName) and gencom.isInstanceDispatched(functionName):
118 return True
119 return False
120
121def isDeviceDriverTableEntry(functionName):
122 if isDriverTableEntry(functionName) and gencom.isDeviceDispatched(functionName):
123 return True
124 return False
125
126def driver_genh():
127 header = """#ifndef LIBVULKAN_DRIVER_GEN_H
128#define LIBVULKAN_DRIVER_GEN_H
129
130#include <vulkan/vk_android_native_buffer.h>
131#include <vulkan/vulkan.h>
132
133#include <bitset>
134
135namespace vulkan {
136namespace driver {\n\n"""
Adithya Srinivasan8dce9d72019-07-11 14:26:04 -0700137 genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen.h')
Adithya Srinivasan01364142019-07-02 15:52:49 -0700138 with open(genfile, 'w') as f:
139 f.write (gencom.copyright)
140 f.write (gencom.warning)
141 f.write (header)
142 defineProcHookType(f)
143 f.write ('struct InstanceDriverTable {\n')
144 gencom.clang_off(f, 1)
145 for cmds in gencom.allCommandsList:
146 if isInstanceDriverTableEntry(cmds):
147 f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n')
148 gencom.clang_on(f, 1)
149 f.write ('};\n\n')
150 f.write ('struct DeviceDriverTable {\n')
151 gencom.clang_off(f,1)
152 for cmds in gencom.allCommandsList:
153 if isDeviceDriverTableEntry(cmds):
154 f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n')
155 gencom.clang_on(f,1)
156 f.write ('};\n\n')
157 f.write ("""const ProcHook* GetProcHook(const char* name);
158ProcHook::Extension GetProcHookExtension(const char* name);
159
160bool InitDriverTable(VkInstance instance,
161 PFN_vkGetInstanceProcAddr get_proc,
162 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
163bool InitDriverTable(VkDevice dev,
164 PFN_vkGetDeviceProcAddr get_proc,
165 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
166
167} // namespace driver
168} // namespace vulkan
169
170#endif // LIBVULKAN_DRIVER_TABLE_H\n""")
Adithya Srinivasan8dce9d72019-07-11 14:26:04 -0700171 f.close()
172 gencom.runClangFormat(genfile)
Adithya Srinivasan01364142019-07-02 15:52:49 -0700173
174def isIntercepted(functionName):
175 switchCase = {
176 # Create functions of dispatchable objects
177 'vkCreateInstance' : True,
178 'vkCreateDevice' : True,
179 'vkEnumeratePhysicalDevices' : True,
180 'vkEnumeratePhysicalDeviceGroups' : True,
181 'vkGetDeviceQueue' : True,
182 'vkGetDeviceQueue2' : True,
183 'vkAllocateCommandBuffers' : True,
184
185 # Destroy functions of dispatchable objects
186 'vkDestroyInstance' : True,
187 'vkDestroyDevice' : True,
188
189 # Enumeration of extensions
190 'vkEnumerateInstanceExtensionProperties' : True,
191 'vkEnumerateDeviceExtensionProperties' : True,
192
193 'vkGetInstanceProcAddr' : True,
194 'vkGetDeviceProcAddr' : True,
195
Yiwei Zhang899d1752019-09-23 16:05:35 -0700196 'vkQueueSubmit' : True,
197
Adithya Srinivasan01364142019-07-02 15:52:49 -0700198 # VK_KHR_swapchain v69 requirement
199 'vkBindImageMemory2' : True,
200 'vkBindImageMemory2KHR' : True
201 }
202 if gencom.isFunctionSupported(functionName):
203 if functionName in switchCase:
204 return switchCase[functionName]
205
206 if functionName in gencom.extensionsDict:
207 return isExtensionIntercepted(gencom.extensionsDict[functionName])
208 return False
209
210def needProcHookStub(functionName):
211 if isIntercepted(functionName) and gencom.isDeviceDispatched(functionName):
212 if functionName in gencom.extensionsDict:
213 if not gencom.isExtensionInternal(gencom.extensionsDict[functionName]):
214 return True
215 return False
216
217def defineInitProc(name, f):
218 f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n')
219 f.write ('\n')
220 f.write ("""#define INIT_PROC(required, obj, proc) \\
221 do { \\
222 data.""" + name + """.proc = \\
223 reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
224 if (UNLIKELY(required && !data.""" + name + """.proc)) { \\
225 ALOGE("missing " #obj " proc: vk" #proc); \\
226 success = false; \\
227 } \\
228 } while (0)\n\n""")
229
230def defineInitProcExt(f):
231 f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\
232 do { \\
233 if (extensions[ProcHook::ext]) \\
234 INIT_PROC(required, obj, proc); \\
235 } while (0)\n\n""")
236
237def defineProcHookStub(functionName, f):
238 if needProcHookStub(functionName):
239 ext_name = gencom.extensionsDict[functionName]
240 base_name = functionName[2:]
241 paramList = [''.join(i) for i in gencom.paramDict[functionName]]
242 p0 = gencom.paramDict[functionName][0][1]
243 f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' checked' + base_name + '(' + ', '.join(paramList) + ') {\n')
244 ext_hook = 'ProcHook::' + ext_name[3:]
245
246 f.write (gencom.clang_off_spaces + 'if (GetData(' + p0 + ').hook_extensions[' + ext_hook + ']) {\n')
247 f.write (gencom.clang_off_spaces *2)
248 if gencom.returnTypeDict[functionName] != 'void':
249 f.write ('return ')
250 paramNames = [''.join(i[1]) for i in gencom.paramDict[functionName]]
251 f.write (base_name + '(' + ', '.join(paramNames) + ');\n')
252 f.write (gencom.clang_off_spaces + '} else {\n')
253 f.write (gencom.clang_off_spaces*2 + 'Logger(' + p0 + ').Err(' + p0 + ', \"' + ext_name + ' not enabled. ' + functionName + ' not executed.\");\n')
254 if gencom.returnTypeDict[functionName] != 'void':
255 f.write (gencom.clang_off_spaces*2 + 'return VK_SUCCESS;\n')
256 f.write (gencom.clang_off_spaces + '}\n')
257 f.write ('}\n\n')
258
259def defineGlobalProcHook(functionName, f):
260 base_name = functionName[2:]
261 assert (functionName not in gencom.extensionsDict)
262 f.write (gencom.clang_off_spaces + '{\n' + gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n' + gencom.clang_off_spaces*2)
263 f.write ("""ProcHook::GLOBAL,
264 ProcHook::EXTENSION_CORE,
265 reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
266 nullptr,
267 },\n""")
268
269def defineInstanceProcHook(functionName, f):
270 base_name = functionName[2:]
271 f.write (gencom.clang_off_spaces + '{\n')
272 f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n')
273 f.write (gencom.clang_off_spaces*2 + 'ProcHook::INSTANCE,\n')
274
275 if functionName in gencom.extensionsDict:
276 ext_name = gencom.extensionsDict[functionName]
277 f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n')
278 if gencom.isExtensionInternal(ext_name):
279 f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
280 else:
281 f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
282
283 else:
284 f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE,
285 reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
286 nullptr,\n""")
287
288 f.write (gencom.clang_off_spaces + '},\n')
289
290def defineDeviceProcHook(functionName, f):
291 base_name = functionName[2:]
292 f.write (gencom.clang_off_spaces + '{\n')
293 f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n')
294 f.write (gencom.clang_off_spaces*2 + 'ProcHook::DEVICE,\n')
295
296 if functionName in gencom.extensionsDict:
297 ext_name = gencom.extensionsDict[functionName]
298 f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n')
299 if gencom.isExtensionInternal(ext_name):
300 f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
301 else:
302 f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(checked' + base_name + '),\n')
303
304 else:
305 f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE,
306 reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
307 nullptr,\n""")
308
309 f.write (gencom.clang_off_spaces + '},\n')
310
311def driver_gencpp():
312 header = """#include <log/log.h>
313#include <string.h>
314
315#include <algorithm>
316
317#include "driver.h"
318
319namespace vulkan {
320namespace driver {
321
322namespace {
323
324// clang-format off\n\n"""
325
Adithya Srinivasan8dce9d72019-07-11 14:26:04 -0700326 genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen.cpp')
Adithya Srinivasan01364142019-07-02 15:52:49 -0700327
328 with open(genfile, 'w') as f:
329 f.write (gencom.copyright)
330 f.write (gencom.warning)
331 f.write (header)
332
333 for cmds in gencom.allCommandsList:
334 defineProcHookStub(cmds, f)
335 gencom.clang_on(f, 0)
336 f.write ('\n')
337
338 f.write ('const ProcHook g_proc_hooks[] = {\n')
339 gencom.clang_off(f, 1)
340 sortedCommandsList = sorted(gencom.allCommandsList)
341 for cmds in sortedCommandsList:
342 if isIntercepted(cmds):
343 if gencom.isGloballyDispatched(cmds):
344 defineGlobalProcHook(cmds, f)
345 elif gencom.isInstanceDispatched(cmds):
346 defineInstanceProcHook(cmds, f)
347 elif gencom.isDeviceDispatched(cmds):
348 defineDeviceProcHook(cmds, f)
349 gencom.clang_on(f, 1)
350 f.write ('};\n\n} // namespace\n\n')
351
352 f.write ("""const ProcHook* GetProcHook(const char* name) {
353 const auto& begin = g_proc_hooks;
354 const auto& end =
355 g_proc_hooks + sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]);
356 const auto hook = std::lower_bound(
357 begin, end, name,
358 [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; });
359 return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr;
360}\n\n""")
361
362 f.write ('ProcHook::Extension GetProcHookExtension(const char* name) {\n')
363 gencom.clang_off(f, 1)
364 for exts in knownExtensions:
365 f.write (gencom.clang_off_spaces + 'if (strcmp(name, \"' + exts + '\") == 0) return ProcHook::' + exts[3:] + ';\n')
366 gencom.clang_on(f, 1)
367 f.write (gencom.clang_off_spaces + 'return ProcHook::EXTENSION_UNKNOWN;\n')
368 f.write ('}\n\n')
369
370 defineInitProc('driver', f)
371 defineInitProcExt(f)
372
373 f.write ("""bool InitDriverTable(VkInstance instance,
374 PFN_vkGetInstanceProcAddr get_proc,
375 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
376 auto& data = GetData(instance);
377 bool success = true;\n\n""")
378 gencom.clang_off(f, 1)
379 for cmds in gencom.allCommandsList:
380 if isInstanceDriverTableEntry(cmds):
381 gencom.initProc(cmds, f)
382 gencom.clang_on(f, 1)
383 f.write ('\n' + gencom.clang_off_spaces + 'return success;\n')
384 f.write ('}\n\n')
385
386 f.write ("""bool InitDriverTable(VkDevice dev,
387 PFN_vkGetDeviceProcAddr get_proc,
388 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
389 auto& data = GetData(dev);
390 bool success = true;\n\n""")
391 gencom.clang_off(f, 1)
392 for cmds in gencom.allCommandsList:
393 if isDeviceDriverTableEntry(cmds):
394 gencom.initProc(cmds, f)
395 gencom.clang_on(f, 1)
396 f.write ('\n' + gencom.clang_off_spaces + 'return success;\n')
397 f.write ('}\n\n} // namespace driver\n} // namespace vulkan\n\n')
398 gencom.clang_on(f, 0)
Adithya Srinivasan8dce9d72019-07-11 14:26:04 -0700399 f.close()
400 gencom.runClangFormat(genfile)