• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1#!/usr/bin/python3 -i
2#
3# Copyright 2020-2024 The Khronos Group Inc.
4#
5# SPDX-License-Identifier: Apache-2.0
6
7# Description:
8# -----------
9# This script generates a .hpp file that can be included in an application
10# to generate json data that can then be used to generate the pipeline cache.
11
12import os
13import re
14import xml.dom.minidom
15from generator import (GeneratorOptions, OutputGenerator, noneStr,
16                       regSortFeatures, write)
17
18copyright = """
19/*
20** Copyright 2020-2024 The Khronos Group Inc.
21**
22** SPDX-License-Identifier: Apache-2.0
23*/
24"""
25
26predefinedCode = """
27/********************************************************************************************/
28/** This code is generated. To make changes, please modify the scripts or the relevant xml **/
29/********************************************************************************************/
30
31#pragma once
32
33#include <stdio.h>
34#include <string.h>
35#include <assert.h>
36#include <inttypes.h>
37#include <vulkan/vulkan.h>
38#include "vulkan_json_gen.h"
39
40#define MAX_SIZE 255 // We don't expect to write a bigger string at a time.
41#define MAX_JSON_SIZE 1024*1024 // We don't expect the entire JSON file to be bigger than this.
42
43static int s_num_spaces = 0;
44static char s_tempBuf[MAX_SIZE];
45static char s_outBuf[MAX_JSON_SIZE];
46static char *s_writePtr = s_outBuf;
47
48#define _OUT s_tempBuf
49
50#define UPDATE_BUF strncpy(s_writePtr, s_tempBuf, strnlen(s_tempBuf, MAX_SIZE)); s_writePtr += strnlen(s_tempBuf, MAX_SIZE);
51
52// Variadic macro for neat buffer update + print.
53#define vk_json_printf(...) { sprintf(__VA_ARGS__); UPDATE_BUF }
54
55// Helper utility to do indentation in the generated json file.
56#define PRINT_SPACE \
57{ \\
58    int spaces; \\
59    for (spaces = 0; spaces < s_num_spaces; spaces++) \\
60        vk_json_printf(_OUT, " "); \\
61}
62
63
64#define INDENT(sz) s_num_spaces += (sz);
65
66const char* getJSONOutput()
67{
68    return s_outBuf;
69}
70
71void resetJSONOutput(void)
72{
73    memset(s_outBuf, 0x00, MAX_JSON_SIZE);
74    s_writePtr = s_outBuf;
75}
76
77"""
78
79printVal = """
80void print_@name(const @name * obj, const char* s, int commaNeeded) {
81    PRINT_SPACE
82    if (s[0] != 0) {
83        vk_json_printf(_OUT, \"\\\"%s\\\" : FORMAT%s\\n\", s, *obj, commaNeeded ? \",\" : \"\");
84    } else {
85        vk_json_printf(_OUT, \"FORMAT%s\\n", *obj, commaNeeded ? \",\" : \"\");
86    }
87}
88"""
89
90class JSONCGeneratorOptions(GeneratorOptions):
91    """JSONCGeneratorOptions - subclass of GeneratorOptions.
92
93    Adds options used by JSONCOutputGenerator objects during C language header
94    generation."""
95
96    def __init__(self,
97                 prefixText="",
98                 genFuncPointers=True,
99                 protectFile=True,
100                 protectFeature=True,
101                 protectProto=None,
102                 protectProtoStr=None,
103                 apicall='',
104                 apientry='',
105                 apientryp='',
106                 indentFuncProto=True,
107                 indentFuncPointer=False,
108                 alignFuncParam=0,
109                 genEnumBeginEndRange=False,
110                 genAliasMacro=False,
111                 aliasMacro='',
112                 **kwargs
113                 ):
114
115        GeneratorOptions.__init__(self, **kwargs)
116
117
118class JSONCOutputGenerator(OutputGenerator):
119    # This is an ordered list of sections in the header file.
120    TYPE_SECTIONS = ['basetype', 'handle', 'enum',
121                     'group', 'bitmask', 'struct']
122    ALL_SECTIONS = TYPE_SECTIONS
123
124    def __init__(self, *args, **kwargs):
125        super().__init__(*args, **kwargs)
126        # Internal state - accumulators for different inner block text
127        self.sections = {section: [] for section in self.ALL_SECTIONS}
128        self.feature_not_empty = False
129        self.may_alias         = None
130        self.featureDict       = {}
131        self.vkscFeatureList   = []
132        self.enumNames         = []
133        self.baseTypeDict      = {
134                                  "int32_t"  : "%d",
135                                  "uint32_t" : "%u",
136                                  "uint8_t"  : "%u",
137                                  "uint64_t" : "%\" PRIu64 \"",
138                                  "float"    : "%f",
139                                  "int"      : "%d",
140                                  "double"   : "%lf",
141                                  "int64_t"  : "%\" PRId64 \"",
142                                  "uint16_t" : "%u",
143                                  "char"     : "%c",
144                                  "size_t"   : "%zu"
145                                  }
146
147    def printBaseTypes(self):
148        for baseType in self.baseTypeDict:
149            temp = printVal
150            temp = printVal.replace("@name", baseType)
151            temp = temp.replace("FORMAT", self.baseTypeDict[baseType])
152            write(temp, file=self.outFile)
153
154    def genStructExtensionCode(self):
155       code  = ""
156       code += "void dumpPNextChain(const void* pNext) {\n"
157       code += "      VkBaseInStructure *pBase = (VkBaseInStructure*)pNext;\n"
158       code += "      if (pNext) {\n"
159       code += "          PRINT_SPACE\n"
160       code += "          vk_json_printf(_OUT, \"\\\"pNext\\\":\\n\");\n"
161       code += "          switch (pBase->sType) {\n"
162
163       typesList = self.registry.reg.findall('types')
164       currentExtension = "VK_VERSION_1_0"
165       for types in typesList:
166           typeList = types.findall("type")
167           for type in typeList:
168               if type.get('category') == 'struct' and type.get('structextends') is not None and type.get('name') in self.vkscFeatureList:
169                   members = type.findall('member')
170                   for m in members:
171                       n = type.get('name')
172                       if m.get('values'):
173                           if n in self.featureDict and currentExtension != self.featureDict[n]:
174                               if currentExtension != "VK_VERSION_1_0":
175                                   code += "#endif\n"
176                               currentExtension = self.featureDict[n]
177                               if self.featureDict[n] != "VK_VERSION_1_0":
178                                   code += "#ifdef %s\n" %(currentExtension)
179                           code += "             case %s:" %(m.get('values'))
180                           code += "print_%s(((%s *)pNext), \"%s\", 1);\n" %(n, n, n)
181                           code += "             break;\n"
182
183       if currentExtension != "VK_VERSION_1_0":
184            code += "#endif\n"
185       code += "             default: assert(!\"No structure type matching!\");\n"
186       code += "         }\n"
187       code += "     }\n"
188       code += "  }\n"
189
190       return code
191
192    def createvkscFeatureList(self):
193        for feature in self.registry.reg.findall('feature'):
194            if feature.get('api').find('vulkansc') != -1:
195                # Remove entries that are removed in features in VKSC profile.
196                requiredList = feature.findall("require")
197
198                for requiredItem in requiredList:
199                    typeList = requiredItem.findall("type")
200                    for typeName in typeList:
201                        if typeName.get("name") != "":
202                            self.featureDict[typeName.get("name")] = feature.get("name")
203                            self.vkscFeatureList.append(typeName.get("name"))
204
205                removeItemList = feature.findall("remove")
206                for removeItem in removeItemList:
207                    removeTypes = removeItem.findall("type")
208                    for item in removeTypes:
209                        if self.vkscFeatureList.count(item.get("name")) > 0:
210                            self.vkscFeatureList.remove(item.get("name"))
211
212        allExtensions = self.registry.reg.findall('extensions')
213        for extensions in allExtensions:
214            extensionList = extensions.findall("extension")
215            for extension in extensionList:
216                if extension.get("supported").find("vulkansc") != -1:
217                    requiredList = extension.findall("require")
218                    for requiredItem in requiredList:
219                        typeList = requiredItem.findall("type")
220                        for typeName in typeList:
221                            self.featureDict[typeName.get("name")] = extension.get("name")
222                            self.vkscFeatureList.append(typeName.get("name"))
223
224    def beginFile(self, genOpts):
225        OutputGenerator.beginFile(self, genOpts)
226        self.createvkscFeatureList()
227
228        write(copyright, file=self.outFile)
229        write(predefinedCode, file=self.outFile)
230        self.printBaseTypes()
231
232        write(self.genStructExtensionCode(), file=self.outFile)
233
234    def endFile(self):
235        OutputGenerator.endFile(self)
236
237    def beginFeature(self, interface, emit):
238        OutputGenerator.beginFeature(self, interface, emit)
239        self.sections = {section: [] for section in self.ALL_SECTIONS}
240        self.feature_not_empty = False
241
242    def endFeature(self):
243        if self.emit:
244            if self.feature_not_empty:
245                if self.genOpts.conventions.writeFeature(self.featureExtraProtect, self.genOpts.filename):
246
247                    for section in self.TYPE_SECTIONS:
248                        contents = self.sections[section]
249                        if contents:
250                            write('\n'.join(contents), file=self.outFile)
251
252        # Finish processing in superclass
253        OutputGenerator.endFeature(self)
254
255    def appendSection(self, section, text, extension):
256        if extension != "VK_VERSION_1_0":
257            self.sections[section].append("#ifdef %s" %(extension))
258        self.sections[section].append(text)
259        self.feature_not_empty = True
260        if extension != "VK_VERSION_1_0":
261            self.sections[section].append("#endif")
262
263    def genEnumData(self, name, obj):
264        code = ""
265        code += "     if (strncmp(str, \"\", 255)) vk_json_printf(_OUT, \"\\\"%s\\\" : \", str);\n"
266        code += "     vk_json_printf(_OUT, \"\\\"%%s\\\"%%s\\n\", %s_map(*%sobj), commaNeeded ? \",\" : \"\");\n" %(name, obj)
267        return code
268
269    def genEnumCode(self, name):
270        code = ""
271        code += "void print_%s(const %s* obj, const char* str, int commaNeeded) {\n" %(name, name)
272        code += "     PRINT_SPACE\n"
273        code += self.genEnumData(name, "")
274        code += "}\n"
275
276        return code
277
278    def genBasetypeCode(self, str1, str2, name, baseType):
279        code = ""
280        code += "void print_" + name + "(" + str1 + name + str2 + " const char* str, int commaNeeded) {\n"
281        code += "     PRINT_SPACE\n"
282        if name == "VkBool32":
283            code += "     vk_json_printf(_OUT, \"\\\"%s\\\" : \\\"%s\\\"%s\\n\", str, (*obj == 0) ? (\"VK_FALSE\") : (\"VK_TRUE\"), commaNeeded ? \",\" : \"\");\n"
284        else:
285            code += "     vk_json_printf(_OUT, \"\\\"%s\\\" : \\\"" + self.baseTypeDict[baseType] + "\\\"%s\\n\", str, *obj, commaNeeded ? \",\" : \"\");\n"
286        code += "}\n"
287        return code
288
289    def genHandleCode(self, str1, str2, name):
290        code = ""
291        code += "void print_%s(%s%s%s const char* str, int commaNeeded) {\n" %(name, str1, name, str2)
292        code += "     (void)%s;\n" %(str2[:-1])
293        code += "     PRINT_SPACE\n"
294        code += "     vk_json_printf(_OUT, \"\\\"%s\\\"%s\\n\", str, commaNeeded ? \",\" : \"\");\n"
295        code += "}\n"
296        return code
297
298    def genBitmaskCode(self, str1, str2, name, mapName):
299        if mapName is not None:
300            code = ""
301            code += "void print_%s(%s%s%s const char* str, int commaNeeded) {\n" %(name, str1, name, str2)
302            code += "     const unsigned int max_bits = 64; \n"
303            code += "     unsigned int _count = 0;\n"
304            code += "     unsigned int checkBit = 1;\n"
305            code += "     unsigned int i = 0;\n"
306            code += "     unsigned int bitCount = 0;\n"
307            code += "     unsigned int n = *obj;\n"
308            code += "     unsigned int b = *obj;\n"
309            code += "     unsigned int res = 0;\n"
310            code += "     PRINT_SPACE\n"
311            code += "     vk_json_printf(_OUT, \"\\\"%s\\\" : \", str);\n"
312            code += "     while (n) {\n"
313            code += "        n &= (n-1);\n"
314            code += "        _count++;\n"
315            code += "     }\n"
316            code += "     vk_json_printf(_OUT, \"\\\"\");\n"
317            code += "     if (*obj == 0) vk_json_printf(_OUT, \"0\");\n"
318            #We need bitpos here, so just iterate fully.
319            code += "     for (i = 0, bitCount = 0; i < max_bits; i++, checkBit <<= 1) {\n"
320            code += "         res = b & checkBit;\n"
321            code += "         if (res) {\n"
322            code += "             bitCount++;\n"
323            code += "             if (bitCount < _count) {\n"
324            code += "                 vk_json_printf(_OUT, \"%%s | \", %s_map(1<<i));\n" %(mapName)
325            code += "             } else {\n"
326            code += "                 vk_json_printf(_OUT, \"%%s\", %s_map(1<<i));\n" %(mapName)
327            code += "             }\n"
328            code += "         }\n"
329            code += "     }\n"
330            code += "     vk_json_printf(_OUT, \"\\\"%s\\n\", commaNeeded ? \",\" : \"\");\n"
331            code += "}\n"
332
333        else:
334            code = ""
335            code += "void print_%s(%s%s%s const char* str, int commaNeeded) {\n" %(name, str1, name, str2)
336            code += "     PRINT_SPACE\n"
337            code += "     vk_json_printf(_OUT, \"\\\"%s\\\" : \\\"%d\\\"%s\\n\", str, (int)(*obj), commaNeeded ? \",\" : \"\");\n"
338            code += "}\n"
339
340        return code
341
342    def genType(self, typeinfo, name, alias):
343        OutputGenerator.genType(self, typeinfo, name, alias)
344        typeElem = typeinfo.elem
345        body = ""
346
347        category = typeElem.get('category')
348        if category == 'funcpointer':
349            section = 'struct'
350        else:
351            section = category
352
353        extension = "VK_VERSION_1_0"
354        if (name in self.featureDict):
355            extension = self.featureDict[name]
356
357        if category in ('struct', 'union'):
358            self.genStruct(typeinfo, name, alias)
359        else:
360            if typeElem.get('category') == 'bitmask':
361                for elem in typeElem:
362                    if elem.tag == 'name':
363                        body += self.genBitmaskCode("const ", " * obj,", elem.text, typeElem.get('requires'))
364
365            elif typeElem.get('category') == 'basetype':
366                    body += self.genBasetypeCode("const ", " * obj,", typeElem.find('name').text, typeElem.find('type').text)
367
368            elif typeElem.get('category') == 'handle':
369                    for elem in typeElem:
370                        if elem.tag == 'name':
371                            body += self.genHandleCode("const ", "  * obj,", elem.text)
372            if body:
373                self.appendSection(section, body, extension)
374
375    def paramIsStruct(self, memberType):
376        if str(self.getTypeCategory(memberType)) == 'struct':
377            return 1
378        return 0
379
380    # Helper taken from the validation layers code.
381    def paramIsPointer(self, param):
382        ispointer = False
383        for elem in param:
384            if elem.tag == 'type' and elem.tail is not None and '*' in elem.tail:
385                ispointer = True
386        return ispointer
387
388    # Helper taken from the validation layers code.
389    def paramIsStaticArray(self, param):
390        isstaticarray = 0
391        paramname = param.find('name')
392        if (paramname.tail is not None) and ('[' in paramname.tail) and (']' in paramname.tail):
393            isstaticarray = paramname.tail.count('[')
394            if isstaticarray:
395                arraySize = paramname.tail[1]
396
397        if isstaticarray:
398            return arraySize
399        else:
400            return 0
401
402    def generateStructMembercode(self, param, str1, str2, str3, str4, memberName, typeName, isCommaNeeded):
403        length = ""
404        code = ""
405        comma = "," if isCommaNeeded else ""
406        isArr = param.get('len') is not None
407
408        if param.get('len') is not None:
409            length = str2 + param.get('len')
410
411        if  re.search(r'\d', length) is None: derefPtr = "*"
412        else:                                 derefPtr = ""
413
414        code += "     PRINT_SPACE\n"
415        code += "     vk_json_printf(_OUT, \"\\\"%s\\\" :\");\n" %(memberName)
416
417        if self.paramIsPointer(param): code += str4 + memberName + ") {\n"
418        else:                          code += "     {\n"
419        if isArr:                      code += "         unsigned int i = 0;\n"
420        code += "         vk_json_printf(_OUT, \"\\n\");\n"
421
422        # TODO: With some tweak, we can use the genArrayCode() here.
423        if isArr is True:
424            code += "         PRINT_SPACE\n"
425            code += "         vk_json_printf(_OUT, \"[\\n\");\n"
426            code += "         for (i = 0; i < %s(%s); i++) {\n" %(derefPtr, length)
427            code += "             if (i+1 == %s(%s))\n" %(derefPtr, length)
428            code += "                 print_%s(%s%s[i], \"%s\", 0);\n" %(typeName, str2, memberName, memberName)
429            code += "             else\n"
430            code += "                 print_%s(%s%s[i], \"%s\", 1);\n" %(typeName, str2, memberName, memberName)
431            code += "         }\n"
432            code += "         PRINT_SPACE\n"
433            code += "         vk_json_printf(_OUT, \"]%s\\n\");\n" % comma
434            code += "     }\n"
435        elif self.paramIsPointer(param):
436            code += "         print_%s(*(%s%s), \"%s\", %s);\n" %(typeName, str2, memberName, memberName, str(isCommaNeeded))
437            code += "     }\n"
438
439        else:
440            code += "         print_%s(%s%s, \"%s\", %s);\n" %(typeName, str2, memberName, memberName, str(isCommaNeeded))
441            code += "     }\n"
442
443        if self.paramIsPointer(param):
444            code += "     else \n"
445            code += "     {\n"
446            code += "         vk_json_printf(_OUT, \" \\\"NULL\\\"%s\\n\");\n" % comma
447            code += "     }\n"
448
449        return code
450
451    def genPNextCode(self, str2):
452        code  = ""
453        code += "     if (obj->pNext) {\n"
454        code += "         dumpPNextChain(obj->pNext);\n"
455        code += "     } else {\n"
456        code += "         PRINT_SPACE\n"
457        code += "         vk_json_printf(_OUT, \"\\\"pNext\\\" : \\\"NULL\\\",\\n\");\n"
458        code += "     }\n"
459
460        return code
461
462    # TODO: This may need to be relaxed in the schema. The schema could say array of integers,
463    # but we will print the extra strings to show them
464    def genArrayCode(self, name, typeName, str2, arraySize, needStrPrint, isCommaNeeded):
465            comma = "," if isCommaNeeded else ""
466            code = ""
467            printStr  = "\"\""
468            arraySize = arraySize.replace(')', '')
469            derefPtr = "*"
470            if arraySize.find("VK") != -1 or re.search(r'\d', arraySize) is not None:
471                derefPtr = ""
472
473            code += "     PRINT_SPACE\n"
474            code += "     vk_json_printf(_OUT, \"\\\"%s\\\" :\");\n" %(name)
475            code += "     if (obj->%s) {\n" %(name)
476            code += "        bool isCommaNeeded = false;\n"
477            code += "        unsigned int i = 0;\n"
478            code += "        vk_json_printf(_OUT, \"\\n\"); PRINT_SPACE\n"
479            code += "        vk_json_printf(_OUT, \"[\\n\");\n"
480            code += "        for (i = 0; i < %s(%s); i++) {\n" %(derefPtr, arraySize)
481            code += "            char tmp[100];\n"
482
483            # Special case handling for giving unique names for pImmutableSamplers if there are multiple
484            # bindings in the same Descriptor set layout.
485            if name == "pImmutableSamplers":
486                code += "            sprintf(tmp, \"%s_%%u_%%u\", *(%sbinding), i);\n" %(name, str2)
487            else:
488                code += "            sprintf(tmp, \"%s_%%u\", i);\n" %(name)
489
490            code += "            INDENT(4);\n"
491            code += "            isCommaNeeded = (i+1) != %s(%s);\n" %(derefPtr, arraySize)
492            if str(self.getTypeCategory(typeName)) == 'handle':
493                code += "            print_%s(%s%s[i], tmp, isCommaNeeded);\n" %(typeName, str2, name)
494            elif not typeName.startswith("Std"):
495                code += "            print_%s(%s%s[i], %s, isCommaNeeded);\n" %(typeName, str2, name, printStr)
496            code += "            INDENT(-4);\n"
497            code += "        }\n"
498            code += "        PRINT_SPACE\n"
499            code += "        vk_json_printf(_OUT, \"]%s\\n\");\n" %(comma)
500            code += "     } else {\n"
501            code += "         vk_json_printf(_OUT, \" \\\"NULL\\\"%s\\n\");\n" %(comma)
502            code += "     }\n"
503
504            return code
505
506    # Prints out member name followed by empty string.
507    def genEmptyCode(self, memberName, isCommaNeeded):
508        comma = "," if isCommaNeeded else ""
509        code = ""
510        code +=  "     /** Note: printing just an empty entry here **/\n"
511        code +=  "     PRINT_SPACE"
512        code +=  "    vk_json_printf(_OUT, \"\\\"%s\\\" : \\\"\\\"%s\\n\");\n" %(memberName, comma)
513
514        return code
515
516    def genStructCode(self, param, str1, str2, str3, str4, structName, isCommaNeeded):
517        code = ""
518        memberName = ""
519        typeName = ""
520
521        for elem in param:
522            if elem.text.find('PFN_') != -1:
523                return "     /** Note: Ignoring function pointer (%s). **/\n" %(elem.text)
524
525            if elem.text == 'pNext':
526                return self.genPNextCode(str2)
527
528            if elem.tag == 'name':
529                memberName = elem.text
530
531            if elem.tag == 'type':
532                typeName = elem.text
533
534            # Some arrays have constant sizes.
535            if elem.text.find("VK_") != -1:
536                return self.genArrayCode(memberName, typeName, str2, elem.text, False, isCommaNeeded)
537
538        if self.paramIsStaticArray(param):
539            return self.genArrayCode(memberName, typeName, str2, self.paramIsStaticArray(param), False, isCommaNeeded)
540
541        # If the struct's member is another struct, we need a different way to handle.
542        elif self.paramIsStruct(typeName) == 1:
543            code += self.generateStructMembercode(param, str1, str2, str3, str4, memberName, typeName, isCommaNeeded)
544
545        # Ignore void* data members
546        elif self.paramIsPointer(param) and typeName == 'void':
547            return "     /** Note: Ignoring void* data. **/\n"
548
549        # Handle C style strings
550        elif self.paramIsPointer(param) and param.get('len') is not None and param.get('len').find('null-terminated') != -1:
551            code = "     /** Printing string inline. **/\n"
552            code += "     PRINT_SPACE\n"
553            code += "     vk_json_printf(_OUT, \"\\\"%s\\\" : \\\"%%s\\\",\\n\", (char*)obj->%s);\n" %(memberName, memberName)
554            return code
555
556        #TODO: Handle this path.
557        elif self.paramIsPointer(param) and param.get('len') is not None and param.get('len').find('latexmath') != -1:
558            code = "     /** Skipping %s. **/\n" %(typeName)
559
560        # For pointers where we have the 'len' field, dump them as arrays.
561        elif self.paramIsPointer(param) and param.get('len') is not None and param.get('len').find('null-terminated') == -1 and param.get('len').find('latexmath') == -1:
562            return self.genArrayCode(memberName, typeName, str2, str2+param.get('len')+")", False, isCommaNeeded)
563
564        # If a struct member is just a handle.
565        elif str(self.getTypeCategory(typeName)) == 'handle':
566            return self.genEmptyCode(memberName, isCommaNeeded)
567
568        elif not typeName.startswith("Std"):
569            code += "     print_%s(%s%s, \"%s\", %s);\n" %(typeName, str2, memberName, memberName, str(isCommaNeeded))
570
571        return code
572
573    def genStruct(self, typeinfo, typeName, alias):
574        OutputGenerator.genStruct(self, typeinfo, typeName, alias)
575        body = ""
576        typeElem = typeinfo.elem
577
578        extension = "VK_VERSION_1_0"
579        if (typeName in self.featureDict):
580            extension = self.featureDict[typeName]
581
582        if alias:
583            body = 'typedef ' + alias + ' ' + typeName + ';\n'
584        else:
585            # The code here is similar to the hpp generator. Hence maintaining similar form.
586            genStr1 = ["const "]
587            genStr2 = ["&obj->" ]
588            genStr3 = [" * obj, const char* s, int commaNeeded) {"]
589            genStr4 = ["     if (obj->"]
590
591            for index in range(len(genStr1)):
592                body += "void print_%s(%s%s%s\n" %(typeName, genStr1[index], typeName, genStr3[index])
593                body += "     (void)s;\n"
594                body += "     PRINT_SPACE\n"
595                body += "     vk_json_printf(_OUT, \"{\\n\");\n"
596                body += "     INDENT(4);\n"
597                body += "\n"
598                count = 0
599                numMembers = len(typeElem.findall('.//member'))
600
601                isCommaNeeded = 1
602                for member in typeElem.findall('.//member'):
603                    count = count + 1
604                    if count == numMembers:
605                        isCommaNeeded = 0
606
607                    body += self.genStructCode(member, genStr1[index], genStr2[index], genStr3[index], genStr4[index], typeName, isCommaNeeded)
608                    body += "\n"
609
610                body += "     INDENT(-4);\n"
611                body += "     PRINT_SPACE\n"
612                body += "     vk_json_printf(_OUT, \"}%s\\n\", commaNeeded ? \",\" : \"\");\n"
613                body += "}\n"
614
615        self.appendSection('struct', body, extension)
616
617    def genGroup(self, groupinfo, groupName, alias=None):
618        OutputGenerator.genGroup(self, groupinfo, groupName, alias)
619        groupElem = groupinfo.elem
620        body = ""
621        section = 'enum'
622
623        extension = "VK_VERSION_1_0"
624        if (groupName in self.featureDict):
625            extension = self.featureDict[groupName]
626        enumType = "uint32_t"
627        bitStr = "1u"
628        if groupElem.get('bitwidth') and (int(groupElem.get('bitwidth')) == 64):
629            enumType = "uint64_t"
630            bitStr = "1ull"
631
632        body += "static const char* %s_map(%s o) {\n" %(groupName, enumType)
633        body += "switch (o) {\n"
634        enums = groupElem.findall('enum')
635
636        for enum in enums:
637            # Avoid having duplicates.
638            if enum.get('name') not in self.enumNames:
639                self.enumNames.append(enum.get('name'))
640
641                if enum.get('value'):
642                    body += "    case %s: return \"%s\";\n" %(enum.get('value'), enum.get('name'))
643
644                elif enum.get('bitpos'):
645                    body += "    case (%s << %s): return \"%s\";\n" %(bitStr, enum.get('bitpos'), enum.get('name'))
646
647                #TODO: Some enums have no offset. How to handle those?
648                elif enum.get('extends') and enum.get("extnumber") and enum.get("offset"):
649                    extNumber = int(enum.get("extnumber"))
650                    offset = int(enum.get("offset"))
651                    enumVal = self.extBase + (extNumber - 1) * self.extBlockSize + offset
652                    body += "    case %s: return \"%s\";\n" %(str(enumVal), enum.get('name'))
653
654        body += "   }\n"
655        body += "   return NULL;\n";
656        body += "}\n"
657        body += self.genEnumCode(groupName)
658
659        self.appendSection(section, body, extension)
660