1bf215546Sopenharmony_ciCOPYRIGHT=u"""
2bf215546Sopenharmony_ci/* Copyright © 2021 Intel Corporation
3bf215546Sopenharmony_ci *
4bf215546Sopenharmony_ci * Permission is hereby granted, free of charge, to any person obtaining a
5bf215546Sopenharmony_ci * copy of this software and associated documentation files (the "Software"),
6bf215546Sopenharmony_ci * to deal in the Software without restriction, including without limitation
7bf215546Sopenharmony_ci * the rights to use, copy, modify, merge, publish, distribute, sublicense,
8bf215546Sopenharmony_ci * and/or sell copies of the Software, and to permit persons to whom the
9bf215546Sopenharmony_ci * Software is furnished to do so, subject to the following conditions:
10bf215546Sopenharmony_ci *
11bf215546Sopenharmony_ci * The above copyright notice and this permission notice (including the next
12bf215546Sopenharmony_ci * paragraph) shall be included in all copies or substantial portions of the
13bf215546Sopenharmony_ci * Software.
14bf215546Sopenharmony_ci *
15bf215546Sopenharmony_ci * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16bf215546Sopenharmony_ci * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17bf215546Sopenharmony_ci * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.  IN NO EVENT SHALL
18bf215546Sopenharmony_ci * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19bf215546Sopenharmony_ci * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
20bf215546Sopenharmony_ci * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
21bf215546Sopenharmony_ci * IN THE SOFTWARE.
22bf215546Sopenharmony_ci */
23bf215546Sopenharmony_ci"""
24bf215546Sopenharmony_ci
25bf215546Sopenharmony_ciimport argparse
26bf215546Sopenharmony_ciimport os
27bf215546Sopenharmony_cifrom collections import OrderedDict, namedtuple
28bf215546Sopenharmony_ciimport xml.etree.ElementTree as et
29bf215546Sopenharmony_ci
30bf215546Sopenharmony_cifrom mako.template import Template
31bf215546Sopenharmony_ci
32bf215546Sopenharmony_ciTEMPLATE_C = Template(COPYRIGHT + """
33bf215546Sopenharmony_ci/* This file generated from ${filename}, don't edit directly. */
34bf215546Sopenharmony_ci
35bf215546Sopenharmony_ci#include "vk_log.h"
36bf215546Sopenharmony_ci#include "vk_physical_device.h"
37bf215546Sopenharmony_ci#include "vk_util.h"
38bf215546Sopenharmony_ci
39bf215546Sopenharmony_cistatic VkResult
40bf215546Sopenharmony_cicheck_physical_device_features(struct vk_physical_device *physical_device,
41bf215546Sopenharmony_ci                               const VkPhysicalDeviceFeatures *supported,
42bf215546Sopenharmony_ci                               const VkPhysicalDeviceFeatures *enabled,
43bf215546Sopenharmony_ci                               const char *struct_name)
44bf215546Sopenharmony_ci{
45bf215546Sopenharmony_ci% for flag in pdev_features:
46bf215546Sopenharmony_ci   if (enabled->${flag} && !supported->${flag})
47bf215546Sopenharmony_ci      return vk_errorf(physical_device, VK_ERROR_FEATURE_NOT_PRESENT,
48bf215546Sopenharmony_ci                       "%s.%s not supported", struct_name, "${flag}");
49bf215546Sopenharmony_ci% endfor
50bf215546Sopenharmony_ci
51bf215546Sopenharmony_ci   return VK_SUCCESS;
52bf215546Sopenharmony_ci}
53bf215546Sopenharmony_ci
54bf215546Sopenharmony_ciVkResult
55bf215546Sopenharmony_civk_physical_device_check_device_features(struct vk_physical_device *physical_device,
56bf215546Sopenharmony_ci                                         const VkDeviceCreateInfo *pCreateInfo)
57bf215546Sopenharmony_ci{
58bf215546Sopenharmony_ci   VkPhysicalDevice vk_physical_device =
59bf215546Sopenharmony_ci      vk_physical_device_to_handle(physical_device);
60bf215546Sopenharmony_ci
61bf215546Sopenharmony_ci   /* Query the device what kind of features are supported. */
62bf215546Sopenharmony_ci   VkPhysicalDeviceFeatures2 supported_features2 = {
63bf215546Sopenharmony_ci      .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2,
64bf215546Sopenharmony_ci   };
65bf215546Sopenharmony_ci
66bf215546Sopenharmony_ci% for f in features:
67bf215546Sopenharmony_ci   ${f.name} supported_${f.name} = { .pNext = NULL };
68bf215546Sopenharmony_ci% endfor
69bf215546Sopenharmony_ci
70bf215546Sopenharmony_ci   vk_foreach_struct_const(feat, pCreateInfo->pNext) {
71bf215546Sopenharmony_ci      VkBaseOutStructure *supported = NULL;
72bf215546Sopenharmony_ci      switch (feat->sType) {
73bf215546Sopenharmony_ci% for f in features:
74bf215546Sopenharmony_ci      case ${f.vk_type}:
75bf215546Sopenharmony_ci         supported = (VkBaseOutStructure *) &supported_${f.name};
76bf215546Sopenharmony_ci         break;
77bf215546Sopenharmony_ci% endfor
78bf215546Sopenharmony_ci      default:
79bf215546Sopenharmony_ci         break;
80bf215546Sopenharmony_ci      }
81bf215546Sopenharmony_ci
82bf215546Sopenharmony_ci      /* Not a feature struct. */
83bf215546Sopenharmony_ci      if (!supported)
84bf215546Sopenharmony_ci         continue;
85bf215546Sopenharmony_ci
86bf215546Sopenharmony_ci      /* Check for cycles in the list */
87bf215546Sopenharmony_ci      if (supported->pNext != NULL || supported->sType != 0)
88bf215546Sopenharmony_ci         return VK_ERROR_UNKNOWN;
89bf215546Sopenharmony_ci
90bf215546Sopenharmony_ci      supported->sType = feat->sType;
91bf215546Sopenharmony_ci      __vk_append_struct(&supported_features2, supported);
92bf215546Sopenharmony_ci   }
93bf215546Sopenharmony_ci
94bf215546Sopenharmony_ci   physical_device->dispatch_table.GetPhysicalDeviceFeatures2(
95bf215546Sopenharmony_ci      vk_physical_device, &supported_features2);
96bf215546Sopenharmony_ci
97bf215546Sopenharmony_ci   if (pCreateInfo->pEnabledFeatures) {
98bf215546Sopenharmony_ci      VkResult result =
99bf215546Sopenharmony_ci        check_physical_device_features(physical_device,
100bf215546Sopenharmony_ci                                       &supported_features2.features,
101bf215546Sopenharmony_ci                                       pCreateInfo->pEnabledFeatures,
102bf215546Sopenharmony_ci                                       "VkPhysicalDeviceFeatures");
103bf215546Sopenharmony_ci      if (result != VK_SUCCESS)
104bf215546Sopenharmony_ci         return result;
105bf215546Sopenharmony_ci   }
106bf215546Sopenharmony_ci
107bf215546Sopenharmony_ci   /* Iterate through additional feature structs */
108bf215546Sopenharmony_ci   vk_foreach_struct_const(feat, pCreateInfo->pNext) {
109bf215546Sopenharmony_ci      /* Check each feature boolean for given structure. */
110bf215546Sopenharmony_ci      switch (feat->sType) {
111bf215546Sopenharmony_ci      case VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2: {
112bf215546Sopenharmony_ci         const VkPhysicalDeviceFeatures2 *features2 = (const void *)feat;
113bf215546Sopenharmony_ci         VkResult result =
114bf215546Sopenharmony_ci            check_physical_device_features(physical_device,
115bf215546Sopenharmony_ci                                           &supported_features2.features,
116bf215546Sopenharmony_ci                                           &features2->features,
117bf215546Sopenharmony_ci                                           "VkPhysicalDeviceFeatures2.features");
118bf215546Sopenharmony_ci         if (result != VK_SUCCESS)
119bf215546Sopenharmony_ci            return result;
120bf215546Sopenharmony_ci        break;
121bf215546Sopenharmony_ci      }
122bf215546Sopenharmony_ci% for f in features:
123bf215546Sopenharmony_ci      case ${f.vk_type} : {
124bf215546Sopenharmony_ci         ${f.name} *a = &supported_${f.name};
125bf215546Sopenharmony_ci         ${f.name} *b = (${f.name} *) feat;
126bf215546Sopenharmony_ci% for flag in f.vk_flags:
127bf215546Sopenharmony_ci         if (b->${flag} && !a->${flag})
128bf215546Sopenharmony_ci            return vk_errorf(physical_device, VK_ERROR_FEATURE_NOT_PRESENT,
129bf215546Sopenharmony_ci                             "%s.%s not supported", "${f.name}", "${flag}");
130bf215546Sopenharmony_ci% endfor
131bf215546Sopenharmony_ci         break;
132bf215546Sopenharmony_ci      }
133bf215546Sopenharmony_ci% endfor
134bf215546Sopenharmony_ci      default:
135bf215546Sopenharmony_ci         break;
136bf215546Sopenharmony_ci      }
137bf215546Sopenharmony_ci   } // for each extension structure
138bf215546Sopenharmony_ci   return VK_SUCCESS;
139bf215546Sopenharmony_ci}
140bf215546Sopenharmony_ci
141bf215546Sopenharmony_ci""", output_encoding='utf-8')
142bf215546Sopenharmony_ci
143bf215546Sopenharmony_ciFeature = namedtuple('Feature', 'name vk_type vk_flags')
144bf215546Sopenharmony_ci
145bf215546Sopenharmony_cidef get_pdev_features(doc):
146bf215546Sopenharmony_ci    for _type in doc.findall('./types/type'):
147bf215546Sopenharmony_ci        if _type.attrib.get('name') != 'VkPhysicalDeviceFeatures':
148bf215546Sopenharmony_ci            continue
149bf215546Sopenharmony_ci
150bf215546Sopenharmony_ci        flags = []
151bf215546Sopenharmony_ci
152bf215546Sopenharmony_ci        for p in _type.findall('./member'):
153bf215546Sopenharmony_ci            assert p.find('./type').text == 'VkBool32'
154bf215546Sopenharmony_ci            flags.append(p.find('./name').text)
155bf215546Sopenharmony_ci
156bf215546Sopenharmony_ci        return flags
157bf215546Sopenharmony_ci
158bf215546Sopenharmony_ci    return None
159bf215546Sopenharmony_ci
160bf215546Sopenharmony_cidef get_features(doc):
161bf215546Sopenharmony_ci    features = OrderedDict()
162bf215546Sopenharmony_ci
163bf215546Sopenharmony_ci    provisional_structs = set()
164bf215546Sopenharmony_ci
165bf215546Sopenharmony_ci    # we want to ignore struct types that are part of provisional extensions
166bf215546Sopenharmony_ci    for _extension in doc.findall('./extensions/extension'):
167bf215546Sopenharmony_ci        if _extension.attrib.get('provisional') != 'true':
168bf215546Sopenharmony_ci            continue
169bf215546Sopenharmony_ci        for p in _extension.findall('./require/type'):
170bf215546Sopenharmony_ci            provisional_structs.add(p.attrib.get('name'))
171bf215546Sopenharmony_ci
172bf215546Sopenharmony_ci    # parse all struct types where structextends VkPhysicalDeviceFeatures2
173bf215546Sopenharmony_ci    for _type in doc.findall('./types/type'):
174bf215546Sopenharmony_ci        if _type.attrib.get('category') != 'struct':
175bf215546Sopenharmony_ci            continue
176bf215546Sopenharmony_ci        if _type.attrib.get('structextends') != 'VkPhysicalDeviceFeatures2,VkDeviceCreateInfo':
177bf215546Sopenharmony_ci            continue
178bf215546Sopenharmony_ci        if _type.attrib.get('name') in provisional_structs:
179bf215546Sopenharmony_ci            continue
180bf215546Sopenharmony_ci
181bf215546Sopenharmony_ci        # find Vulkan structure type
182bf215546Sopenharmony_ci        for elem in _type:
183bf215546Sopenharmony_ci            if "STRUCTURE_TYPE" in str(elem.attrib):
184bf215546Sopenharmony_ci                s_type = elem.attrib.get('values')
185bf215546Sopenharmony_ci
186bf215546Sopenharmony_ci        # collect a list of feature flags
187bf215546Sopenharmony_ci        flags = []
188bf215546Sopenharmony_ci
189bf215546Sopenharmony_ci        for p in _type.findall('./member'):
190bf215546Sopenharmony_ci            m_name = p.find('./name').text
191bf215546Sopenharmony_ci            if m_name == 'pNext':
192bf215546Sopenharmony_ci                pass
193bf215546Sopenharmony_ci            elif m_name == 'sType':
194bf215546Sopenharmony_ci                s_type = p.attrib.get('values')
195bf215546Sopenharmony_ci            else:
196bf215546Sopenharmony_ci                assert p.find('./type').text == 'VkBool32'
197bf215546Sopenharmony_ci                flags.append(m_name)
198bf215546Sopenharmony_ci
199bf215546Sopenharmony_ci        feat = Feature(name=_type.attrib.get('name'), vk_type=s_type, vk_flags=flags)
200bf215546Sopenharmony_ci        features[_type.attrib.get('name')] = feat
201bf215546Sopenharmony_ci
202bf215546Sopenharmony_ci    return features.values()
203bf215546Sopenharmony_ci
204bf215546Sopenharmony_cidef get_features_from_xml(xml_files):
205bf215546Sopenharmony_ci    pdev_features = None
206bf215546Sopenharmony_ci    features = []
207bf215546Sopenharmony_ci
208bf215546Sopenharmony_ci    for filename in xml_files:
209bf215546Sopenharmony_ci        doc = et.parse(filename)
210bf215546Sopenharmony_ci        features += get_features(doc)
211bf215546Sopenharmony_ci        if not pdev_features:
212bf215546Sopenharmony_ci            pdev_features = get_pdev_features(doc)
213bf215546Sopenharmony_ci
214bf215546Sopenharmony_ci    return pdev_features, features
215bf215546Sopenharmony_ci
216bf215546Sopenharmony_ci
217bf215546Sopenharmony_cidef main():
218bf215546Sopenharmony_ci    parser = argparse.ArgumentParser()
219bf215546Sopenharmony_ci    parser.add_argument('--out-c', required=True, help='Output C file.')
220bf215546Sopenharmony_ci    parser.add_argument('--xml',
221bf215546Sopenharmony_ci                        help='Vulkan API XML file.',
222bf215546Sopenharmony_ci                        required=True, action='append', dest='xml_files')
223bf215546Sopenharmony_ci    args = parser.parse_args()
224bf215546Sopenharmony_ci
225bf215546Sopenharmony_ci    pdev_features, features = get_features_from_xml(args.xml_files)
226bf215546Sopenharmony_ci
227bf215546Sopenharmony_ci    environment = {
228bf215546Sopenharmony_ci        'filename': os.path.basename(__file__),
229bf215546Sopenharmony_ci        'pdev_features': pdev_features,
230bf215546Sopenharmony_ci        'features': features,
231bf215546Sopenharmony_ci    }
232bf215546Sopenharmony_ci
233bf215546Sopenharmony_ci    try:
234bf215546Sopenharmony_ci        with open(args.out_c, 'wb') as f:
235bf215546Sopenharmony_ci            f.write(TEMPLATE_C.render(**environment))
236bf215546Sopenharmony_ci    except Exception:
237bf215546Sopenharmony_ci        # In the event there's an error, this imports some helpers from mako
238bf215546Sopenharmony_ci        # to print a useful stack trace and prints it, then exits with
239bf215546Sopenharmony_ci        # status 1, if python is run with debug; otherwise it just raises
240bf215546Sopenharmony_ci        # the exception
241bf215546Sopenharmony_ci        import sys
242bf215546Sopenharmony_ci        from mako import exceptions
243bf215546Sopenharmony_ci        print(exceptions.text_error_template().render(), file=sys.stderr)
244bf215546Sopenharmony_ci        sys.exit(1)
245bf215546Sopenharmony_ci
246bf215546Sopenharmony_ciif __name__ == '__main__':
247bf215546Sopenharmony_ci    main()
248