blob: a0c648cc903efd30beea68ad61560339b878ca3c [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"""
Adithya Srinivasan8dce9d72019-07-11 14:26:04 -070066 genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen.h')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070067 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()
Adithya Srinivasan8dce9d72019-07-11 14:26:04 -070096 gencom.runClangFormat(genfile)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070097
98def defineInitProc(name, f):
99 f.write ('#define UNLIKELY(expr) __builtin_expect((expr), 0)\n')
100 f.write ('\n')
101 f.write ("""#define INIT_PROC(required, obj, proc) \\
102 do { \\
103 data.""" + name + """.proc = \\
104 reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
105 if (UNLIKELY(required && !data.""" + name + """.proc)) { \\
106 ALOGE("missing " #obj " proc: vk" #proc); \\
107 success = false; \\
108 } \\
109 } while (0)\n\n""")
110
111def defineInitProcExt(f):
112 f.write ('// Exported extension functions may be invoked even when their extensions\n')
113 f.write ('// are disabled. Dispatch to stubs when that happens.\n')
114 f.write ("""#define INIT_PROC_EXT(ext, required, obj, proc) \\
115 do { \\
116 if (extensions[driver::ProcHook::ext]) \\
117 INIT_PROC(required, obj, proc); \\
118 else \\
119 data.dispatch.proc = disabled##proc; \\
120 } while (0)\n\n""")
121
122def defineExtensionStub(functionName, f):
123 if functionName in gencom.extensionsDict and gencom.isFunctionExported(functionName):
124 extname = gencom.extensionsDict[functionName]
125 base_name = functionName[2:]
126 pList = gencom.paramDict[functionName]
127 firstParam = pList[0][0] + pList[0][1]
128 tailParams = [x[0][:-1] for x in pList[1:]]
129 tailP = ', '.join(tailParams)
130 f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[functionName] + ' disabled' + base_name + '(' + firstParam + ', ' + tailP + ') {\n')
131 f.write (gencom.clang_off_spaces)
132 f.write ('driver::Logger(' + pList[0][1] + ').Err(' + pList[0][1] + ', \"' + extname + ' not enabled. Exported ' + functionName + ' not executed.\");\n')
133 if gencom.returnTypeDict[functionName] != 'void':
134 f.write(gencom.clang_off_spaces + 'return VK_SUCCESS;\n')
135 f.write ('}\n\n')
136
137def isIntercepted(functionName):
138 if gencom.isFunctionSupported(functionName):
139 if gencom.isGloballyDispatched(functionName):
140 return True
141 elif functionName == 'vkCreateDevice':
142 return True
143 elif functionName == 'vkEnumerateDeviceLayerProperties':
144 return True
145 elif functionName == 'vkEnumerateDeviceExtensionProperties':
146 return True
147 elif functionName == 'vkDestroyInstance':
148 return True
149 elif functionName == 'vkDestroyDevice':
150 return True
151 return False
152
153def interceptInstanceProcAddr(functionName, f):
154 indent = 1
155 f.write (gencom.clang_off_spaces*indent + '// global functions\n' + gencom.clang_off_spaces*indent+ 'if (instance == VK_NULL_HANDLE) {\n')
156 indent = indent + 1
157 for cmds in gencom.allCommandsList:
158 if gencom.isGloballyDispatched(cmds):
159 f.write(gencom.clang_off_spaces*indent + 'if (strcmp(pName, \"' + cmds + '\") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ');\n')
160
161 f.write ('\n')
162 f.write (""" ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \\\"%s\\\") call", pName);
163 return nullptr;
164 }
165
166 static const struct Hook {
167 const char* name;
168 PFN_vkVoidFunction proc;
169 } hooks[] = {\n""")
170 sortedCommandsList = sorted(gencom.allCommandsList)
171 for cmds in sortedCommandsList:
172 if gencom.isFunctionExported(cmds):
173 if gencom.isGloballyDispatched(cmds):
174 f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", nullptr },\n')
175 elif isIntercepted(cmds) or cmds == 'vkGetInstanceProcAddr' or gencom.isDeviceDispatched(cmds):
176 f.write (gencom.clang_off_spaces*2 + '{ \"' + cmds + '\", reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ') },\n')
177 f.write (gencom.clang_off_spaces + """};
178 // clang-format on
179 constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
180 auto hook = std::lower_bound(
181 hooks, hooks + count, pName,
182 [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; });
183 if (hook < hooks + count && strcmp(hook->name, pName) == 0) {
184 if (!hook->proc) {
185 vulkan::driver::Logger(instance).Err(
186 instance, "invalid vkGetInstanceProcAddr(%p, \\\"%s\\\") call",
187 instance, pName);
188 }
189 return hook->proc;
190 }
191 // clang-format off\n\n""")
192
193def interceptDeviceProcAddr(functionName, f):
194 f.write (gencom.clang_off_spaces + """if (device == VK_NULL_HANDLE) {
195 ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call");
196 return nullptr;
197 }\n\n""")
198 f.write (gencom.clang_off_spaces + 'static const char* const known_non_device_names[] = {\n')
199 sortedCommandsList = sorted(gencom.allCommandsList)
200 for cmds in sortedCommandsList:
201 if gencom.isFunctionSupported(cmds):
202 if not gencom.isDeviceDispatched(cmds):
203 f.write(gencom.clang_off_spaces*2 + '\"' + cmds + '\",\n')
204 f.write(gencom.clang_off_spaces + '};\n')
205 f.write(gencom.clang_off_spaces + """// clang-format on
206 constexpr size_t count =
207 sizeof(known_non_device_names) / sizeof(known_non_device_names[0]);
208 if (!pName ||
209 std::binary_search(
210 known_non_device_names, known_non_device_names + count, pName,
211 [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) {
212 vulkan::driver::Logger(device).Err(
213 device, "invalid vkGetDeviceProcAddr(%p, \\\"%s\\\") call", device,
214 (pName) ? pName : "(null)");
215 return nullptr;
216 }
217 // clang-format off\n\n""")
218 for cmds in gencom.allCommandsList:
219 if gencom.isDeviceDispatched(cmds):
220 if isIntercepted(cmds) or cmds == 'vkGetDeviceProcAddr':
221 f.write (gencom.clang_off_spaces + 'if (strcmp(pName, "' + cmds + '") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' + cmds[2:] + ');\n')
222 f.write ('\n')
223
224def apiDispatch(functionName, f):
225 assert not isIntercepted(functionName)
226
227 f.write (gencom.clang_off_spaces)
228 if gencom.returnTypeDict[functionName] != 'void':
229 f.write ('return ')
230
231 paramList = gencom.paramDict[functionName]
232 p0 = paramList[0][1]
233 f.write('GetData(' + p0 + ').dispatch.' + functionName[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n')
234
235
236def api_gencpp():
Adithya Srinivasan8dce9d72019-07-11 14:26:04 -0700237 genfile = os.path.join(os.path.dirname(__file__),'..','libvulkan','api_gen.cpp')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700238 header = """#include <log/log.h>
239#include <string.h>
240
241#include <algorithm>
242
243// to catch mismatches between vulkan.h and this file
244#undef VK_NO_PROTOTYPES
245#include "api.h"
246
247namespace vulkan {
248namespace api {
249
250"""
251 with open(genfile, 'w') as f:
252 f.write (gencom.copyright)
253 f.write (gencom.warning)
254 f.write ("""#include <log/log.h>
255#include <string.h>
256
257#include <algorithm>
258
259// to catch mismatches between vulkan.h and this file
260#undef VK_NO_PROTOTYPES
261#include "api.h"
262
263namespace vulkan {
264namespace api {\n\n""")
265 defineInitProc('dispatch',f)
266 defineInitProcExt(f)
267 f.write ('namespace {\n\n')
268 gencom.clang_off(f,0)
269 f.write ('\n')
270 for cmds in gencom.allCommandsList:
271 defineExtensionStub(cmds,f)
272 gencom.clang_on(f,0)
273 f.write ('\n} // namespace\n\n')
274 f.write ("""bool InitDispatchTable(
275 VkInstance instance,
276 PFN_vkGetInstanceProcAddr get_proc,
277 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
278 auto& data = GetData(instance);
279 bool success = true;\n\n""")
280 gencom.clang_off(f,1)
281 for cmds in gencom.allCommandsList:
282 if gencom.isInstanceDispatchTableEntry(cmds):
283 gencom.initProc(cmds, f)
284 gencom.clang_on(f,1)
285 f.write ('\n')
286 f.write (' return success;\n}\n\n')
287 f.write ("""bool InitDispatchTable(
288 VkDevice dev,
289 PFN_vkGetDeviceProcAddr get_proc,
290 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
291 auto& data = GetData(dev);
292 bool success = true;\n\n""")
293
294 gencom.clang_off(f,1)
295 for cmds in gencom.allCommandsList:
296 if gencom.isDeviceDispatchTableEntry(cmds):
297 gencom.initProc(cmds, f)
298 gencom.clang_on(f,1)
299 f.write ('\n')
300 f.write (' return success;\n}\n\n')
301
302 gencom.clang_off(f,0)
303
304 f.write ('\nnamespace {\n\n')
305 f.write('// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr\n')
306 for cmds in gencom.allCommandsList:
307 if gencom.isFunctionExported(cmds) and not isIntercepted(cmds):
308 paramList = [''.join(i) for i in gencom.paramDict[cmds]]
309 f.write ('VKAPI_ATTR '+gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ');\n')
310
311 f.write ('\n')
312
313 for cmds in gencom.allCommandsList:
314 if gencom.isFunctionExported(cmds) and not isIntercepted(cmds):
315 paramList = [''.join(i) for i in gencom.paramDict[cmds]]
316 f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds[2:] + '(' + ', '.join(paramList) + ') {\n')
317 if cmds == 'vkGetInstanceProcAddr':
318 interceptInstanceProcAddr(cmds, f)
319 elif cmds == 'vkGetDeviceProcAddr':
320 interceptDeviceProcAddr(cmds, f)
321 apiDispatch(cmds, f)
322 f.write('}\n\n')
323 f.write ("""\n} // anonymous namespace
324
325// clang-format on
326
327} // namespace api
328} // namespace vulkan
329
330// clang-format off\n\n""")
331
332 for cmds in gencom.allCommandsList:
333 if gencom.isFunctionExported(cmds):
334 paramList = [''.join(i) for i in gencom.paramDict[cmds]]
335 f.write ('__attribute__((visibility("default")))\n')
336 f.write ('VKAPI_ATTR ' + gencom.returnTypeDict[cmds] + ' ' + cmds + '(' + ', '.join(paramList) + ') {\n')
337 f.write (gencom.clang_off_spaces)
338 if gencom.returnTypeDict[cmds] != 'void':
339 f.write ('return ')
340 paramList = gencom.paramDict[cmds]
341 f.write ('vulkan::api::' + cmds[2:] + '(' + ', '.join(i[1] for i in paramList) + ');\n')
342 f.write ('}\n\n')
343
344 gencom.clang_on(f, 0)
Adithya Srinivasan8dce9d72019-07-11 14:26:04 -0700345 f.close()
346 gencom.runClangFormat(genfile)