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