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