1#!/usr/bin/env python 2 3# Copyright 2019 The Amber Authors. All rights reserved. 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# Generates vk-wrappers.inc in the src/ directory. 18 19from __future__ import print_function 20 21import os.path 22import re 23import sys 24import xml.etree.ElementTree as ET 25from string import Template 26 27def read_inc(file): 28 methods = [] 29 pattern = re.compile(r"AMBER_VK_FUNC\((\w+)\)") 30 with open(file, 'r') as f: 31 for line in f: 32 match = pattern.search(line) 33 if match == None: 34 raise Exception("FAILED TO MATCH PATTERN"); 35 36 methods.append(match.group(1)) 37 return methods 38 39 40def read_vk(file): 41 methods = {} 42 tree = ET.parse(file) 43 root = tree.getroot(); 44 for command in root.iter("command"): 45 proto = command.find('proto') 46 if proto == None: 47 continue 48 49 return_type = proto.find('type').text 50 name = proto.find('name').text 51 52 param_list = [] 53 for param in command.findall('param'): 54 param_val = "".join(param.itertext()) 55 param_name = param.find('name').text 56 param_list.append({ 57 'def': param_val, 58 'name': param_name 59 }) 60 61 methods[name] = { 62 'return_type': return_type, 63 'name': name, 64 'params': param_list 65 } 66 67 return methods 68 69 70def gen_wrappers(methods, xml): 71 content = "" 72 for method in methods: 73 data = xml[method] 74 if data == None: 75 raise Exception("Failed to find {}".format(method)) 76 77 param_vals = [] 78 param_names = [] 79 for param in data['params']: 80 param_vals.append(param['def']) 81 param_names.append(param['name']) 82 83 signature = ', '.join(str(x) for x in param_vals) 84 arguments = ', '.join(str(x) for x in param_names) 85 return_type = data['return_type'] 86 return_variable = '' 87 call_prefix = '' 88 if return_type != 'void': 89 return_variable = 'ret' 90 call_prefix = return_type + ' ' + return_variable + ' = ' 91 92 template = Template(R'''{ 93 PFN_${method} ptr = reinterpret_cast<PFN_${method}>(getInstanceProcAddr(instance_, "${method}")); 94 if (!ptr) { 95 return Result("Vulkan: Unable to load ${method} pointer"); 96 } 97 if (delegate && delegate->LogGraphicsCalls()) { 98 ptrs_.${method} = [ptr, delegate](${signature}) -> ${return_type} { 99 delegate->Log("${method}"); 100 uint64_t timestamp_start = 0; 101 if (delegate->LogGraphicsCallsTime()) { 102 timestamp_start = delegate->GetTimestampNs(); 103 } 104 ${call_prefix}ptr(${arguments}); 105 if (delegate->LogGraphicsCallsTime()) { 106 uint64_t timestamp_end = delegate->GetTimestampNs(); 107 uint64_t duration = timestamp_end - timestamp_start; 108 std::ostringstream out; 109 out << "time "; 110 // name of method on 40 characters 111 out << std::left << std::setw(40) << "${method}"; 112 // duration in nanoseconds on 12 characters, right-aligned 113 out << std::right << std::setw(12) << duration; 114 out << " ns"; 115 delegate->Log(out.str()); 116 } 117 return ${return_variable}; 118 }; 119 } else { 120 ptrs_.${method} = [ptr](${signature}) -> ${return_type} { 121 ${call_prefix}ptr(${arguments}); 122 return ${return_variable}; 123 }; 124 } 125} 126''') 127 128 content += template.substitute(method=method, 129 signature=signature, 130 arguments=arguments, 131 return_type=return_type, 132 return_variable=return_variable, 133 call_prefix=call_prefix) 134 135 return content 136 137 138def gen_headers(methods, xml): 139 content = "" 140 for method in methods: 141 data = xml[method] 142 if data == None: 143 raise Exception("Failed to find {}".format(method)) 144 145 param_vals = [] 146 param_names = [] 147 for param in data['params']: 148 param_vals.append(param['def']) 149 param_names.append(param['name']) 150 151 content += "std::function<{}({})> {};\n".format(data['return_type'], 152 ', '.join(str(x) for x in param_vals), method) 153 154 return content 155 156 157def gen_direct(methods): 158 content = ""; 159 160 template = Template(R''' 161if (!(ptrs_.${method} = reinterpret_cast<PFN_${method}>(getInstanceProcAddr(instance_, "${method}")))) { 162 return Result("Vulkan: Unable to load ${method} pointer"); 163} 164''') 165 166 for method in methods: 167 content += template.substitute(method=method) 168 169 return content 170 171 172def gen_direct_headers(methods): 173 content = "" 174 for method in methods: 175 content += "PFN_{} {};\n".format(method, method); 176 177 return content 178 179 180def main(): 181 if len(sys.argv) != 3: 182 print('usage: {} <outdir> <src_dir>'.format( 183 sys.argv[0])) 184 sys.exit(1) 185 186 outdir = sys.argv[1] 187 srcdir = sys.argv[2] 188 189 vulkan_versions = ("1-0", "1-1") 190 191 for vulkan_version in vulkan_versions: 192 193 vkfile = os.path.join(srcdir, 'third_party', 'vulkan-headers', 'registry', 'vk.xml') 194 incfile = os.path.join(srcdir, 'src', 'vulkan', 'vk-funcs-%s.inc' % vulkan_version) 195 196 data = read_inc(incfile) 197 198 wrapper_content = '' 199 header_content = '' 200 if os.path.isfile(vkfile): 201 vk_data = read_vk(vkfile) 202 wrapper_content = gen_wrappers(data, vk_data) 203 header_content = gen_headers(data, vk_data) 204 else: 205 wrapper_content = gen_direct(data) 206 header_content = gen_direct_headers(data) 207 208 outfile = os.path.join(outdir, 'vk-wrappers-%s.inc' % vulkan_version) 209 if os.path.isfile(outfile): 210 with open(outfile, 'r') as f: 211 if wrapper_content == f.read(): 212 return 213 with open(outfile, 'w') as f: 214 f.write(wrapper_content) 215 216 hdrfile = os.path.join(outdir, 'vk-wrappers-%s.h' % vulkan_version) 217 if os.path.isfile(hdrfile): 218 with open(hdrfile, 'r') as f: 219 if header_content == f.read(): 220 return 221 with open(hdrfile, 'w') as f: 222 f.write(header_content) 223 224 225if __name__ == '__main__': 226 main() 227