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