blob: 001af208a81508d9d1fc8fdba64a4841e0f6facf [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
Tom Murphyea321842024-06-14 18:26:58 +000064/*
65 * This file is autogenerated by api_generator.py. Do not edit directly.
66 */
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070067namespace vulkan {
68namespace api {
69
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070070struct InstanceDispatchTable {
71 // clang-format off\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070072
Yiwei Zhang1ca59c12019-10-10 12:54:42 -070073 for entry in instance_dispatch_table_entries:
74 f.write(gencom.indent(1) + entry + '\n')
75
76 f.write("""\
77 // clang-format on
78};
79
80struct DeviceDispatchTable {
81 // clang-format off\n""")
82
83 for entry in device_dispatch_table_entries:
84 f.write(gencom.indent(1) + entry + '\n')
85
86 f.write("""\
87 // clang-format on
88};
89
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -070090bool InitDispatchTable(
91 VkInstance instance,
92 PFN_vkGetInstanceProcAddr get_proc,
93 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions);
94bool InitDispatchTable(
95 VkDevice dev,
96 PFN_vkGetDeviceProcAddr get_proc,
97 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions);
98
99} // namespace api
100} // namespace vulkan
101
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700102#endif // LIBVULKAN_API_GEN_H\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700103
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700104 f.close()
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700105 gencom.run_clang_format(genfile)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700106
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700107
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700108def _define_extension_stub(cmd, f):
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700109 """Emits a stub for an exported extension function.
110
111 Args:
112 cmd: Vulkan function name.
113 f: Output file handle.
114 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700115 if (cmd in gencom.extension_dict and gencom.is_function_exported(cmd)):
116 ext_name = gencom.extension_dict[cmd]
117 ret = gencom.return_type_dict[cmd]
118 params = gencom.param_dict[cmd]
119 first_param = params[0][0] + params[0][1]
120 tail_params = ', '.join([i[0][:-1] for i in params[1:]])
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700121
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700122 f.write('VKAPI_ATTR ' + ret + ' disabled' + gencom.base_name(cmd) +
123 '(' + first_param + ', ' + tail_params + ') {\n')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700124
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700125 f.write(gencom.indent(1) + 'driver::Logger(' + params[0][1] +
126 ').Err(' + params[0][1] + ', \"' + ext_name +
127 ' not enabled. Exported ' + cmd + ' not executed.\");\n')
128
129 if gencom.return_type_dict[cmd] != 'void':
130 f.write(gencom.indent(1) + 'return VK_SUCCESS;\n')
131
132 f.write('}\n\n')
133
134
135def _is_intercepted(cmd):
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700136 """Returns true if a function is intercepted by vulkan::api.
137
138 Args:
139 cmd: Vulkan function name.
140 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700141 if gencom.is_function_supported(cmd):
142 if gencom.is_globally_dispatched(cmd) or cmd in _INTERCEPTED_COMMANDS:
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700143 return True
144 return False
145
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700146
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700147def _intercept_instance_proc_addr(f):
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700148 """Emits code for vkGetInstanceProcAddr for function interception.
149
150 Args:
151 f: Output file handle.
152 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700153 f.write("""\
154 // global functions
155 if (instance == VK_NULL_HANDLE) {\n""")
156
157 for cmd in gencom.command_list:
Jesse Hall7559c762020-05-21 16:28:48 -0700158 # vkGetInstanceProcAddr(nullptr, "vkGetInstanceProcAddr") is effectively
159 # globally dispatched
160 if gencom.is_globally_dispatched(cmd) or cmd == 'vkGetInstanceProcAddr':
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700161 f.write(gencom.indent(2) +
162 'if (strcmp(pName, \"' + cmd +
163 '\") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' +
164 gencom.base_name(cmd) + ');\n')
165
166 f.write("""
167 ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \\\"%s\\\") call", pName);
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700168 return nullptr;
169 }
170
171 static const struct Hook {
172 const char* name;
173 PFN_vkVoidFunction proc;
174 } hooks[] = {\n""")
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700175
176 sorted_command_list = sorted(gencom.command_list)
177 for cmd in sorted_command_list:
178 if gencom.is_function_exported(cmd):
179 if gencom.is_globally_dispatched(cmd):
180 f.write(gencom.indent(2) + '{ \"' + cmd + '\", nullptr },\n')
181 elif (_is_intercepted(cmd) or
182 cmd == 'vkGetInstanceProcAddr' or
183 gencom.is_device_dispatched(cmd)):
184 f.write(gencom.indent(2) + '{ \"' + cmd +
185 '\", reinterpret_cast<PFN_vkVoidFunction>(' +
186 gencom.base_name(cmd) + ') },\n')
187
188 f.write("""\
189 };
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700190 // clang-format on
191 constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
192 auto hook = std::lower_bound(
193 hooks, hooks + count, pName,
194 [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; });
195 if (hook < hooks + count && strcmp(hook->name, pName) == 0) {
196 if (!hook->proc) {
197 vulkan::driver::Logger(instance).Err(
198 instance, "invalid vkGetInstanceProcAddr(%p, \\\"%s\\\") call",
199 instance, pName);
200 }
201 return hook->proc;
202 }
203 // clang-format off\n\n""")
204
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700205
206def _intercept_device_proc_addr(f):
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700207 """Emits code for vkGetDeviceProcAddr for function interception.
208
209 Args:
210 f: Output file handle.
211 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700212 f.write("""\
213 if (device == VK_NULL_HANDLE) {
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700214 ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call");
215 return nullptr;
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700216 }
217
218 static const char* const known_non_device_names[] = {\n""")
219
220 sorted_command_list = sorted(gencom.command_list)
221 for cmd in sorted_command_list:
222 if gencom.is_function_supported(cmd):
223 if not gencom.is_device_dispatched(cmd):
224 f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
225
226 f.write("""\
227 };
228 // clang-format on
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700229 constexpr size_t count =
230 sizeof(known_non_device_names) / sizeof(known_non_device_names[0]);
231 if (!pName ||
232 std::binary_search(
233 known_non_device_names, known_non_device_names + count, pName,
234 [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) {
235 vulkan::driver::Logger(device).Err(
236 device, "invalid vkGetDeviceProcAddr(%p, \\\"%s\\\") call", device,
237 (pName) ? pName : "(null)");
238 return nullptr;
239 }
240 // clang-format off\n\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700241
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700242 for cmd in gencom.command_list:
243 if gencom.is_device_dispatched(cmd):
244 if _is_intercepted(cmd) or cmd == 'vkGetDeviceProcAddr':
245 f.write(gencom.indent(1) + 'if (strcmp(pName, "' + cmd +
246 '") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' +
247 gencom.base_name(cmd) + ');\n')
248 f.write('\n')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700249
250
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700251def _api_dispatch(cmd, f):
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700252 """Emits code to dispatch a function.
253
254 Args:
255 cmd: Vulkan function name.
256 f: Output file handle.
257 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700258 assert not _is_intercepted(cmd)
259
260 f.write(gencom.indent(1))
261 if gencom.return_type_dict[cmd] != 'void':
262 f.write('return ')
263
264 param_list = gencom.param_dict[cmd]
265 handle = param_list[0][1]
266 f.write('GetData(' + handle + ').dispatch.' + gencom.base_name(cmd) +
267 '(' + ', '.join(i[1] for i in param_list) + ');\n')
268
269
270def gen_cpp():
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700271 """Generates the api_gen.cpp file.
272 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700273 genfile = os.path.join(os.path.dirname(__file__),
274 '..', 'libvulkan', 'api_gen.cpp')
275
276 with open(genfile, 'w') as f:
277 f.write(gencom.copyright_and_warning(2016))
278
279 f.write("""\
280#include <log/log.h>
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700281#include <string.h>
282
283#include <algorithm>
284
285// to catch mismatches between vulkan.h and this file
286#undef VK_NO_PROTOTYPES
287#include "api.h"
288
Tom Murphyea321842024-06-14 18:26:58 +0000289/*
290 * This file is autogenerated by api_generator.py. Do not edit directly.
291 */
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700292namespace vulkan {
293namespace api {
294
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700295#define UNLIKELY(expr) __builtin_expect((expr), 0)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700296
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700297#define INIT_PROC(required, obj, proc) \\
298 do { \\
299 data.dispatch.proc = \\
300 reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
301 if (UNLIKELY(required && !data.dispatch.proc)) { \\
302 ALOGE("missing " #obj " proc: vk" #proc); \\
303 success = false; \\
304 } \\
305 } while (0)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700306
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700307// Exported extension functions may be invoked even when their extensions
308// are disabled. Dispatch to stubs when that happens.
309#define INIT_PROC_EXT(ext, required, obj, proc) \\
310 do { \\
311 if (extensions[driver::ProcHook::ext]) \\
312 INIT_PROC(required, obj, proc); \\
313 else \\
314 data.dispatch.proc = disabled##proc; \\
315 } while (0)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700316
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700317namespace {
318
319// clang-format off\n\n""")
320
321 for cmd in gencom.command_list:
322 _define_extension_stub(cmd, f)
323
324 f.write("""\
325// clang-format on
326
327} // namespace
328
329bool InitDispatchTable(
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700330 VkInstance instance,
331 PFN_vkGetInstanceProcAddr get_proc,
332 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
333 auto& data = GetData(instance);
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700334 bool success = true;
335
336 // clang-format off\n""")
337
338 for cmd in gencom.command_list:
339 if gencom.is_instance_dispatch_table_entry(cmd):
340 gencom.init_proc(cmd, f)
341
342 f.write("""\
343 // clang-format on
344
345 return success;
346}
347
348bool InitDispatchTable(
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700349 VkDevice dev,
350 PFN_vkGetDeviceProcAddr get_proc,
351 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
352 auto& data = GetData(dev);
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700353 bool success = true;
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700354
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700355 // clang-format off\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700356
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700357 for cmd in gencom.command_list:
358 if gencom.is_device_dispatch_table_entry(cmd):
359 gencom.init_proc(cmd, f)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700360
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700361 f.write("""\
362 // clang-format on
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700363
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700364 return success;
365}
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700366
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700367// clang-format off
368
369namespace {
370
371// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr
372""")
373
374 for cmd in gencom.command_list:
375 if gencom.is_function_exported(cmd) and not _is_intercepted(cmd):
376 param_list = [''.join(i) for i in gencom.param_dict[cmd]]
377 f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
378 gencom.base_name(cmd) + '(' + ', '.join(param_list) + ');\n')
379
380 f.write('\n')
381 for cmd in gencom.command_list:
382 if gencom.is_function_exported(cmd) and not _is_intercepted(cmd):
383 param_list = [''.join(i) for i in gencom.param_dict[cmd]]
384 f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
385 gencom.base_name(cmd) + '(' + ', '.join(param_list) + ') {\n')
386 if cmd == 'vkGetInstanceProcAddr':
387 _intercept_instance_proc_addr(f)
388 elif cmd == 'vkGetDeviceProcAddr':
389 _intercept_device_proc_addr(f)
390 _api_dispatch(cmd, f)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700391 f.write('}\n\n')
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700392
393 f.write("""
394} // anonymous namespace
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700395
396// clang-format on
397
398} // namespace api
399} // namespace vulkan
400
401// clang-format off\n\n""")
402
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700403 for cmd in gencom.command_list:
404 if gencom.is_function_exported(cmd):
405 param_list = [''.join(i) for i in gencom.param_dict[cmd]]
406 f.write('__attribute__((visibility("default")))\n')
407 f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
408 cmd + '(' + ', '.join(param_list) + ') {\n')
409 f.write(gencom.indent(1))
410 if gencom.return_type_dict[cmd] != 'void':
411 f.write('return ')
412 param_list = gencom.param_dict[cmd]
413 f.write('vulkan::api::' + gencom.base_name(cmd) +
414 '(' + ', '.join(i[1] for i in param_list) + ');\n}\n\n')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700415
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700416 f.write('// clang-format on\n')
Adithya Srinivasan8dce9d72019-07-11 14:26:04 -0700417 f.close()
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700418 gencom.run_clang_format(genfile)