Home | History | Annotate | Download | only in loader
      1 #!/usr/bin/env python3
      2 #
      3 # Copyright (c) 2015-2016 The Khronos Group Inc.
      4 # Copyright (c) 2015-2016 Valve Corporation
      5 # Copyright (c) 2015-2016 LunarG, Inc.
      6 #
      7 # Licensed under the Apache License, Version 2.0 (the "License");
      8 # you may not use this file except in compliance with the License.
      9 # You may obtain a copy of the License at
     10 #
     11 #     http://www.apache.org/licenses/LICENSE-2.0
     12 #
     13 # Unless required by applicable law or agreed to in writing, software
     14 # distributed under the License is distributed on an "AS IS" BASIS,
     15 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
     16 # See the License for the specific language governing permissions and
     17 # limitations under the License.
     18 #
     19 # Author: Jon Ashburn <jon (at] lunarg.com>
     20 #
     21 
     22 import os, sys
     23 
     24 # add main repo directory so vulkan.py can be imported. This needs to be a complete path.
     25 ld_path = os.path.dirname(os.path.abspath(__file__))
     26 main_path = os.path.abspath(ld_path + "/../")
     27 sys.path.append(main_path)
     28 
     29 import vulkan
     30 
     31 def generate_get_proc_addr_check(name):
     32     return "    if (!%s || %s[0] != 'v' || %s[1] != 'k')\n" \
     33            "        return NULL;" % ((name,) * 3)
     34 
     35 class Subcommand(object):
     36     def __init__(self, argv):
     37         self.argv = argv
     38         self.headers = vulkan.headers
     39         self.protos = vulkan.protos
     40 
     41     def run(self):
     42         print(self.generate())
     43 
     44     def _requires_special_trampoline_code(self, name):
     45         # Don't be cute trying to use a general rule to programmatically populate this list
     46         # it just obsfucates what is going on!
     47         wsi_creates_dispatchable_object = ["CreateSwapchainKHR"]
     48         creates_dispatchable_object = ["CreateDevice", "GetDeviceQueue", "AllocateCommandBuffers"] + wsi_creates_dispatchable_object
     49         if name in creates_dispatchable_object:
     50             return True
     51         else:
     52            return False
     53 
     54     def _is_loader_non_trampoline_entrypoint(self, proto):
     55         if proto.name in ["GetDeviceProcAddr", "EnumeratePhysicalDevices", "EnumerateLayers", "DbgRegisterMsgCallback", "DbgUnregisterMsgCallback", "DbgSetGlobalOption", "DestroyInstance"]:
     56             return True
     57         return not self.is_dispatchable_object_first_param(proto)
     58 
     59 
     60     def is_dispatchable_object_first_param(self, proto):
     61         in_objs = proto.object_in_params()
     62         non_dispatch_objs = []
     63         param0 = proto.params[0]
     64         return (len(in_objs) > 0)  and (in_objs[0].ty == param0.ty) and (param0.ty not in non_dispatch_objs)
     65 
     66     def generate(self):
     67         copyright = self.generate_copyright()
     68         header = self.generate_header()
     69         body = self.generate_body()
     70         footer = self.generate_footer()
     71 
     72         contents = []
     73         if copyright:
     74             contents.append(copyright)
     75         if header:
     76             contents.append(header)
     77         if body:
     78             contents.append(body)
     79         if footer:
     80             contents.append(footer)
     81 
     82         return "\n\n".join(contents)
     83 
     84     def generate_copyright(self):
     85         return """/* THIS FILE IS GENERATED.  DO NOT EDIT. */
     86 
     87 /*
     88  * Copyright (c) 2015-2016 The Khronos Group Inc.
     89  * Copyright (c) 2015-2016 Valve Corporation
     90  * Copyright (c) 2015-2016 LunarG, Inc.
     91  *
     92  * Licensed under the Apache License, Version 2.0 (the "License");
     93  * you may not use this file except in compliance with the License.
     94  * You may obtain a copy of the License at
     95  *
     96  *     http://www.apache.org/licenses/LICENSE-2.0
     97  *
     98  * Unless required by applicable law or agreed to in writing, software
     99  * distributed under the License is distributed on an "AS IS" BASIS,
    100  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    101  * See the License for the specific language governing permissions and
    102  * limitations under the License.
    103  *
    104  * Author: Jon Ashburn <jon (at] lunarg.com>
    105  * Author: Chia-I Wu <olv (at] lunarg.com>
    106  * Author: Courtney Goeltzenleuchter <courtney (at] lunarg.com>
    107  */"""
    108 
    109     def generate_header(self):
    110         return "\n".join(["#include <" + h + ">" for h in self.headers])
    111 
    112     def generate_body(self):
    113         pass
    114 
    115     def generate_footer(self):
    116         pass
    117 
    118 class DispatchTableOpsSubcommand(Subcommand):
    119     def run(self):
    120         if len(self.argv) != 1:
    121             print("DispatchTableOpsSubcommand: <prefix> unspecified")
    122             return
    123 
    124         self.prefix = self.argv[0]
    125         super().run()
    126 
    127     def generate_header(self):
    128         return "\n".join(["#include <vulkan/vulkan.h>",
    129                           "#include <vkLayer.h>",
    130                           "#include <string.h>",
    131                           "#include \"loader_platform.h\""])
    132 
    133     def _generate_init(self, type):
    134         stmts = []
    135         func = []
    136         if type == "device":
    137             for proto in self.protos:
    138                 if self.is_dispatchable_object_first_param(proto) or proto.name == "CreateInstance":
    139                     stmts.append("table->%s = (PFN_vk%s) gpa(gpu, \"vk%s\");" %
    140                         (proto.name, proto.name, proto.name))
    141                 else:
    142                     stmts.append("table->%s = vk%s; /* non-dispatchable */" %
    143                              (proto.name, proto.name))
    144             func.append("static inline void %s_init_device_dispatch_table(VkLayerDispatchTable *table,"
    145                 % self.prefix)
    146             func.append("%s                                              PFN_vkGetDeviceProcAddr gpa,"
    147                 % (" " * len(self.prefix)))
    148             func.append("%s                                              VkPhysicalDevice gpu)"
    149                 % (" " * len(self.prefix)))
    150         else:
    151             for proto in self.protos:
    152                 if proto.params[0].ty != "VkInstance" and proto.params[0].ty != "VkPhysicalDevice":
    153                     continue
    154                 stmts.append("table->%s = vk%s;" % (proto.name, proto.name))
    155             func.append("static inline void %s_init_instance_dispatch_table(VkLayerInstanceDispatchTable *table)"
    156                 % self.prefix)
    157         func.append("{")
    158         func.append("    %s" % "\n    ".join(stmts))
    159         func.append("}")
    160 
    161         return "\n".join(func)
    162 
    163     def _generate_lookup(self):
    164         lookups = []
    165         for proto in self.protos:
    166             if self.is_dispatchable_object_first_param(proto):
    167                 lookups.append("if (!strcmp(name, \"%s\"))" % (proto.name))
    168                 lookups.append("    return (void *) table->%s;"
    169                     % (proto.name))
    170 
    171         func = []
    172         func.append("static inline void *%s_lookup_dispatch_table(const VkLayerDispatchTable *table,"
    173                 % self.prefix)
    174         func.append("%s                                           const char *name)"
    175                 % (" " * len(self.prefix)))
    176         func.append("{")
    177         func.append(generate_get_proc_addr_check("name"))
    178         func.append("")
    179         func.append("    name += 2;")
    180         func.append("    %s" % "\n    ".join(lookups))
    181         func.append("")
    182         func.append("    return NULL;")
    183         func.append("}")
    184 
    185         return "\n".join(func)
    186 
    187     def generate_body(self):
    188         body = [self._generate_init("device"),
    189                 self._generate_lookup(),
    190                 self._generate_init("instance")]
    191 
    192         return "\n\n".join(body)
    193 
    194 class WinDefFileSubcommand(Subcommand):
    195     def run(self):
    196         library_exports = {
    197                 "all": [],
    198         }
    199 
    200         if len(self.argv) != 2 or self.argv[1] not in library_exports:
    201             print("WinDefFileSubcommand: <library-name> {%s}" %
    202                     "|".join(library_exports.keys()))
    203             return
    204 
    205         self.library = self.argv[0]
    206         self.exports = library_exports[self.argv[1]]
    207 
    208         super().run()
    209 
    210     def generate_copyright(self):
    211         return """; THIS FILE IS GENERATED.  DO NOT EDIT.
    212 
    213 ;;;; Begin Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;
    214 ; Copyright (c) 2015-2016 The Khronos Group Inc.
    215 ; Copyright (c) 2015-2016 Valve Corporation
    216 ; Copyright (c) 2015-2016 LunarG, Inc.
    217 ;
    218 ; Licensed under the Apache License, Version 2.0 (the "License");
    219 ; you may not use this file except in compliance with the License.
    220 ; You may obtain a copy of the License at
    221 ;
    222 ;     http://www.apache.org/licenses/LICENSE-2.0
    223 ;
    224 ; Unless required by applicable law or agreed to in writing, software
    225 ; distributed under the License is distributed on an "AS IS" BASIS,
    226 ; WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    227 ; See the License for the specific language governing permissions and
    228 ; limitations under the License.
    229 ;
    230 ;
    231 ;  Author: Jon Ashburn <jon (at] lunarg.com>
    232 ;;;;  End Copyright Notice ;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"""
    233 
    234     def generate_header(self):
    235         return "; The following is required on Windows, for exporting symbols from the DLL"
    236 
    237     def generate_body(self):
    238         body = []
    239 
    240         body.append("LIBRARY " + self.library)
    241         body.append("EXPORTS")
    242 
    243         for proto in self.protos:
    244             if self.exports and proto.name not in self.exports:
    245                 continue
    246 #           This was intended to reject WSI calls, but actually rejects ALL extensions
    247 #           TODO:  Make this WSI-extension specific
    248 #           if proto.name.endswith("KHR"):
    249 #               continue
    250             body.append("   vk" + proto.name)
    251 
    252         return "\n".join(body)
    253 
    254 def main():
    255 
    256     wsi = {
    257             "Win32",
    258             "Android",
    259             "Xcb",
    260             "Xlib",
    261             "Wayland",
    262             "Mir"
    263     }
    264 
    265     subcommands = {
    266             "dispatch-table-ops": DispatchTableOpsSubcommand,
    267             "win-def-file": WinDefFileSubcommand,
    268     }
    269 
    270     if len(sys.argv) < 3 or sys.argv[1] not in wsi or sys.argv[2] not in subcommands:
    271         print("Usage: %s <wsi> <subcommand> [options]" % sys.argv[0])
    272         print
    273         print("Available wsi (displayservers) are: %s" % " ".join(wsi))
    274         print("Available subcommands are: %s" % " ".join(subcommands))
    275         exit(1)
    276 
    277     subcmd = subcommands[sys.argv[2]](sys.argv[3:])
    278     subcmd.run()
    279 
    280 if __name__ == "__main__":
    281     main()
    282