blob: be24172eed550c9929a14670d64ccba7aeb05f5d [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:
Jesse Hall7559c762020-05-21 16:28:48 -0700155 # vkGetInstanceProcAddr(nullptr, "vkGetInstanceProcAddr") is effectively
156 # globally dispatched
157 if gencom.is_globally_dispatched(cmd) or cmd == 'vkGetInstanceProcAddr':
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700158 f.write(gencom.indent(2) +
159 'if (strcmp(pName, \"' + cmd +
160 '\") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' +
161 gencom.base_name(cmd) + ');\n')
162
163 f.write("""
164 ALOGE("invalid vkGetInstanceProcAddr(VK_NULL_HANDLE, \\\"%s\\\") call", pName);
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700165 return nullptr;
166 }
167
168 static const struct Hook {
169 const char* name;
170 PFN_vkVoidFunction proc;
171 } hooks[] = {\n""")
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700172
173 sorted_command_list = sorted(gencom.command_list)
174 for cmd in sorted_command_list:
175 if gencom.is_function_exported(cmd):
176 if gencom.is_globally_dispatched(cmd):
177 f.write(gencom.indent(2) + '{ \"' + cmd + '\", nullptr },\n')
178 elif (_is_intercepted(cmd) or
179 cmd == 'vkGetInstanceProcAddr' or
180 gencom.is_device_dispatched(cmd)):
181 f.write(gencom.indent(2) + '{ \"' + cmd +
182 '\", reinterpret_cast<PFN_vkVoidFunction>(' +
183 gencom.base_name(cmd) + ') },\n')
184
185 f.write("""\
186 };
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700187 // clang-format on
188 constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
189 auto hook = std::lower_bound(
190 hooks, hooks + count, pName,
191 [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; });
192 if (hook < hooks + count && strcmp(hook->name, pName) == 0) {
193 if (!hook->proc) {
194 vulkan::driver::Logger(instance).Err(
195 instance, "invalid vkGetInstanceProcAddr(%p, \\\"%s\\\") call",
196 instance, pName);
197 }
198 return hook->proc;
199 }
200 // clang-format off\n\n""")
201
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700202
203def _intercept_device_proc_addr(f):
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700204 """Emits code for vkGetDeviceProcAddr for function interception.
205
206 Args:
207 f: Output file handle.
208 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700209 f.write("""\
210 if (device == VK_NULL_HANDLE) {
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700211 ALOGE("invalid vkGetDeviceProcAddr(VK_NULL_HANDLE, ...) call");
212 return nullptr;
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700213 }
214
215 static const char* const known_non_device_names[] = {\n""")
216
217 sorted_command_list = sorted(gencom.command_list)
218 for cmd in sorted_command_list:
219 if gencom.is_function_supported(cmd):
220 if not gencom.is_device_dispatched(cmd):
221 f.write(gencom.indent(2) + '\"' + cmd + '\",\n')
222
223 f.write("""\
224 };
225 // clang-format on
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700226 constexpr size_t count =
227 sizeof(known_non_device_names) / sizeof(known_non_device_names[0]);
228 if (!pName ||
229 std::binary_search(
230 known_non_device_names, known_non_device_names + count, pName,
231 [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) {
232 vulkan::driver::Logger(device).Err(
233 device, "invalid vkGetDeviceProcAddr(%p, \\\"%s\\\") call", device,
234 (pName) ? pName : "(null)");
235 return nullptr;
236 }
237 // clang-format off\n\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700238
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700239 for cmd in gencom.command_list:
240 if gencom.is_device_dispatched(cmd):
241 if _is_intercepted(cmd) or cmd == 'vkGetDeviceProcAddr':
242 f.write(gencom.indent(1) + 'if (strcmp(pName, "' + cmd +
243 '") == 0) return reinterpret_cast<PFN_vkVoidFunction>(' +
244 gencom.base_name(cmd) + ');\n')
245 f.write('\n')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700246
247
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700248def _api_dispatch(cmd, f):
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700249 """Emits code to dispatch a function.
250
251 Args:
252 cmd: Vulkan function name.
253 f: Output file handle.
254 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700255 assert not _is_intercepted(cmd)
256
257 f.write(gencom.indent(1))
258 if gencom.return_type_dict[cmd] != 'void':
259 f.write('return ')
260
261 param_list = gencom.param_dict[cmd]
262 handle = param_list[0][1]
263 f.write('GetData(' + handle + ').dispatch.' + gencom.base_name(cmd) +
264 '(' + ', '.join(i[1] for i in param_list) + ');\n')
265
266
267def gen_cpp():
Yiwei Zhang6ca5d0c2019-10-11 17:15:02 -0700268 """Generates the api_gen.cpp file.
269 """
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700270 genfile = os.path.join(os.path.dirname(__file__),
271 '..', 'libvulkan', 'api_gen.cpp')
272
273 with open(genfile, 'w') as f:
274 f.write(gencom.copyright_and_warning(2016))
275
276 f.write("""\
277#include <log/log.h>
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700278#include <string.h>
279
280#include <algorithm>
281
282// to catch mismatches between vulkan.h and this file
283#undef VK_NO_PROTOTYPES
284#include "api.h"
285
286namespace vulkan {
287namespace api {
288
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700289#define UNLIKELY(expr) __builtin_expect((expr), 0)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700290
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700291#define INIT_PROC(required, obj, proc) \\
292 do { \\
293 data.dispatch.proc = \\
294 reinterpret_cast<PFN_vk##proc>(get_proc(obj, "vk" #proc)); \\
295 if (UNLIKELY(required && !data.dispatch.proc)) { \\
296 ALOGE("missing " #obj " proc: vk" #proc); \\
297 success = false; \\
298 } \\
299 } while (0)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700300
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700301// Exported extension functions may be invoked even when their extensions
302// are disabled. Dispatch to stubs when that happens.
303#define INIT_PROC_EXT(ext, required, obj, proc) \\
304 do { \\
305 if (extensions[driver::ProcHook::ext]) \\
306 INIT_PROC(required, obj, proc); \\
307 else \\
308 data.dispatch.proc = disabled##proc; \\
309 } while (0)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700310
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700311namespace {
312
313// clang-format off\n\n""")
314
315 for cmd in gencom.command_list:
316 _define_extension_stub(cmd, f)
317
318 f.write("""\
319// clang-format on
320
321} // namespace
322
323bool InitDispatchTable(
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700324 VkInstance instance,
325 PFN_vkGetInstanceProcAddr get_proc,
326 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
327 auto& data = GetData(instance);
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700328 bool success = true;
329
330 // clang-format off\n""")
331
332 for cmd in gencom.command_list:
333 if gencom.is_instance_dispatch_table_entry(cmd):
334 gencom.init_proc(cmd, f)
335
336 f.write("""\
337 // clang-format on
338
339 return success;
340}
341
342bool InitDispatchTable(
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700343 VkDevice dev,
344 PFN_vkGetDeviceProcAddr get_proc,
345 const std::bitset<driver::ProcHook::EXTENSION_COUNT>& extensions) {
346 auto& data = GetData(dev);
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700347 bool success = true;
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700348
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700349 // clang-format off\n""")
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700350
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700351 for cmd in gencom.command_list:
352 if gencom.is_device_dispatch_table_entry(cmd):
353 gencom.init_proc(cmd, f)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700354
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700355 f.write("""\
356 // clang-format on
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700357
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700358 return success;
359}
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700360
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700361// clang-format off
362
363namespace {
364
365// forward declarations needed by GetInstanceProcAddr and GetDeviceProcAddr
366""")
367
368 for cmd in gencom.command_list:
369 if gencom.is_function_exported(cmd) and not _is_intercepted(cmd):
370 param_list = [''.join(i) for i in gencom.param_dict[cmd]]
371 f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
372 gencom.base_name(cmd) + '(' + ', '.join(param_list) + ');\n')
373
374 f.write('\n')
375 for cmd in gencom.command_list:
376 if gencom.is_function_exported(cmd) and not _is_intercepted(cmd):
377 param_list = [''.join(i) for i in gencom.param_dict[cmd]]
378 f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
379 gencom.base_name(cmd) + '(' + ', '.join(param_list) + ') {\n')
380 if cmd == 'vkGetInstanceProcAddr':
381 _intercept_instance_proc_addr(f)
382 elif cmd == 'vkGetDeviceProcAddr':
383 _intercept_device_proc_addr(f)
384 _api_dispatch(cmd, f)
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700385 f.write('}\n\n')
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700386
387 f.write("""
388} // anonymous namespace
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700389
390// clang-format on
391
392} // namespace api
393} // namespace vulkan
394
395// clang-format off\n\n""")
396
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700397 for cmd in gencom.command_list:
398 if gencom.is_function_exported(cmd):
399 param_list = [''.join(i) for i in gencom.param_dict[cmd]]
400 f.write('__attribute__((visibility("default")))\n')
401 f.write('VKAPI_ATTR ' + gencom.return_type_dict[cmd] + ' ' +
402 cmd + '(' + ', '.join(param_list) + ') {\n')
403 f.write(gencom.indent(1))
404 if gencom.return_type_dict[cmd] != 'void':
405 f.write('return ')
406 param_list = gencom.param_dict[cmd]
407 f.write('vulkan::api::' + gencom.base_name(cmd) +
408 '(' + ', '.join(i[1] for i in param_list) + ');\n}\n\n')
Adithya Srinivasan751a7dc2019-07-02 17:17:25 -0700409
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700410 f.write('// clang-format on\n')
Adithya Srinivasan8dce9d72019-07-11 14:26:04 -0700411 f.close()
Yiwei Zhang1ca59c12019-10-10 12:54:42 -0700412 gencom.run_clang_format(genfile)