blob: 92326caf464e5a92333939b507c93fad618a2c0c [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
94 # VK_KHR_swapchain->VK_ANDROID_native_buffer translation
95 'vkCreateImage' : True,
96 'vkDestroyImage' : True,
97
98 'vkGetPhysicalDeviceProperties' : True,
99 'vkGetPhysicalDeviceProperties2' : True,
100 'vkGetPhysicalDeviceProperties2KHR' : True,
101
102 # VK_KHR_swapchain v69 requirement
103 'vkBindImageMemory2' : True,
104 'vkBindImageMemory2KHR' : True
105 }
106 if gencom.isFunctionSupported(functionName):
107 if functionName in switchCase:
108 return True
109 if functionName in gencom.extensionsDict:
110 if gencom.extensionsDict[functionName] == 'VK_ANDROID_native_buffer' or gencom.extensionsDict[functionName] == 'VK_EXT_debug_report':
111 return True
112 return False
113
114def isInstanceDriverTableEntry(functionName):
115 if isDriverTableEntry(functionName) and gencom.isInstanceDispatched(functionName):
116 return True
117 return False
118
119def isDeviceDriverTableEntry(functionName):
120 if isDriverTableEntry(functionName) and gencom.isDeviceDispatched(functionName):
121 return True
122 return False
123
124def driver_genh():
125 header = """#ifndef LIBVULKAN_DRIVER_GEN_H
126#define LIBVULKAN_DRIVER_GEN_H
127
128#include <vulkan/vk_android_native_buffer.h>
129#include <vulkan/vulkan.h>
130
131#include <bitset>
132
133namespace vulkan {
134namespace driver {\n\n"""
135 genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen2.h')
136 with open(genfile, 'w') as f:
137 f.write (gencom.copyright)
138 f.write (gencom.warning)
139 f.write (header)
140 defineProcHookType(f)
141 f.write ('struct InstanceDriverTable {\n')
142 gencom.clang_off(f, 1)
143 for cmds in gencom.allCommandsList:
144 if isInstanceDriverTableEntry(cmds):
145 f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n')
146 gencom.clang_on(f, 1)
147 f.write ('};\n\n')
148 f.write ('struct DeviceDriverTable {\n')
149 gencom.clang_off(f,1)
150 for cmds in gencom.allCommandsList:
151 if isDeviceDriverTableEntry(cmds):
152 f.write (gencom.clang_off_spaces + 'PFN_' + cmds + ' ' + cmds[2:] + ';\n')
153 gencom.clang_on(f,1)
154 f.write ('};\n\n')
155 f.write ("""const ProcHook* GetProcHook(const char* name);
156ProcHook::Extension GetProcHookExtension(const char* name);
157
158bool InitDriverTable(VkInstance instance,
159 PFN_vkGetInstanceProcAddr get_proc,
160 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
161bool InitDriverTable(VkDevice dev,
162 PFN_vkGetDeviceProcAddr get_proc,
163 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions);
164
165} // namespace driver
166} // namespace vulkan
167
168#endif // LIBVULKAN_DRIVER_TABLE_H\n""")
169
170def isIntercepted(functionName):
171 switchCase = {
172 # Create functions of dispatchable objects
173 'vkCreateInstance' : True,
174 'vkCreateDevice' : True,
175 'vkEnumeratePhysicalDevices' : True,
176 'vkEnumeratePhysicalDeviceGroups' : True,
177 'vkGetDeviceQueue' : True,
178 'vkGetDeviceQueue2' : True,
179 'vkAllocateCommandBuffers' : True,
180
181 # Destroy functions of dispatchable objects
182 'vkDestroyInstance' : True,
183 'vkDestroyDevice' : True,
184
185 # Enumeration of extensions
186 'vkEnumerateInstanceExtensionProperties' : True,
187 'vkEnumerateDeviceExtensionProperties' : True,
188
189 'vkGetInstanceProcAddr' : True,
190 'vkGetDeviceProcAddr' : True,
191
192 # VK_KHR_swapchain v69 requirement
193 'vkBindImageMemory2' : True,
194 'vkBindImageMemory2KHR' : True
195 }
196 if gencom.isFunctionSupported(functionName):
197 if functionName in switchCase:
198 return switchCase[functionName]
199
200 if functionName in gencom.extensionsDict:
201 return isExtensionIntercepted(gencom.extensionsDict[functionName])
202 return False
203
204def needProcHookStub(functionName):
205 if isIntercepted(functionName) and gencom.isDeviceDispatched(functionName):
206 if functionName in gencom.extensionsDict:
207 if not gencom.isExtensionInternal(gencom.extensionsDict[functionName]):
208 return True
209 return False
210
211def defineInitProc(name, f):
212 f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n')
213 f.write ('\n')
214 f.write ("""#define INIT_PROC(required, obj, proc) \\
215 do { \\
216 data.""" + name + """.proc = \\
217 reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
218 if (UNLIKELY(required && !data.""" + name + """.proc)) { \\
219 ALOGE("missing " #obj " proc: vk" #proc); \\
220 success = false; \\
221 } \\
222 } while (0)\n\n""")
223
224def defineInitProcExt(f):
225 f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\
226 do { \\
227 if (extensions[ProcHook::ext]) \\
228 INIT_PROC(required, obj, proc); \\
229 } while (0)\n\n""")
230
231def defineProcHookStub(functionName, f):
232 if needProcHookStub(functionName):
233 ext_name = gencom.extensionsDict[functionName]
234 base_name = functionName[2:]
235 paramList = [''.join(i) for i in gencom.paramDict[functionName]]
236 p0 = gencom.paramDict[functionName][0][1]
237 f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' checked' + base_name + '(' + ', '.join(paramList) + ') {\n')
238 ext_hook = 'ProcHook::' + ext_name[3:]
239
240 f.write (gencom.clang_off_spaces + 'if (GetData(' + p0 + ').hook_extensions[' + ext_hook + ']) {\n')
241 f.write (gencom.clang_off_spaces *2)
242 if gencom.returnTypeDict[functionName] != 'void':
243 f.write ('return ')
244 paramNames = [''.join(i[1]) for i in gencom.paramDict[functionName]]
245 f.write (base_name + '(' + ', '.join(paramNames) + ');\n')
246 f.write (gencom.clang_off_spaces + '} else {\n')
247 f.write (gencom.clang_off_spaces*2 + 'Logger(' + p0 + ').Err(' + p0 + ', \"' + ext_name + ' not enabled. ' + functionName + ' not executed.\");\n')
248 if gencom.returnTypeDict[functionName] != 'void':
249 f.write (gencom.clang_off_spaces*2 + 'return VK_SUCCESS;\n')
250 f.write (gencom.clang_off_spaces + '}\n')
251 f.write ('}\n\n')
252
253def defineGlobalProcHook(functionName, f):
254 base_name = functionName[2:]
255 assert (functionName not in gencom.extensionsDict)
256 f.write (gencom.clang_off_spaces + '{\n' + gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n' + gencom.clang_off_spaces*2)
257 f.write ("""ProcHook::GLOBAL,
258 ProcHook::EXTENSION_CORE,
259 reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
260 nullptr,
261 },\n""")
262
263def defineInstanceProcHook(functionName, f):
264 base_name = functionName[2:]
265 f.write (gencom.clang_off_spaces + '{\n')
266 f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n')
267 f.write (gencom.clang_off_spaces*2 + 'ProcHook::INSTANCE,\n')
268
269 if functionName in gencom.extensionsDict:
270 ext_name = gencom.extensionsDict[functionName]
271 f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n')
272 if gencom.isExtensionInternal(ext_name):
273 f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
274 else:
275 f.write (gencom.clang_off_spaces*2 + 'reinterpret_cast<PFN_vkVoidFunction>(' + base_name + '),\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
276
277 else:
278 f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE,
279 reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
280 nullptr,\n""")
281
282 f.write (gencom.clang_off_spaces + '},\n')
283
284def defineDeviceProcHook(functionName, f):
285 base_name = functionName[2:]
286 f.write (gencom.clang_off_spaces + '{\n')
287 f.write (gencom.clang_off_spaces*2 + '\"' + functionName + '\",\n')
288 f.write (gencom.clang_off_spaces*2 + 'ProcHook::DEVICE,\n')
289
290 if functionName in gencom.extensionsDict:
291 ext_name = gencom.extensionsDict[functionName]
292 f.write (gencom.clang_off_spaces*2 + 'ProcHook::' + ext_name[3:] + ',\n')
293 if gencom.isExtensionInternal(ext_name):
294 f.write (gencom.clang_off_spaces*2 + 'nullptr,\n' + gencom.clang_off_spaces*2 + 'nullptr,\n')
295 else:
296 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')
297
298 else:
299 f.write (gencom.clang_off_spaces*2 + """ProcHook::EXTENSION_CORE,
300 reinterpret_cast<PFN_vkVoidFunction>(""" + base_name + """),
301 nullptr,\n""")
302
303 f.write (gencom.clang_off_spaces + '},\n')
304
305def driver_gencpp():
306 header = """#include <log/log.h>
307#include <string.h>
308
309#include <algorithm>
310
311#include "driver.h"
312
313namespace vulkan {
314namespace driver {
315
316namespace {
317
318// clang-format off\n\n"""
319
320 genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','driver_gen2.cpp')
321
322 with open(genfile, 'w') as f:
323 f.write (gencom.copyright)
324 f.write (gencom.warning)
325 f.write (header)
326
327 for cmds in gencom.allCommandsList:
328 defineProcHookStub(cmds, f)
329 gencom.clang_on(f, 0)
330 f.write ('\n')
331
332 f.write ('const ProcHook g_proc_hooks[] = {\n')
333 gencom.clang_off(f, 1)
334 sortedCommandsList = sorted(gencom.allCommandsList)
335 for cmds in sortedCommandsList:
336 if isIntercepted(cmds):
337 if gencom.isGloballyDispatched(cmds):
338 defineGlobalProcHook(cmds, f)
339 elif gencom.isInstanceDispatched(cmds):
340 defineInstanceProcHook(cmds, f)
341 elif gencom.isDeviceDispatched(cmds):
342 defineDeviceProcHook(cmds, f)
343 gencom.clang_on(f, 1)
344 f.write ('};\n\n} // namespace\n\n')
345
346 f.write ("""const ProcHook* GetProcHook(const char* name) {
347 const auto& begin = g_proc_hooks;
348 const auto& end =
349 g_proc_hooks + sizeof(g_proc_hooks) / sizeof(g_proc_hooks[0]);
350 const auto hook = std::lower_bound(
351 begin, end, name,
352 [](const ProcHook& e, const char* n) { return strcmp(e.name, n) < 0; });
353 return (hook < end && strcmp(hook->name, name) == 0) ? hook : nullptr;
354}\n\n""")
355
356 f.write ('ProcHook::Extension GetProcHookExtension(const char* name) {\n')
357 gencom.clang_off(f, 1)
358 for exts in knownExtensions:
359 f.write (gencom.clang_off_spaces + 'if (strcmp(name, \"' + exts + '\") == 0) return ProcHook::' + exts[3:] + ';\n')
360 gencom.clang_on(f, 1)
361 f.write (gencom.clang_off_spaces + 'return ProcHook::EXTENSION_UNKNOWN;\n')
362 f.write ('}\n\n')
363
364 defineInitProc('driver', f)
365 defineInitProcExt(f)
366
367 f.write ("""bool InitDriverTable(VkInstance instance,
368 PFN_vkGetInstanceProcAddr get_proc,
369 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
370 auto& data = GetData(instance);
371 bool success = true;\n\n""")
372 gencom.clang_off(f, 1)
373 for cmds in gencom.allCommandsList:
374 if isInstanceDriverTableEntry(cmds):
375 gencom.initProc(cmds, f)
376 gencom.clang_on(f, 1)
377 f.write ('\n' + gencom.clang_off_spaces + 'return success;\n')
378 f.write ('}\n\n')
379
380 f.write ("""bool InitDriverTable(VkDevice dev,
381 PFN_vkGetDeviceProcAddr get_proc,
382 const std::bitset<ProcHook::EXTENSION_COUNT>& extensions) {
383 auto& data = GetData(dev);
384 bool success = true;\n\n""")
385 gencom.clang_off(f, 1)
386 for cmds in gencom.allCommandsList:
387 if isDeviceDriverTableEntry(cmds):
388 gencom.initProc(cmds, f)
389 gencom.clang_on(f, 1)
390 f.write ('\n' + gencom.clang_off_spaces + 'return success;\n')
391 f.write ('}\n\n} // namespace driver\n} // namespace vulkan\n\n')
392 gencom.clang_on(f, 0)
393