blob: 7c390755e1510ddf7f8bfb043f0538cc1019417a [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.
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -070016
17"""Generates the api_gen.h and api_gen.cpp.
18"""
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070019
20import os
21import generator_common as gencom
22
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -070023# Functions intercepted at vulkan::api level.
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070024_INTERCEPTED_COMMANDS = [
25 'vkCreateDevice',
26 'vkDestroyDevice',
27 'vkDestroyInstance',
28 'vkEnumerateDeviceExtensionProperties',
29 'vkEnumerateDeviceLayerProperties',
30]
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070031
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070032
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070033def gen_h():
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -070034 """Generates the api_gen.h file.
35 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070036 genfile = os.path.join(os.path.dirname(__file__),
37 '..', 'libvulkan', 'api_gen.h')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070038
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070039 with open(genfile, 'w') as f:
40 instance_dispatch_table_entries = []
41 device_dispatch_table_entries = []
42
43 for cmd in gencom.command_list:
44 if cmd not in gencom.alias_dict:
45 if gencom.is_instance_dispatch_table_entry(cmd):
46 instance_dispatch_table_entries.append(
47 'PFN_' + cmd + ' ' + gencom.base_name(cmd) + ';')
48 elif gencom.is_device_dispatch_table_entry(cmd):
49 device_dispatch_table_entries.append(
50 'PFN_' + cmd + ' ' + gencom.base_name(cmd) + ';')
51
52 f.write(gencom.copyright_and_warning(2016))
53
54 f.write("""\
55#ifndef LIBVULKAN_API_GEN_H
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070056#define LIBVULKAN_API_GEN_H
57
58#include <vulkan/vulkan.h>
59
60#include <bitset>
61
62#include "driver_gen.h"
63
64namespace vulkan {
65namespace api {
66
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070067struct InstanceDispatchTable {
68 // clang-format off\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070069
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070070 for entry in instance_dispatch_table_entries:
71 f.write(gencom.indent(1) + entry + '\n')
72
73 f.write("""\
74 // clang-format on
75};
76
77struct DeviceDispatchTable {
78 // clang-format off\n""")
79
80 for entry in device_dispatch_table_entries:
81 f.write(gencom.indent(1) + entry + '\n')
82
83 f.write("""\
84 // clang-format on
85};
86
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070087bool InitDispatchTable(
88 VkInstance instance,
89 PFN_vkGetInstanceProcAddr get_proc,
90 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions);
91bool InitDispatchTable(
92 VkDevice dev,
93 PFN_vkGetDeviceProcAddr get_proc,
94 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions);
95
96} // namespace api
97} // namespace vulkan
98
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070099#endif // LIBVULKAN_API_GEN_H\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700100
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700101 f.close()
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700102 gencom.run_clang_format(genfile)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700103
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700104
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700105def _define_extension_stub(cmd, f):
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700106 """Emits a stub for an exported extension function.
107
108 Args:
109 cmd: Vulkan function name.
110 f: Output file handle.
111 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700112 if (cmd in gencom.extension_dict and gencom.is_function_exported(cmd)):
113 ext_name = gencom.extension_dict[cmd]
114 ret = gencom.return_type_dict[cmd]
115 params = gencom.param_dict[cmd]
116 first_param = params[0][0] + params[0][1]
117 tail_params = ', '.join([i[0][:-1] for i in params[1:]])
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700118
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700119 f.write('VKAPI_ATTR ' + ret + ' disabled' + gencom.base_name(cmd) +
120 '(' + first_param + ', ' + tail_params + ') {\n')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700121
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700122 f.write(gencom.indent(1) + 'driver::Logger(' + params[0][1] +
123 ').Err(' + params[0][1] + ', \"' + ext_name +
124 ' not enabled. Exported ' + cmd + ' not executed.\");\n')
125
126 if gencom.return_type_dict[cmd] != 'void':
127 f.write(gencom.indent(1) + 'return VK_SUCCESS;\n')
128
129 f.write('}\n\n')
130
131
132def _is_intercepted(cmd):
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700133 """Returns true if a function is intercepted by vulkan::api.
134
135 Args:
136 cmd: Vulkan function name.
137 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700138 if gencom.is_function_supported(cmd):
139 if gencom.is_globally_dispatched(cmd) or cmd in _INTERCEPTED_COMMANDS:
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700140 return True
141 return False
142
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700143
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700144def _intercept_instance_proc_addr(f):
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700145 """Emits code for vkGetInstanceProcAddr for function interception.
146
147 Args:
148 f: Output file handle.
149 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700150 f.write("""\
151 // global functions
152 if (instance == VK_NULL_HANDLE) {\n""")
153
154 for cmd in gencom.command_list:
155 if gencom.is_globally_dispatched(cmd):
156 f.write(gencom.indent(2) +
157 'if (strcmp(pName, \"' + cmd +
158 '\") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' +
159 gencom.base_name(cmd) + ');\n')
160
161 f.write("""
162 ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \\\"%s\\\") call", pName);
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700163 return nullptr;
164 }
165
166 static const struct Hook {
167 const char* name;
168 PFN_vkVoidFunction proc;
169 } hooks[] = {\n""")
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700170
171 sorted_command_list = sorted(gencom.command_list)
172 for cmd in sorted_command_list:
173 if gencom.is_function_exported(cmd):
174 if gencom.is_globally_dispatched(cmd):
175 f.write(gencom.indent(2) + '{ \"' + cmd + '\", nullptr },\n')
176 elif (_is_intercepted(cmd) or
177 cmd == 'vkGetInstanceProcAddr' or
178 gencom.is_device_dispatched(cmd)):
179 f.write(gencom.indent(2) + '{ \"' + cmd +
180 '\", reinterpret_cast<PFN_vkVoidFunction>(' +
181 gencom.base_name(cmd) + ') },\n')
182
183 f.write("""\
184 };
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700185 // clang-format on
186 constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
187 auto hook = std::lower_bound(
188 hooks, hooks + count, pName,
189 [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; });
190 if (hook < hooks + count && strcmp(hook->name, pName) == 0) {
191 if (!hook->proc) {
192 vulkan::driver::Logger(instance).Err(
193 instance, "invalid vkGetInstanceProcAddr(%p, \\\"%s\\\") call",
194 instance, pName);
195 }
196 return hook->proc;
197 }
198 // clang-format off\n\n""")
199
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700200
201def _intercept_device_proc_addr(f):
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700202 """Emits code for vkGetDeviceProcAddr for function interception.
203
204 Args:
205 f: Output file handle.
206 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700207 f.write("""\
208 if (device == VK_NULL_HANDLE) {
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700209 ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call");
210 return nullptr;
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700211 }
212
213 static const char* const known_non_device_names[] = {\n""")
214
215 sorted_command_list = sorted(gencom.command_list)
216 for cmd in sorted_command_list:
217 if gencom.is_function_supported(cmd):
218 if not gencom.is_device_dispatched(cmd):
219 f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
220
221 f.write("""\
222 };
223 // clang-format on
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700224 constexpr size_t count =
225 sizeof(known_non_device_names) / sizeof(known_non_device_names[0]);
226 if (!pName ||
227 std::binary_search(
228 known_non_device_names, known_non_device_names + count, pName,
229 [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) {
230 vulkan::driver::Logger(device).Err(
231 device, "invalid vkGetDeviceProcAddr(%p, \\\"%s\\\") call", device,
232 (pName) ? pName : "(null)");
233 return nullptr;
234 }
235 // clang-format off\n\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700236
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700237 for cmd in gencom.command_list:
238 if gencom.is_device_dispatched(cmd):
239 if _is_intercepted(cmd) or cmd == 'vkGetDeviceProcAddr':
240 f.write(gencom.indent(1) + 'if (strcmp(pName, "' + cmd +
241 '") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' +
242 gencom.base_name(cmd) + ');\n')
243 f.write('\n')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700244
245
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700246def _api_dispatch(cmd, f):
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700247 """Emits code to dispatch a function.
248
249 Args:
250 cmd: Vulkan function name.
251 f: Output file handle.
252 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700253 assert not _is_intercepted(cmd)
254
255 f.write(gencom.indent(1))
256 if gencom.return_type_dict[cmd] != 'void':
257 f.write('return ')
258
259 param_list = gencom.param_dict[cmd]
260 handle = param_list[0][1]
261 f.write('GetData(' + handle + ').dispatch.' + gencom.base_name(cmd) +
262 '(' + ', '.join(i[1] for i in param_list) + ');\n')
263
264
265def gen_cpp():
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700266 """Generates the api_gen.cpp file.
267 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700268 genfile = os.path.join(os.path.dirname(__file__),
269 '..', 'libvulkan', 'api_gen.cpp')
270
271 with open(genfile, 'w') as f:
272 f.write(gencom.copyright_and_warning(2016))
273
274 f.write("""\
275#include <log/log.h>
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700276#include <string.h>
277
278#include <algorithm>
279
280// to catch mismatches between vulkan.h and this file
281#undef VK_NO_PROTOTYPES
282#include "api.h"
283
284namespace vulkan {
285namespace api {
286
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700287#define UNLIKELY(expr) __builtin_expect((expr), 0)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700288
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700289#define INIT_PROC(required, obj, proc) \\
290 do { \\
291 data.dispatch.proc = \\
292 reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
293 if (UNLIKELY(required && !data.dispatch.proc)) { \\
294 ALOGE("missing " #obj " proc: vk" #proc); \\
295 success = false; \\
296 } \\
297 } while (0)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700298
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700299// Exported extension functions may be invoked even when their extensions
300// are disabled. Dispatch to stubs when that happens.
301#define INIT_PROC_EXT(ext, required, obj, proc) \\
302 do { \\
303 if (extensions[driver::ProcHook::ext]) \\
304 INIT_PROC(required, obj, proc); \\
305 else \\
306 data.dispatch.proc = disabled##proc; \\
307 } while (0)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700308
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700309namespace {
310
311// clang-format off\n\n""")
312
313 for cmd in gencom.command_list:
314 _define_extension_stub(cmd, f)
315
316 f.write("""\
317// clang-format on
318
319} // namespace
320
321bool InitDispatchTable(
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700322 VkInstance instance,
323 PFN_vkGetInstanceProcAddr get_proc,
324 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
325 auto& data = GetData(instance);
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700326 bool success = true;
327
328 // clang-format off\n""")
329
330 for cmd in gencom.command_list:
331 if gencom.is_instance_dispatch_table_entry(cmd):
332 gencom.init_proc(cmd, f)
333
334 f.write("""\
335 // clang-format on
336
337 return success;
338}
339
340bool InitDispatchTable(
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700341 VkDevice dev,
342 PFN_vkGetDeviceProcAddr get_proc,
343 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
344 auto& data = GetData(dev);
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700345 bool success = true;
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700346
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700347 // clang-format off\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700348
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700349 for cmd in gencom.command_list:
350 if gencom.is_device_dispatch_table_entry(cmd):
351 gencom.init_proc(cmd, f)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700352
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700353 f.write("""\
354 // clang-format on
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700355
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700356 return success;
357}
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700358
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700359// clang-format off
360
361namespace {
362
363// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr
364""")
365
366 for cmd in gencom.command_list:
367 if gencom.is_function_exported(cmd) and not _is_intercepted(cmd):
368 param_list = [''.join(i) for i in gencom.param_dict[cmd]]
369 f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
370 gencom.base_name(cmd) + '(' + ', '.join(param_list) + ');\n')
371
372 f.write('\n')
373 for cmd in gencom.command_list:
374 if gencom.is_function_exported(cmd) and not _is_intercepted(cmd):
375 param_list = [''.join(i) for i in gencom.param_dict[cmd]]
376 f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
377 gencom.base_name(cmd) + '(' + ', '.join(param_list) + ') {\n')
378 if cmd == 'vkGetInstanceProcAddr':
379 _intercept_instance_proc_addr(f)
380 elif cmd == 'vkGetDeviceProcAddr':
381 _intercept_device_proc_addr(f)
382 _api_dispatch(cmd, f)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700383 f.write('}\n\n')
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700384
385 f.write("""
386} // anonymous namespace
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700387
388// clang-format on
389
390} // namespace api
391} // namespace vulkan
392
393// clang-format off\n\n""")
394
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700395 for cmd in gencom.command_list:
396 if gencom.is_function_exported(cmd):
397 param_list = [''.join(i) for i in gencom.param_dict[cmd]]
398 f.write('__attribute__((visibility("default")))\n')
399 f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
400 cmd + '(' + ', '.join(param_list) + ') {\n')
401 f.write(gencom.indent(1))
402 if gencom.return_type_dict[cmd] != 'void':
403 f.write('return ')
404 param_list = gencom.param_dict[cmd]
405 f.write('vulkan::api::' + gencom.base_name(cmd) +
406 '(' + ', '.join(i[1] for i in param_list) + ');\n}\n\n')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700407
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700408 f.write('// clang-format on\n')
Adithya Srinivasan8dce9d72019-07-11 14:26:04 -0700409 f.close()
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700410 gencom.run_clang_format(genfile)