Chia-I Wu | 0c20324 | 2016-03-15 13:44:51 +0800 | [diff] [blame^] | 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"}} |
| 32 | ¶ |
| 33 | // WARNING: This file is generated. See ../README.md for instructions. |
| 34 | ¶ |
| 35 | #ifndef LIBVULKAN_API_GEN_H |
| 36 | #define LIBVULKAN_API_GEN_H |
| 37 | ¶ |
| 38 | #include <vulkan/vulkan.h> |
| 39 | ¶ |
| 40 | namespace vulkan {« |
| 41 | namespace api {« |
| 42 | ¶ |
| 43 | struct 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 | }; |
| 52 | ¶ |
| 53 | struct 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 | }; |
| 62 | ¶ |
| 63 | bool InitDispatchTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc); |
| 64 | bool InitDispatchTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc); |
| 65 | ¶ |
| 66 | »} // namespace api |
| 67 | »} // namespace vulkan |
| 68 | ¶ |
| 69 | #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"}} |
| 80 | ¶ |
| 81 | // WARNING: This file is generated. See ../README.md for instructions. |
| 82 | ¶ |
| 83 | #include <string.h> |
| 84 | #include <algorithm> |
| 85 | #include <log/log.h> |
| 86 | ¶ |
| 87 | #include "api.h" |
| 88 | ¶ |
| 89 | namespace vulkan {« |
| 90 | namespace api {« |
| 91 | ¶ |
| 92 | {{Macro "C++.DefineInitProcMacros" "dispatch"}} |
| 93 | ¶ |
| 94 | bool InitDispatchTable(VkInstance instance, PFN_vkGetInstanceProcAddr get_proc) { |
| 95 | auto& data = GetData(instance); |
| 96 | bool success = true; |
| 97 | ¶ |
| 98 | // 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 |
| 105 | ¶ |
| 106 | return success; |
| 107 | } |
| 108 | ¶ |
| 109 | bool InitDispatchTable(VkDevice dev, PFN_vkGetDeviceProcAddr get_proc) { |
| 110 | auto& data = GetData(dev); |
| 111 | bool success = true; |
| 112 | ¶ |
| 113 | // 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 |
| 120 | ¶ |
| 121 | return success; |
| 122 | } |
| 123 | ¶ |
| 124 | »} // namespace api |
| 125 | »} // namespace vulkan |
| 126 | ¶ |
| 127 | // clang-format off |
| 128 | ¶ |
| 129 | {{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 | } |
| 141 | ¶ |
| 142 | {{end}} |
| 143 | {{end}} |
| 144 | ¶ |
| 145 | // 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) |
| 168 | ¶ |
| 169 | #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) |
| 177 | ¶ |
| 178 | // 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}} |
| 281 | ¶ |
| 282 | ALOGE("vkGetInstanceProcAddr called with %s without instance", pName); |
| 283 | return nullptr; |
| 284 | } |
| 285 | ¶ |
| 286 | 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 |
| 325 | ¶ |
| 326 | {{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 | } |
| 341 | ¶ |
| 342 | 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 |
| 362 | ¶ |
| 363 | {{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}} |