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@lunarg.com> 20# 21 22import os, sys 23 24# add main repo directory so vulkan.py can be imported. This needs to be a complete path. 25ld_path = os.path.dirname(os.path.abspath(__file__)) 26main_path = os.path.abspath(ld_path + "/../") 27sys.path.append(main_path) 28 29import vulkan 30 31def generate_get_proc_addr_check(name): 32 return " if (!%s || %s[0] != 'v' || %s[1] != 'k')\n" \ 33 " return NULL;" % ((name,) * 3) 34 35class 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@lunarg.com> 105 * Author: Chia-I Wu <olv@lunarg.com> 106 * Author: Courtney Goeltzenleuchter <courtney@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 118class 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 194class 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@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 254def 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 280if __name__ == "__main__": 281 main() 282