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