code-generator.tmpl revision 0c2032490b80178ec823bf22a7f5d08398851cc3
1{{define "Copyright"}}
2/*
3•* Copyright 2016 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¶{{end}}
18
19{{Include "../api/templates/vulkan_common.tmpl"}}
20{{Global "clang-format" (Strings "clang-format" "-style=file")}}
21{{Macro "DefineGlobals" $}}
22{{$ | Macro "api_gen.h"   | Format (Global "clang-format") | Write "api_gen.h"  }}
23{{$ | Macro "api_gen.cpp" | Format (Global "clang-format") | Write "api_gen.cpp"}}
24
25{{/*
26-------------------------------------------------------------------------------
27  api_gen.h
28-------------------------------------------------------------------------------
29*/}}
30{{define "api_gen.h"}}
31{{Macro "Copyright"}}
3233// WARNING: This file is generated. See ../README.md for instructions.
3435#ifndef LIBVULKAN_API_GEN_H
36#define LIBVULKAN_API_GEN_H
3738#include <vulkan/vulkan.h>
3940namespace vulkan {«
41namespace api {«
4243struct InstanceDispatchTable {
44  // clang-format off
45  {{range $f := AllCommands $}}
46    {{if (Macro "api.IsInstanceDispatchTableEntry" $f)}}
47      {{Macro "C++.DeclareDispatchTableEntry" $f}};
48    {{end}}
49  {{end}}
50  // clang-format on
51};
5253struct DeviceDispatchTable {
54  // clang-format off
55  {{range $f := AllCommands $}}
56    {{if (Macro "api.IsDeviceDispatchTableEntry" $f)}}
57      {{Macro "C++.DeclareDispatchTableEntry" $f}};
58    {{end}}
59  {{end}}
60  // clang-format on
61};
6263bool InitDispatchTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc);
64bool InitDispatchTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc);
6566»} // namespace api
67»} // namespace vulkan
6869#endif // LIBVULKAN_API_GEN_H
70¶{{end}}
71
72
73{{/*
74-------------------------------------------------------------------------------
75  api_gen.cpp
76-------------------------------------------------------------------------------
77*/}}
78{{define "api_gen.cpp"}}
79{{Macro "Copyright"}}
8081// WARNING: This file is generated. See ../README.md for instructions.
8283#include <string.h>
84#include <algorithm>
85#include <log/log.h>
8687#include "api.h"
8889namespace vulkan {«
90namespace api {«
9192{{Macro "C++.DefineInitProcMacros" "dispatch"}}
9394bool InitDispatchTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc) {
95    auto& data = GetData(instance);
96    bool success = true;
9798    // clang-format off
99    {{range $f := AllCommands $}}
100      {{if (Macro "api.IsInstanceDispatchTableEntry" $f)}}
101        {{Macro "C++.InitProc" $f}}
102      {{end}}
103    {{end}}
104    // clang-format on
105106    return success;
107}
108109bool InitDispatchTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc) {
110    auto& data = GetData(dev);
111    bool success = true;
112113    // clang-format off
114    {{range $f := AllCommands $}}
115      {{if (Macro "api.IsDeviceDispatchTableEntry" $f)}}
116        {{Macro "C++.InitProc" $f}}
117      {{end}}
118    {{end}}
119    // clang-format on
120121    return success;
122}
123124»} // namespace api
125»} // namespace vulkan
126127// clang-format off
128129{{range $f := AllCommands $}}
130  {{if (Macro "IsFunctionExported" $f)}}
131    __attribute__((visibility("default")))
132    VKAPI_ATTR {{Node "Type" $f.Return}} {{$f.Name}}({{Macro "Parameters" $f}}) {
133      {{     if eq $f.Name "vkGetInstanceProcAddr"}}
134        {{Macro "api.C++.InterceptInstanceProcAddr" $}}
135      {{else if eq $f.Name "vkGetDeviceProcAddr"}}
136        {{Macro "api.C++.InterceptDeviceProcAddr" $}}
137      {{end}}
138
139      {{Macro "api.C++.Dispatch" $f}}
140    }
141142  {{end}}
143{{end}}
144145// clang-format on
146¶{{end}}
147
148
149{{/*
150------------------------------------------------------------------------------
151  Emits a declaration of a dispatch table entry.
152------------------------------------------------------------------------------
153*/}}
154{{define "C++.DeclareDispatchTableEntry"}}
155  {{AssertType $ "Function"}}
156
157  {{Macro "FunctionPtrName" $}} {{Macro "BaseName" $}}
158{{end}}
159
160
161{{/*
162-------------------------------------------------------------------------------
163  Emits macros to help initialize dispatch tables.
164-------------------------------------------------------------------------------
165*/}}
166{{define "C++.DefineInitProcMacros"}}
167  #define UNLIKELY(expr) __builtin_expect((expr), 0)
168169  #define INIT_PROC(obj, proc) do {                             \
170      data.{{$}}.proc = reinterpret_cast<PFN_vk ## proc>(       \
171              get_proc(obj, "vk" # proc));                      \
172      if (UNLIKELY(!data.{{$}}.proc)) {                         \
173          ALOGE("missing " # obj " proc: vk" # proc);           \
174          success = false;                                      \
175      }                                                         \
176  } while(0)
177178  // TODO do we want to point to a stub or nullptr when ext is not enabled?
179  #define INIT_PROC_EXT(ext, obj, proc) do {                    \
180      INIT_PROC(obj, proc);                                     \
181  } while(0)
182{{end}}
183
184
185{{/*
186-------------------------------------------------------------------------------
187  Emits code to invoke INIT_PROC or INIT_PROC_EXT.
188-------------------------------------------------------------------------------
189*/}}
190{{define "C++.InitProc"}}
191  {{AssertType $ "Function"}}
192
193  {{$ext := GetAnnotation $ "extension"}}
194  {{if $ext}}
195    INIT_PROC_EXT({{Macro "BaseName" $ext}}, §
196  {{else}}
197    INIT_PROC(§
198  {{end}}
199
200  {{if (Macro "IsInstanceDispatched" $)}}
201    instance, §
202  {{else}}
203    dev, §
204  {{end}}
205
206  {{Macro "BaseName" $}});
207{{end}}
208
209
210{{/*
211------------------------------------------------------------------------------
212  Emits true if a function is exported and instance-dispatched.
213------------------------------------------------------------------------------
214*/}}
215{{define "api.IsInstanceDispatchTableEntry"}}
216  {{AssertType $ "Function"}}
217
218  {{if and (Macro "IsFunctionExported" $) (Macro "IsInstanceDispatched" $)}}
219    true
220  {{end}}
221{{end}}
222
223
224{{/*
225------------------------------------------------------------------------------
226  Emits true if a function is exported and device-dispatched.
227------------------------------------------------------------------------------
228*/}}
229{{define "api.IsDeviceDispatchTableEntry"}}
230  {{AssertType $ "Function"}}
231
232  {{if and (Macro "IsFunctionExported" $) (Macro "IsDeviceDispatched" $)}}
233    true
234  {{end}}
235{{end}}
236
237
238{{/*
239------------------------------------------------------------------------------
240  Emits true if a function is intercepted by vulkan::api.
241------------------------------------------------------------------------------
242*/}}
243{{define "api.IsIntercepted"}}
244  {{AssertType $ "Function"}}
245
246  {{if (Macro "IsFunctionSupported" $)}}
247    {{/* Global functions cannot be dispatched at all */}}
248    {{     if (Macro "IsGloballyDispatched" $)}}true
249
250    {{/* VkPhysicalDevice functions that manage device layers */}}
251    {{else if eq $.Name "vkCreateDevice"}}true
252    {{else if eq $.Name "vkEnumerateDeviceLayerProperties"}}true
253    {{else if eq $.Name "vkEnumerateDeviceExtensionProperties"}}true
254
255    {{/* Destroy functions of dispatchable objects */}}
256    {{else if eq $.Name "vkDestroyInstance"}}true
257    {{else if eq $.Name "vkDestroyDevice"}}true
258
259    {{end}}
260  {{end}}
261{{end}}
262
263
264{{/*
265------------------------------------------------------------------------------
266  Emits code for vkGetInstanceProcAddr for function interception.
267------------------------------------------------------------------------------
268*/}}
269{{define "api.C++.InterceptInstanceProcAddr"}}
270  {{AssertType $ "API"}}
271
272  // global functions
273  if (!instance) {
274    {{range $f := AllCommands $}}
275      {{if (Macro "IsGloballyDispatched" $f)}}
276        if (strcmp(pName, "{{$f.Name}}") == 0) return §
277          reinterpret_cast<PFN_vkVoidFunction>(§
278            vulkan::api::{{Macro "BaseName" $f}});
279      {{end}}
280    {{end}}
281282    ALOGE("vkGetInstanceProcAddr called with %s without instance",  pName);
283    return nullptr;
284  }
285286  static const struct Hook {
287    const char* name;
288    PFN_vkVoidFunction proc;
289  } hooks[] = {
290    {{range $f := SortBy (AllCommands $) "FunctionName"}}
291      {{if (Macro "IsFunctionExported" $f)}}
292        {{/* hide global functions */}}
293        {{if (Macro "IsGloballyDispatched" $f)}}
294          { "{{$f.Name}}", nullptr },
295
296        {{/* redirect intercepted functions */}}
297        {{else if (Macro "api.IsIntercepted" $f)}}
298          { "{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>(§
299            vulkan::api::{{Macro "BaseName" $f}}) },
300
301        {{/* redirect vkGetInstanceProcAddr to itself */}}
302        {{else if eq $f.Name "vkGetInstanceProcAddr"}}
303          { "{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>({{$f.Name}}) },
304
305        {{/* redirect device functions to themselves as a workaround for
306             layers that do not intercept in their vkGetInstanceProcAddr */}}
307        {{else if (Macro "IsDeviceDispatched" $f)}}
308          { "{{$f.Name}}", reinterpret_cast<PFN_vkVoidFunction>({{$f.Name}}) },
309
310        {{end}}
311      {{end}}
312    {{end}}
313  };
314  // clang-format on
315  constexpr size_t count = sizeof(hooks) / sizeof(hooks[0]);
316  auto hook = std::lower_bound(
317    hooks, hooks + count, pName,
318    [](const Hook& h, const char* n) { return strcmp(h.name, n) < 0; });
319  if (hook <  hooks + count && strcmp(hook->name, pName) == 0) {
320    if (!hook->proc)
321      ALOGE("vkGetInstanceProcAddr called with %s with instance",  pName);
322    return hook->proc;
323  }
324  // clang-format off
325326{{end}}
327
328
329{{/*
330------------------------------------------------------------------------------
331  Emits code for vkGetDeviceProcAddr for function interception.
332------------------------------------------------------------------------------
333*/}}
334{{define "api.C++.InterceptDeviceProcAddr"}}
335  {{AssertType $ "API"}}
336
337  if (device == VK_NULL_HANDLE) {
338    ALOGE("vkGetDeviceProcAddr called with invalid device");
339    return nullptr;
340  }
341342  static const char* const known_non_device_names[] = {
343    {{range $f := SortBy (AllCommands $) "FunctionName"}}
344      {{if (Macro "IsFunctionSupported" $f)}}
345        {{if not (Macro "IsDeviceDispatched" $f)}}
346          "{{$f.Name}}",
347        {{end}}
348      {{end}}
349    {{end}}
350  };
351  // clang-format on
352  constexpr size_t count = sizeof(known_non_device_names) /
353    sizeof(known_non_device_names[0]);
354  if (!pName ||
355      std::binary_search(
356        known_non_device_names, known_non_device_names + count, pName,
357        [](const char* a, const char* b) { return (strcmp(a, b) < 0); })) {
358    ALOGE("vkGetDeviceProcAddr called with %s", pName);
359    return nullptr;
360  }
361  // clang-format off
362363{{end}}
364
365
366{{/*
367------------------------------------------------------------------------------
368  Emits code to dispatch a function.
369------------------------------------------------------------------------------
370*/}}
371{{define "api.C++.Dispatch"}}
372  {{AssertType $ "Function"}}
373
374  {{if (Macro "api.IsIntercepted" $)}}// call into api.cpp{{end}}
375  {{if not (IsVoid $.Return.Type)}}return §{{end}}
376
377  {{if (Macro "api.IsIntercepted" $)}}
378    vulkan::api::§
379  {{else}}
380    {{$p0 := index $.CallParameters 0}}
381    vulkan::api::GetData({{$p0.Name}}).dispatch.§
382  {{end}}
383
384  {{Macro "BaseName" $}}({{Macro "Arguments" $}});
385{{end}}
386
387
388{{/*
389-------------------------------------------------------------------------------
390  Emits a function/extension name without the "vk"/"VK_" prefix.
391-------------------------------------------------------------------------------
392*/}}
393{{define "BaseName"}}
394  {{     if IsFunction $}}{{TrimPrefix "vk" $.Name}}
395  {{else if eq $.Name "extension"}}{{TrimPrefix "VK_" (index $.Arguments 0)}}
396  {{else}}{{Error "invalid use of BaseName"}}
397  {{end}}
398{{end}}
399
400
401{{/*
402-------------------------------------------------------------------------------
403  Emits a comma-separated list of C parameter names for the given command.
404-------------------------------------------------------------------------------
405*/}}
406{{define "Arguments"}}
407  {{AssertType $ "Function"}}
408
409  {{ForEach $.CallParameters "ParameterName" | JoinWith ", "}}
410{{end}}
411
412
413{{/*
414------------------------------------------------------------------------------
415------------------------------------------------------------------------------
416*/}}
417{{define "IsGloballyDispatched"}}
418  {{AssertType $ "Function"}}
419  {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Global")}}
420    true
421  {{end}}
422{{end}}
423
424
425{{/*
426------------------------------------------------------------------------------
427  Emit "true" for supported functions that undergo table dispatch. Only global
428  functions and functions handled in the loader top without calling into
429  lower layers are not dispatched.
430------------------------------------------------------------------------------
431*/}}
432{{define "IsInstanceDispatched"}}
433  {{AssertType $ "Function"}}
434  {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Instance")}}
435    true
436  {{end}}
437{{end}}
438
439
440{{/*
441------------------------------------------------------------------------------
442  Emit "true" for supported functions that can have device-specific dispatch.
443------------------------------------------------------------------------------
444*/}}
445{{define "IsDeviceDispatched"}}
446  {{AssertType $ "Function"}}
447  {{if and (Macro "IsFunctionSupported" $) (eq (Macro "Vtbl" $) "Device")}}
448    true
449  {{end}}
450{{end}}
451
452
453{{/*
454------------------------------------------------------------------------------
455  Emit "true" if a function is core or from a supportable extension.
456------------------------------------------------------------------------------
457*/}}
458{{define "IsFunctionSupported"}}
459  {{AssertType $ "Function"}}
460  {{if not (GetAnnotation $ "pfn")}}
461    {{$ext := GetAnnotation $ "extension"}}
462    {{if not $ext}}true
463    {{else if not (Macro "IsExtensionBlacklisted" $ext)}}true
464    {{end}}
465  {{end}}
466{{end}}
467
468
469{{/*
470------------------------------------------------------------------------------
471  Decides whether a function should be exported from the Android Vulkan
472  library. Functions in the core API and in loader extensions are exported.
473------------------------------------------------------------------------------
474*/}}
475{{define "IsFunctionExported"}}
476  {{AssertType $ "Function"}}
477
478  {{if (Macro "IsFunctionSupported" $)}}
479    {{$ext := GetAnnotation $ "extension"}}
480    {{if $ext}}
481      {{Macro "IsExtensionExported" $ext}}
482    {{else}}
483      true
484    {{end}}
485  {{end}}
486{{end}}
487
488
489{{/*
490------------------------------------------------------------------------------
491  Emit "true" if an extension is unsupportable on Android.
492------------------------------------------------------------------------------
493*/}}
494{{define "IsExtensionBlacklisted"}}
495  {{$ext := index $.Arguments 0}}
496  {{     if eq $ext "VK_KHR_display"}}true
497  {{else if eq $ext "VK_KHR_display_swapchain"}}true
498  {{else if eq $ext "VK_KHR_xlib_surface"}}true
499  {{else if eq $ext "VK_KHR_xcb_surface"}}true
500  {{else if eq $ext "VK_KHR_wayland_surface"}}true
501  {{else if eq $ext "VK_KHR_mir_surface"}}true
502  {{else if eq $ext "VK_KHR_win32_surface"}}true
503  {{end}}
504{{end}}
505
506
507{{/*
508------------------------------------------------------------------------------
509  Reports whether an extension is implemented entirely by the loader,
510  so drivers should not enumerate it.
511------------------------------------------------------------------------------
512*/}}
513{{define "IsExtensionExported"}}
514  {{$ext := index $.Arguments 0}}
515  {{     if eq $ext "VK_KHR_surface"}}true
516  {{else if eq $ext "VK_KHR_swapchain"}}true
517  {{else if eq $ext "VK_KHR_android_surface"}}true
518  {{end}}
519{{end}}
520