blob: d1fff421256b04497248f0fd8fc6d474f5f999a7 [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
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070023_INTERCEPTED_COMMANDS = [
24 'vkCreateDevice',
25 'vkDestroyDevice',
26 'vkDestroyInstance',
27 'vkEnumerateDeviceExtensionProperties',
28 'vkEnumerateDeviceLayerProperties',
29]
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070030
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070031
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070032def gen_h():
33 genfile = os.path.join(os.path.dirname(__file__),
34 '..', 'libvulkan', 'api_gen.h')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070035
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070036 with open(genfile, 'w') as f:
37 instance_dispatch_table_entries = []
38 device_dispatch_table_entries = []
39
40 for cmd in gencom.command_list:
41 if cmd not in gencom.alias_dict:
42 if gencom.is_instance_dispatch_table_entry(cmd):
43 instance_dispatch_table_entries.append(
44 'PFN_' + cmd + ' ' + gencom.base_name(cmd) + ';')
45 elif gencom.is_device_dispatch_table_entry(cmd):
46 device_dispatch_table_entries.append(
47 'PFN_' + cmd + ' ' + gencom.base_name(cmd) + ';')
48
49 f.write(gencom.copyright_and_warning(2016))
50
51 f.write("""\
52#ifndef LIBVULKAN_API_GEN_H
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070053#define LIBVULKAN_API_GEN_H
54
55#include <vulkan/vulkan.h>
56
57#include <bitset>
58
59#include "driver_gen.h"
60
61namespace vulkan {
62namespace api {
63
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070064struct InstanceDispatchTable {
65 // clang-format off\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070066
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070067 for entry in instance_dispatch_table_entries:
68 f.write(gencom.indent(1) + entry + '\n')
69
70 f.write("""\
71 // clang-format on
72};
73
74struct DeviceDispatchTable {
75 // clang-format off\n""")
76
77 for entry in device_dispatch_table_entries:
78 f.write(gencom.indent(1) + entry + '\n')
79
80 f.write("""\
81 // clang-format on
82};
83
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070084bool InitDispatchTable(
85 VkInstance instance,
86 PFN_vkGetInstanceProcAddr get_proc,
87 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions);
88bool InitDispatchTable(
89 VkDevice dev,
90 PFN_vkGetDeviceProcAddr get_proc,
91 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions);
92
93} // namespace api
94} // namespace vulkan
95
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070096#endif // LIBVULKAN_API_GEN_H\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070097
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070098 f.close()
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070099 gencom.run_clang_format(genfile)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700100
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700101
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700102def _define_extension_stub(cmd, f):
103 if (cmd in gencom.extension_dict and gencom.is_function_exported(cmd)):
104 ext_name = gencom.extension_dict[cmd]
105 ret = gencom.return_type_dict[cmd]
106 params = gencom.param_dict[cmd]
107 first_param = params[0][0] + params[0][1]
108 tail_params = ', '.join([i[0][:-1] for i in params[1:]])
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700109
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700110 f.write('VKAPI_ATTR ' + ret + ' disabled' + gencom.base_name(cmd) +
111 '(' + first_param + ', ' + tail_params + ') {\n')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700112
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700113 f.write(gencom.indent(1) + 'driver::Logger(' + params[0][1] +
114 ').Err(' + params[0][1] + ', \"' + ext_name +
115 ' not enabled. Exported ' + cmd + ' not executed.\");\n')
116
117 if gencom.return_type_dict[cmd] != 'void':
118 f.write(gencom.indent(1) + 'return VK_SUCCESS;\n')
119
120 f.write('}\n\n')
121
122
123def _is_intercepted(cmd):
124 if gencom.is_function_supported(cmd):
125 if gencom.is_globally_dispatched(cmd) or cmd in _INTERCEPTED_COMMANDS:
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700126 return True
127 return False
128
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700129
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700130def _intercept_instance_proc_addr(f):
131 f.write("""\
132 // global functions
133 if (instance == VK_NULL_HANDLE) {\n""")
134
135 for cmd in gencom.command_list:
136 if gencom.is_globally_dispatched(cmd):
137 f.write(gencom.indent(2) +
138 'if (strcmp(pName, \"' + cmd +
139 '\") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' +
140 gencom.base_name(cmd) + ');\n')
141
142 f.write("""
143 ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \\\"%s\\\") call", pName);
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700144 return nullptr;
145 }
146
147 static const struct Hook {
148 const char* name;
149 PFN_vkVoidFunction proc;
150 } hooks[] = {\n""")
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700151
152 sorted_command_list = sorted(gencom.command_list)
153 for cmd in sorted_command_list:
154 if gencom.is_function_exported(cmd):
155 if gencom.is_globally_dispatched(cmd):
156 f.write(gencom.indent(2) + '{ \"' + cmd + '\", nullptr },\n')
157 elif (_is_intercepted(cmd) or
158 cmd == 'vkGetInstanceProcAddr' or
159 gencom.is_device_dispatched(cmd)):
160 f.write(gencom.indent(2) + '{ \"' + cmd +
161 '\", reinterpret_cast<PFN_vkVoidFunction>(' +
162 gencom.base_name(cmd) + ') },\n')
163
164 f.write("""\
165 };
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700166 // clang-format on
167 constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
168 auto hook = std::lower_bound(
169 hooks, hooks + count, pName,
170 [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; });
171 if (hook < hooks + count && strcmp(hook->name, pName) == 0) {
172 if (!hook->proc) {
173 vulkan::driver::Logger(instance).Err(
174 instance, "invalid vkGetInstanceProcAddr(%p, \\\"%s\\\") call",
175 instance, pName);
176 }
177 return hook->proc;
178 }
179 // clang-format off\n\n""")
180
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700181
182def _intercept_device_proc_addr(f):
183 f.write("""\
184 if (device == VK_NULL_HANDLE) {
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700185 ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call");
186 return nullptr;
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700187 }
188
189 static const char* const known_non_device_names[] = {\n""")
190
191 sorted_command_list = sorted(gencom.command_list)
192 for cmd in sorted_command_list:
193 if gencom.is_function_supported(cmd):
194 if not gencom.is_device_dispatched(cmd):
195 f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
196
197 f.write("""\
198 };
199 // clang-format on
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700200 constexpr size_t count =
201 sizeof(known_non_device_names) / sizeof(known_non_device_names[0]);
202 if (!pName ||
203 std::binary_search(
204 known_non_device_names, known_non_device_names + count, pName,
205 [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) {
206 vulkan::driver::Logger(device).Err(
207 device, "invalid vkGetDeviceProcAddr(%p, \\\"%s\\\") call", device,
208 (pName) ? pName : "(null)");
209 return nullptr;
210 }
211 // clang-format off\n\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700212
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700213 for cmd in gencom.command_list:
214 if gencom.is_device_dispatched(cmd):
215 if _is_intercepted(cmd) or cmd == 'vkGetDeviceProcAddr':
216 f.write(gencom.indent(1) + 'if (strcmp(pName, "' + cmd +
217 '") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' +
218 gencom.base_name(cmd) + ');\n')
219 f.write('\n')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700220
221
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700222def _api_dispatch(cmd, f):
223 assert not _is_intercepted(cmd)
224
225 f.write(gencom.indent(1))
226 if gencom.return_type_dict[cmd] != 'void':
227 f.write('return ')
228
229 param_list = gencom.param_dict[cmd]
230 handle = param_list[0][1]
231 f.write('GetData(' + handle + ').dispatch.' + gencom.base_name(cmd) +
232 '(' + ', '.join(i[1] for i in param_list) + ');\n')
233
234
235def gen_cpp():
236 genfile = os.path.join(os.path.dirname(__file__),
237 '..', 'libvulkan', 'api_gen.cpp')
238
239 with open(genfile, 'w') as f:
240 f.write(gencom.copyright_and_warning(2016))
241
242 f.write("""\
243#include <log/log.h>
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700244#include <string.h>
245
246#include <algorithm>
247
248// to catch mismatches between vulkan.h and this file
249#undef VK_NO_PROTOTYPES
250#include "api.h"
251
252namespace vulkan {
253namespace api {
254
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700255#define UNLIKELY(expr) __builtin_expect((expr), 0)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700256
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700257#define INIT_PROC(required, obj, proc) \\
258 do { \\
259 data.dispatch.proc = \\
260 reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
261 if (UNLIKELY(required && !data.dispatch.proc)) { \\
262 ALOGE("missing " #obj " proc: vk" #proc); \\
263 success = false; \\
264 } \\
265 } while (0)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700266
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700267// Exported extension functions may be invoked even when their extensions
268// are disabled. Dispatch to stubs when that happens.
269#define INIT_PROC_EXT(ext, required, obj, proc) \\
270 do { \\
271 if (extensions[driver::ProcHook::ext]) \\
272 INIT_PROC(required, obj, proc); \\
273 else \\
274 data.dispatch.proc = disabled##proc; \\
275 } while (0)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700276
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700277namespace {
278
279// clang-format off\n\n""")
280
281 for cmd in gencom.command_list:
282 _define_extension_stub(cmd, f)
283
284 f.write("""\
285// clang-format on
286
287} // namespace
288
289bool InitDispatchTable(
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700290 VkInstance instance,
291 PFN_vkGetInstanceProcAddr get_proc,
292 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
293 auto& data = GetData(instance);
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700294 bool success = true;
295
296 // clang-format off\n""")
297
298 for cmd in gencom.command_list:
299 if gencom.is_instance_dispatch_table_entry(cmd):
300 gencom.init_proc(cmd, f)
301
302 f.write("""\
303 // clang-format on
304
305 return success;
306}
307
308bool InitDispatchTable(
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700309 VkDevice dev,
310 PFN_vkGetDeviceProcAddr get_proc,
311 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
312 auto& data = GetData(dev);
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700313 bool success = true;
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700314
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700315 // clang-format off\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700316
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700317 for cmd in gencom.command_list:
318 if gencom.is_device_dispatch_table_entry(cmd):
319 gencom.init_proc(cmd, f)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700320
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700321 f.write("""\
322 // clang-format on
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700323
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700324 return success;
325}
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700326
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700327// clang-format off
328
329namespace {
330
331// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr
332""")
333
334 for cmd in gencom.command_list:
335 if gencom.is_function_exported(cmd) and not _is_intercepted(cmd):
336 param_list = [''.join(i) for i in gencom.param_dict[cmd]]
337 f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
338 gencom.base_name(cmd) + '(' + ', '.join(param_list) + ');\n')
339
340 f.write('\n')
341 for cmd in gencom.command_list:
342 if gencom.is_function_exported(cmd) and not _is_intercepted(cmd):
343 param_list = [''.join(i) for i in gencom.param_dict[cmd]]
344 f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
345 gencom.base_name(cmd) + '(' + ', '.join(param_list) + ') {\n')
346 if cmd == 'vkGetInstanceProcAddr':
347 _intercept_instance_proc_addr(f)
348 elif cmd == 'vkGetDeviceProcAddr':
349 _intercept_device_proc_addr(f)
350 _api_dispatch(cmd, f)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700351 f.write('}\n\n')
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700352
353 f.write("""
354} // anonymous namespace
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700355
356// clang-format on
357
358} // namespace api
359} // namespace vulkan
360
361// clang-format off\n\n""")
362
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700363 for cmd in gencom.command_list:
364 if gencom.is_function_exported(cmd):
365 param_list = [''.join(i) for i in gencom.param_dict[cmd]]
366 f.write('__attribute__((visibility("default")))\n')
367 f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
368 cmd + '(' + ', '.join(param_list) + ') {\n')
369 f.write(gencom.indent(1))
370 if gencom.return_type_dict[cmd] != 'void':
371 f.write('return ')
372 param_list = gencom.param_dict[cmd]
373 f.write('vulkan::api::' + gencom.base_name(cmd) +
374 '(' + ', '.join(i[1] for i in param_list) + ');\n}\n\n')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700375
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700376 f.write('// clang-format on\n')
Adithya Srinivasan8dce9d72019-07-11 14:26:04 -0700377 f.close()
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700378 gencom.run_clang_format(genfile)