blob: 05dc9957b0e29742d28d3709594798858aeb997c [file] [log] [blame]
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -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 required for generating the
18# vulkan api framework directly from the vulkan registry (vk.xml)
19
20import os
21import generator_common as gencom
22
23def isInstanceDispatchTableEntry(functionName):
24 if functionName == 'vkEnumerateDeviceLayerProperties': # deprecated, unused internally - @dbd33bc
25 return False
26 if gencom.gencom.isFunctionExported(functionName) and gencom.isInstanceDispatched(functionName):
27 return True
28 return False
29
30def isDeviceDispatchTableEntry(functionName):
31 if gencom.gencom.isFunctionExported(functionName) and gencom.gencom.isDeviceDispatched(functionName):
32 return True
33 return False
34
35def api_genh():
36
37 header = """#ifndef LIBVULKAN_API_GEN_H
38#define LIBVULKAN_API_GEN_H
39
40#include <vulkan/vulkan.h>
41
42#include <bitset>
43
44#include "driver_gen.h"
45
46namespace vulkan {
47namespace api {
48
49"""
50
51 tail = """
52bool InitDispatchTable(
53 VkInstance instance,
54 PFN_vkGetInstanceProcAddr get_proc,
55 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions);
56bool InitDispatchTable(
57 VkDevice dev,
58 PFN_vkGetDeviceProcAddr get_proc,
59 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions);
60
61} // namespace api
62} // namespace vulkan
63
64#endif // LIBVULKAN_API_GEN_H
65"""
66 genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen2.h')
67 with open(genfile, 'w') as f:
68 instanceDispatchTableEntries = []
69 deviceDispatchTableEntries = []
70 for commands in gencom.allCommandsList:
71 if commands not in gencom.aliasDict:
72 if gencom.isInstanceDispatchTableEntry(commands):
73 instanceDispatchTableEntries.append('PFN_'+commands+' '+commands[2:]+';')
74 elif gencom.isDeviceDispatchTableEntry(commands):
75 deviceDispatchTableEntries.append('PFN_'+commands+' '+commands[2:]+';')
76
77 f.write (gencom.copyright)
78 f.write (gencom.warning)
79 f.write (header)
80 f.write ('struct InstanceDispatchTable {\n')
81 gencom.clang_off(f,1)
82 for functions in instanceDispatchTableEntries:
83 f.write(gencom.clang_off_spaces + functions + '\n')
84 gencom.clang_on(f,1)
85 f.write ('};\n\n')
86
87 f.write ('struct DeviceDispatchTable {\n')
88 gencom.clang_off(f,1)
89 for functions in deviceDispatchTableEntries:
90 f.write(gencom.clang_off_spaces + functions + '\n')
91 gencom.clang_on(f,1)
92 f.write ('};\n')
93
94 f.write (tail)
95 f.close()
96
97def defineInitProc(name, f):
98 f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n')
99 f.write ('\n')
100 f.write ("""#define INIT_PROC(required, obj, proc) \\
101 do { \\
102 data.""" + name + """.proc = \\
103 reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
104 if (UNLIKELY(required && !data.""" + name + """.proc)) { \\
105 ALOGE("missing " #obj " proc: vk" #proc); \\
106 success = false; \\
107 } \\
108 } while (0)\n\n""")
109
110def defineInitProcExt(f):
111 f.write ('// Exported extension functions may be invoked even when their extensions\n')
112 f.write ('// are disabled. Dispatch to stubs when that happens.\n')
113 f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\
114 do { \\
115 if (extensions[driver::ProcHook::ext]) \\
116 INIT_PROC(required, obj, proc); \\
117 else \\
118 data.dispatch.proc = disabled##proc; \\
119 } while (0)\n\n""")
120
121def defineExtensionStub(functionName, f):
122 if functionName in gencom.extensionsDict and gencom.isFunctionExported(functionName):
123 extname = gencom.extensionsDict[functionName]
124 base_name = functionName[2:]
125 pList = gencom.paramDict[functionName]
126 firstParam = pList[0][0] + pList[0][1]
127 tailParams = [x[0][:-1] for x in pList[1:]]
128 tailP = ', '.join(tailParams)
129 f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' disabled' + base_name + '(' + firstParam + ', ' + tailP + ') {\n')
130 f.write (gencom.clang_off_spaces)
131 f.write ('driver::Logger(' + pList[0][1] + ').Err(' + pList[0][1] + ', \"' + extname + ' not enabled. Exported ' + functionName + ' not executed.\");\n')
132 if gencom.returnTypeDict[functionName] != 'void':
133 f.write(gencom.clang_off_spaces + 'return VK_SUCCESS;\n')
134 f.write ('}\n\n')
135
136def isIntercepted(functionName):
137 if gencom.isFunctionSupported(functionName):
138 if gencom.isGloballyDispatched(functionName):
139 return True
140 elif functionName == 'vkCreateDevice':
141 return True
142 elif functionName == 'vkEnumerateDeviceLayerProperties':
143 return True
144 elif functionName == 'vkEnumerateDeviceExtensionProperties':
145 return True
146 elif functionName == 'vkDestroyInstance':
147 return True
148 elif functionName == 'vkDestroyDevice':
149 return True
150 return False
151
152def interceptInstanceProcAddr(functionName, f):
153 indent = 1
154 f.write (gencom.clang_off_spaces*indent + '// global functions\n' + gencom.clang_off_spaces*indent+ 'if (instance == VK_NULL_HANDLE) {\n')
155 indent = indent + 1
156 for cmds in gencom.allCommandsList:
157 if gencom.isGloballyDispatched(cmds):
158 f.write(gencom.clang_off_spaces*indent + 'if (strcmp(pName, \"' + cmds + '\") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ');\n')
159
160 f.write ('\n')
161 f.write (""" ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \\\"%s\\\") call", pName);
162 return nullptr;
163 }
164
165 static const struct Hook {
166 const char* name;
167 PFN_vkVoidFunction proc;
168 } hooks[] = {\n""")
169 sortedCommandsList = sorted(gencom.allCommandsList)
170 for cmds in sortedCommandsList:
171 if gencom.isFunctionExported(cmds):
172 if gencom.isGloballyDispatched(cmds):
173 f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", nullptr },\n')
174 elif isIntercepted(cmds) or cmds == 'vkGetInstanceProcAddr' or gencom.isDeviceDispatched(cmds):
175 f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ') },\n')
176 f.write (gencom.clang_off_spaces + """};
177 // clang-format on
178 constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
179 auto hook = std::lower_bound(
180 hooks, hooks + count, pName,
181 [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; });
182 if (hook < hooks + count && strcmp(hook->name, pName) == 0) {
183 if (!hook->proc) {
184 vulkan::driver::Logger(instance).Err(
185 instance, "invalid vkGetInstanceProcAddr(%p, \\\"%s\\\") call",
186 instance, pName);
187 }
188 return hook->proc;
189 }
190 // clang-format off\n\n""")
191
192def interceptDeviceProcAddr(functionName, f):
193 f.write (gencom.clang_off_spaces + """if (device == VK_NULL_HANDLE) {
194 ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call");
195 return nullptr;
196 }\n\n""")
197 f.write (gencom.clang_off_spaces + 'static const char* const known_non_device_names[] = {\n')
198 sortedCommandsList = sorted(gencom.allCommandsList)
199 for cmds in sortedCommandsList:
200 if gencom.isFunctionSupported(cmds):
201 if not gencom.isDeviceDispatched(cmds):
202 f.write(gencom.clang_off_spaces*2 + '\"' + cmds + '\",\n')
203 f.write(gencom.clang_off_spaces + '};\n')
204 f.write(gencom.clang_off_spaces + """// clang-format on
205 constexpr size_t count =
206 sizeof(known_non_device_names) / sizeof(known_non_device_names[0]);
207 if (!pName ||
208 std::binary_search(
209 known_non_device_names, known_non_device_names + count, pName,
210 [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) {
211 vulkan::driver::Logger(device).Err(
212 device, "invalid vkGetDeviceProcAddr(%p, \\\"%s\\\") call", device,
213 (pName) ? pName : "(null)");
214 return nullptr;
215 }
216 // clang-format off\n\n""")
217 for cmds in gencom.allCommandsList:
218 if gencom.isDeviceDispatched(cmds):
219 if isIntercepted(cmds) or cmds == 'vkGetDeviceProcAddr':
220 f.write (gencom.clang_off_spaces + 'if (strcmp(pName, "' + cmds + '") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ');\n')
221 f.write ('\n')
222
223def apiDispatch(functionName, f):
224 assert not isIntercepted(functionName)
225
226 f.write (gencom.clang_off_spaces)
227 if gencom.returnTypeDict[functionName] != 'void':
228 f.write ('return ')
229
230 paramList = gencom.paramDict[functionName]
231 p0 = paramList[0][1]
232 f.write('GetData(' + p0 + ').dispatch.' + functionName[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n')
233
234
235def api_gencpp():
236 genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen2.cpp')
237 header = """#include <log/log.h>
238#include <string.h>
239
240#include <algorithm>
241
242// to catch mismatches between vulkan.h and this file
243#undef VK_NO_PROTOTYPES
244#include "api.h"
245
246namespace vulkan {
247namespace api {
248
249"""
250 with open(genfile, 'w') as f:
251 f.write (gencom.copyright)
252 f.write (gencom.warning)
253 f.write ("""#include <log/log.h>
254#include <string.h>
255
256#include <algorithm>
257
258// to catch mismatches between vulkan.h and this file
259#undef VK_NO_PROTOTYPES
260#include "api.h"
261
262namespace vulkan {
263namespace api {\n\n""")
264 defineInitProc('dispatch',f)
265 defineInitProcExt(f)
266 f.write ('namespace {\n\n')
267 gencom.clang_off(f,0)
268 f.write ('\n')
269 for cmds in gencom.allCommandsList:
270 defineExtensionStub(cmds,f)
271 gencom.clang_on(f,0)
272 f.write ('\n} // namespace\n\n')
273 f.write ("""bool InitDispatchTable(
274 VkInstance instance,
275 PFN_vkGetInstanceProcAddr get_proc,
276 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
277 auto& data = GetData(instance);
278 bool success = true;\n\n""")
279 gencom.clang_off(f,1)
280 for cmds in gencom.allCommandsList:
281 if gencom.isInstanceDispatchTableEntry(cmds):
282 gencom.initProc(cmds, f)
283 gencom.clang_on(f,1)
284 f.write ('\n')
285 f.write (' return success;\n}\n\n')
286 f.write ("""bool InitDispatchTable(
287 VkDevice dev,
288 PFN_vkGetDeviceProcAddr get_proc,
289 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
290 auto& data = GetData(dev);
291 bool success = true;\n\n""")
292
293 gencom.clang_off(f,1)
294 for cmds in gencom.allCommandsList:
295 if gencom.isDeviceDispatchTableEntry(cmds):
296 gencom.initProc(cmds, f)
297 gencom.clang_on(f,1)
298 f.write ('\n')
299 f.write (' return success;\n}\n\n')
300
301 gencom.clang_off(f,0)
302
303 f.write ('\nnamespace {\n\n')
304 f.write('// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr\n')
305 for cmds in gencom.allCommandsList:
306 if gencom.isFunctionExported(cmds) and not isIntercepted(cmds):
307 paramList = [''.join(i) for i in gencom.paramDict[cmds]]
308 f.write ('VKAPI_ATTR '+gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ');\n')
309
310 f.write ('\n')
311
312 for cmds in gencom.allCommandsList:
313 if gencom.isFunctionExported(cmds) and not isIntercepted(cmds):
314 paramList = [''.join(i) for i in gencom.paramDict[cmds]]
315 f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ') {\n')
316 if cmds == 'vkGetInstanceProcAddr':
317 interceptInstanceProcAddr(cmds, f)
318 elif cmds == 'vkGetDeviceProcAddr':
319 interceptDeviceProcAddr(cmds, f)
320 apiDispatch(cmds, f)
321 f.write('}\n\n')
322 f.write ("""\n} // anonymous namespace
323
324// clang-format on
325
326} // namespace api
327} // namespace vulkan
328
329// clang-format off\n\n""")
330
331 for cmds in gencom.allCommandsList:
332 if gencom.isFunctionExported(cmds):
333 paramList = [''.join(i) for i in gencom.paramDict[cmds]]
334 f.write ('__attribute__((visibility("default")))\n')
335 f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds + '(' + ', '.join(paramList) + ') {\n')
336 f.write (gencom.clang_off_spaces)
337 if gencom.returnTypeDict[cmds] != 'void':
338 f.write ('return ')
339 paramList = gencom.paramDict[cmds]
340 f.write ('vulkan::api::' + cmds[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n')
341 f.write ('}\n\n')
342
343 gencom.clang_on(f, 0)
344