1#!/usr/bin/python3 -i 2# 3# Copyright 2020-2023 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 14from generator import (GeneratorOptions, OutputGenerator, noneStr, 15 regSortFeatures, write) 16 17copyright = """ 18/* 19 * Copyright (c) 2021 The Khronos Group Inc. 20 * 21 * Licensed under the Apache License, Version 2.0 (the "License"); 22 * you may not use this file except in compliance with the License. 23 * You may obtain a copy of the License at 24 * 25 * http://www.apache.org/licenses/LICENSE-2.0 26 * 27 * Unless required by applicable law or agreed to in writing, software 28 * distributed under the License is distributed on an "AS IS" BASIS, 29 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 30 * See the License for the specific language governing permissions and 31 * limitations under the License. 32 * 33 *//*! 34 * \\file 35 * \\brief Defines JSON generators for Vulkan structures 36 */ 37""" 38 39predefinedCode = """ 40/********************************************************************************************/ 41/** This code is generated. To make changes, please modify the scripts or the relevant xml **/ 42/********************************************************************************************/ 43 44#include <iostream> 45#include <map> 46#include <bitset> 47#include <functional> 48#include <sstream> 49#include <cassert> 50#include <cmath> 51#ifndef VULKAN_JSON_CTS 52 #include <vulkan/vulkan.h> 53#endif 54 55#ifdef _WIN32 56 #ifndef WIN32_LEAN_AND_MEAN 57 #define WIN32_LEAN_AND_MEAN 58 #endif 59 #define VC_EXTRALEAN 60 #define NOMINMAX 61 #include <windows.h> 62#endif 63 64namespace vk_json { 65 66static thread_local int s_num_spaces = 0; 67static thread_local std::stringstream _string_stream; 68 69static void dumpPNextChain(const void* pNext); 70 71// By default, redirect to std::cout. Can stream it to a stringstream if needed. 72//#define _OUT std::cout 73#define _OUT _string_stream 74 75// Helper utility to do indentation in the generated json file. 76#define PRINT_SPACE for (int k = 0; k < s_num_spaces; k++) _OUT << \" \"; 77 78#define INDENT(sz) s_num_spaces += (sz); 79 80#define PRINT_VAL(c) PRINT_SPACE \\ 81 if (s != "") {\\ 82 _OUT << \"\\\"\" << s << \"\\\"\" << \" : \" << o << (c ? \",\" : \"\") << std::endl; \\ 83 } else {\\ 84 _OUT << o << (c ? \",\" : \"\") << std::endl; \\ 85 } 86 87#define PRINT_STR(c) PRINT_SPACE \\ 88 if (s != "") {\\ 89 _OUT << \"\\\"\" << s << \"\\\"\" << \" : " << \"\\\"\" << o << \"\\\"\" << (c ? \",\" : \"\") << std::endl; \\ 90 } else {\\ 91 _OUT << \"\\\"\" << o << \"\\\"\" << (c ? \",\" : \"\") << std::endl; \\ 92 } 93 94// To make sure the generated data is consistent across platforms, 95// we typecast to 32-bit and dump the data. 96// The value is not expected to exceed the range. 97static void print_size_t(const size_t* o, const std::string& s, bool commaNeeded=true) 98{ 99 PRINT_SPACE 100 _OUT << \"\\\"\" << s << \"\\\"\" << \" : \" << static_cast<%s>(*o) << (commaNeeded ? \",\" : \"\") << std::endl;\\ 101} 102static void print_size_t(size_t o, const std::string& s, bool commaNeeded=true) 103{ 104 PRINT_SPACE 105 _OUT << \"\\\"\" << s << \"\\\"\" << \" : \" << static_cast<%s>(o) << (commaNeeded ? \",\" : \"\") << std::endl;\\ 106} 107""" 108 109headerGuardTop = """#ifndef _VULKAN_JSON_DATA_HPP 110#define _VULKAN_JSON_DATA_HPP 111""" 112 113headerGuardBottom = """#endif // _VULKAN_JSON_DATA_HPP""" 114 115encodeBase64CodeCTS = """ 116// Base 64 formatter class from executor/xeTestLogWriter.cpp 117 118class Base64Formatter 119{ 120public: 121 const deUint8* data; 122 int numBytes; 123 124 Base64Formatter(const deUint8* data_, int numBytes_) : data(data_), numBytes(numBytes_) {} 125}; 126 127std::ostream& operator<< (std::ostream& str, const Base64Formatter& fmt) 128{ 129 static const char s_base64Table[64] = 130 { 131 'A','B','C','D','E','F','G','H','I','J','K','L','M', 132 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', 133 'a','b','c','d','e','f','g','h','i','j','k','l','m', 134 'n','o','p','q','r','s','t','u','v','w','x','y','z', 135 '0','1','2','3','4','5','6','7','8','9','+','/' 136 }; 137 138 const deUint8* data = fmt.data; 139 int numBytes = fmt.numBytes; 140 int srcNdx = 0; 141 142 DE_ASSERT(data && (numBytes > 0)); 143 144 /* Loop all input chars. */ 145 while (srcNdx < numBytes) 146 { 147 int numRead = de::min(3, numBytes - srcNdx); 148 deUint8 s0 = data[srcNdx]; 149 deUint8 s1 = (numRead >= 2) ? data[srcNdx + 1] : 0; 150 deUint8 s2 = (numRead >= 3) ? data[srcNdx + 2] : 0; 151 char d[4]; 152 153 srcNdx += numRead; 154 155 d[0] = s_base64Table[s0 >> 2]; 156 d[1] = s_base64Table[((s0 & 0x3) << 4) | (s1 >> 4)]; 157 d[2] = s_base64Table[((s1 & 0xF) << 2) | (s2 >> 6)]; 158 d[3] = s_base64Table[s2 & 0x3F]; 159 160 if (numRead < 3) d[3] = '='; 161 if (numRead < 2) d[2] = '='; 162 163 /* Write data. */ 164 str.write(&d[0], sizeof(d)); 165 } 166 167 return str; 168} 169 170inline Base64Formatter toBase64(const deUint8* bytes, int numBytes) {return Base64Formatter(bytes, numBytes); } 171 172static void print_void_data(const void * o, int oSize, const std::string& s, bool commaNeeded=true) 173{ 174 if (o != NULL && oSize != 0) 175 { 176 PRINT_SPACE _OUT << "\\\"" << s << "\\\"" << " : " << "\\\"" << toBase64((deUint8*)o, oSize) << "\\\"" << (commaNeeded ? "," : "") << std::endl; 177 } 178 else 179 { 180 PRINT_SPACE _OUT << "\\\"" << s << "\\\"" << " : " << "\\\"NULL\\\"" << (commaNeeded ? "," : "") << std::endl; 181 } 182} 183""" 184encodeBase64Code = """ 185// Base 64 formatter class from executor/xeTestLogWriter.cpp 186 187class Base64Formatter 188{ 189public: 190 const uint8_t* data; 191 int numBytes; 192 193 Base64Formatter(const uint8_t* data_, int numBytes_) : data(data_), numBytes(numBytes_) {} 194}; 195 196std::ostream& operator<< (std::ostream& str, const Base64Formatter& fmt) 197{ 198 static const char s_base64Table[64] = 199 { 200 'A','B','C','D','E','F','G','H','I','J','K','L','M', 201 'N','O','P','Q','R','S','T','U','V','W','X','Y','Z', 202 'a','b','c','d','e','f','g','h','i','j','k','l','m', 203 'n','o','p','q','r','s','t','u','v','w','x','y','z', 204 '0','1','2','3','4','5','6','7','8','9','+','/' 205 }; 206 207 const uint8_t* data = fmt.data; 208 int numBytes = fmt.numBytes; 209 int srcNdx = 0; 210 211 assert(data && (numBytes > 0)); 212 213 /* Loop all input chars. */ 214 while (srcNdx < numBytes) 215 { 216 #undef min 217 int numRead = std::min(3, numBytes - srcNdx); 218 uint8_t s0 = data[srcNdx]; 219 uint8_t s1 = (numRead >= 2) ? data[srcNdx + 1] : 0; 220 uint8_t s2 = (numRead >= 3) ? data[srcNdx + 2] : 0; 221 char d[4]; 222 223 srcNdx += numRead; 224 225 d[0] = s_base64Table[s0 >> 2]; 226 d[1] = s_base64Table[((s0 & 0x3) << 4) | (s1 >> 4)]; 227 d[2] = s_base64Table[((s1 & 0xF) << 2) | (s2 >> 6)]; 228 d[3] = s_base64Table[s2 & 0x3F]; 229 230 if (numRead < 3) d[3] = '='; 231 if (numRead < 2) d[2] = '='; 232 233 /* Write data. */ 234 str.write(&d[0], sizeof(d)); 235 } 236 237 return str; 238} 239 240inline Base64Formatter toBase64(const uint8_t* bytes, int numBytes) {return Base64Formatter(bytes, numBytes); } 241 242static void print_void_data(const void * o, int oSize, const std::string& s, bool commaNeeded=true) 243{ 244 if (o != NULL && oSize != 0) 245 { 246 PRINT_SPACE _OUT << "\\\"" << s << "\\\"" << " : " << "\\\"" << toBase64((uint8_t*)o, oSize) << "\\\"" << (commaNeeded ? "," : "") << std::endl; 247 } 248 else 249 { 250 PRINT_SPACE _OUT << "\\\"" << s << "\\\"" << " : " << "\\\"NULL\\\"" << (commaNeeded ? "," : "") << std::endl; 251 } 252} 253""" 254 255class JSONGeneratorOptions(GeneratorOptions): 256 """JSONGeneratorOptions - subclass of GeneratorOptions. 257 258 Adds options used by JSONOutputGenerator objects during C language header 259 generation.""" 260 261 def __init__(self, 262 prefixText="", 263 genFuncPointers=True, 264 protectFile=True, 265 protectFeature=True, 266 protectProto=None, 267 protectProtoStr=None, 268 apicall='', 269 apientry='', 270 apientryp='', 271 isCTS = False, 272 indentFuncProto=True, 273 indentFuncPointer=False, 274 alignFuncParam=0, 275 genEnumBeginEndRange=False, 276 genAliasMacro=False, 277 aliasMacro='', 278 vulkanLayer=False, 279 **kwargs 280 ): 281 282 GeneratorOptions.__init__(self, **kwargs) 283 self.isCTS = isCTS 284 285 self.vulkanLayer = vulkanLayer 286 287class JSONOutputGenerator(OutputGenerator): 288 # This is an ordered list of sections in the header file. 289 TYPE_SECTIONS = ['basetype', 'handle', 'enum', 290 'group', 'bitmask', 'struct'] 291 ALL_SECTIONS = TYPE_SECTIONS 292 293 def __init__(self, *args, **kwargs): 294 super().__init__(*args, **kwargs) 295 # Internal state - accumulators for different inner block text 296 self.sections = {section: [] for section in self.ALL_SECTIONS} 297 self.feature_not_empty = False 298 self.may_alias = None 299 self.vkscFeatureList = [] 300 self.vkFeatureLayerList = [] 301 302 # Fills in some extensions for exclusion while generating code for layer. 303 self.vkLayerNotReqList = set([""]) 304 305 self.platformList = ["xlib", 306 "xlib_xrandr", 307 "xcb", 308 "wayland", 309 "directfb", 310 "android", 311 "win32", 312 "vi", 313 "ios", 314 "macos", 315 "metal", 316 "fuchsia", 317 "ggp", 318 "QNX", 319 "provisional"] 320 self.baseTypeList = ["int32_t", 321 "uint32_t", 322 "uint8_t", 323 "uint64_t", 324 "float", 325 "int", 326 "double", 327 "int64_t", 328 "uint16_t", 329 "char"] 330 331 def printBaseTypes(self): 332 for baseType in self.baseTypeList: 333 printStr = " PRINT_VAL(commaNeeded)\n" 334 335 # Some special handling needed here. 336 if baseType == 'char': 337 write("static void print_%s(const %s * const* o, const std::string& s, bool commaNeeded=true)\n" %(baseType, self.baseTypeListMap[baseType]) + 338 "{\n" + 339 " PRINT_STR(commaNeeded)\n" + 340 "}\n" 341 , file=self.outFile 342 ) 343 344 if self.isCTS and baseType == "float": 345 printStr = " if (std::isnan(o))\n" 346 printStr +=" {\n" 347 printStr +=" PRINT_SPACE\n" 348 printStr +=" if (s != \"\")\n" 349 printStr +=" _OUT << \"\\\"\" << s << \"\\\"\" << \" : \\\"NaN\\\"\" << (commaNeeded ? \",\" : \"\") << std::endl;\n" 350 printStr +=" else\n" 351 printStr +=" _OUT << \"\\\"NaN\\\"\" << (commaNeeded ? \",\" : \"\") << std::endl;\n" 352 printStr +=" }\n" 353 printStr +=" else\n" 354 printStr +=" {\n" 355 printStr +=" PRINT_VAL(commaNeeded)\n" 356 printStr +=" }\n" 357 358 write("static void print_%s(%s o, const std::string& s, bool commaNeeded=true)\n" %(baseType, self.baseTypeListMap[baseType]) + 359 "{\n" + 360 printStr + 361 "}\n" 362 , file=self.outFile 363 ) 364 365 if baseType == 'char': 366 printStr = " PRINT_STR(commaNeeded)\n" 367 368 if self.isCTS and baseType == "float": 369 printStr = " if (std::isnan(*o))\n" 370 printStr +=" {\n" 371 printStr +=" PRINT_SPACE\n" 372 printStr +=" if (s != \"\")\n" 373 printStr +=" _OUT << \"\\\"\" << s << \"\\\"\" << \" : \\\"NaN\\\"\" << (commaNeeded ? \",\" : \"\") << std::endl;\n" 374 printStr +=" else\n" 375 printStr +=" _OUT << \"\\\"NaN\\\"\" << (commaNeeded ? \",\" : \"\") << std::endl;\n" 376 printStr +=" }\n" 377 printStr +=" else\n" 378 printStr +=" {\n" 379 printStr +=" PRINT_VAL(commaNeeded)\n" 380 printStr +=" }\n" 381 382 write("static void print_%s(const %s * o, const std::string& s, bool commaNeeded=true)\n" %(baseType, self.baseTypeListMap[baseType]) + 383 "{\n" + 384 printStr + 385 "}\n" 386 , file=self.outFile 387 ) 388 389 def createLayerUnusedList(self): 390 allExtensions = self.registry.reg.findall('extensions') 391 for extensions in allExtensions: 392 extensionList = extensions.findall("extension") 393 for extension in extensionList: 394 for platform in self.platformList: 395 if re.search(platform, extension.get("name"), re.IGNORECASE): 396 requiredList = extension.findall("require") 397 for requiredItem in requiredList: 398 typeList = requiredItem.findall("type") 399 for typeName in typeList: 400 if platform == "vi": 401 if re.search("NN", extension.get("name")): 402 self.vkLayerNotReqList.add(typeName.get("name")) 403 else: 404 self.vkLayerNotReqList.add(typeName.get("name")) 405 break 406 407 typesList = self.registry.reg.findall('types') 408 for types in typesList: 409 typeList = types.findall("type") 410 for type in typeList: 411 if type.get("name") != "": 412 cat = type.get("category") 413 name = type.get("name") 414 if cat in {"handle", "bitmask", "basetype", "enum", "struct"}: 415 for platform in self.platformList: 416 if re.search(platform, name, re.IGNORECASE): 417 if platform == "vi": 418 if re.search("NN", name): 419 self.vkLayerNotReqList.add(name) 420 else: 421 self.vkLayerNotReqList.add(name) 422 break 423 424 425 def createvkscFeatureList(self): 426 for feature in self.registry.reg.findall('feature'): 427 if feature.get('api').find('vulkansc') != -1: 428 # Remove entries that are removed in features in VKSC profile. 429 requiredList = feature.findall("require") 430 431 for requiredItem in requiredList: 432 typeList = requiredItem.findall("type") 433 for typeName in typeList: 434 if typeName.get("name") != "": 435 self.vkscFeatureList.append(typeName.get("name")) 436 437 removeItemList = feature.findall("remove") 438 for removeItem in removeItemList: 439 removeTypes = removeItem.findall("type") 440 for item in removeTypes: 441 if self.vkscFeatureList.count(item.get("name")) > 0: 442 self.vkscFeatureList.remove(item.get("name")) 443 444 allExtensions = self.registry.reg.findall('extensions') 445 for extensions in allExtensions: 446 extensionList = extensions.findall("extension") 447 for extension in extensionList: 448 if extension.get("supported").find("vulkansc") != -1: 449 requiredList = extension.findall("require") 450 for requiredItem in requiredList: 451 typeList = requiredItem.findall("type") 452 for typeName in typeList: 453 self.vkscFeatureList.append(typeName.get("name")) 454 455 def printPrototypesAndExtensionDump(self): 456 code = "" 457 458 code += "/*************************************** Begin prototypes ***********************************/\n" 459 if self.vulkanLayer: 460 typesList = self.registry.reg.findall('types') 461 for types in typesList: 462 typeList = types.findall("type") 463 for type in typeList: 464 if type.get("name") != "": 465 cat = type.get("category") 466 name = type.get("name") 467 468 enumList = self.registry.reg.findall('enums') 469 for enums in enumList: 470 name = enums.get("name") 471 else: 472 typesList = self.registry.reg.findall('types') 473 for types in typesList: 474 typeList = types.findall("type") 475 for type in typeList: 476 if type.get("name") != "": 477 cat = type.get("category") 478 name = type.get("name") 479 480 code += "/*************************************** End prototypes ***********************************/\n\n" 481 code += "static void dumpPNextChain(const void* pNext) {\n" 482 code += " VkBaseInStructure *pBase = (VkBaseInStructure*)pNext;\n" 483 code += " if (pNext) {\n" 484 code += " PRINT_SPACE\n" 485 code += " _OUT << \"\\\"pNext\\\":\"<< std::endl;\n\n" 486 code += " switch (pBase->sType) {\n" 487 488 for type in typeList: 489 if type.get('category') == 'struct' and type.get('structextends') is not None: 490 if (self.vulkanLayer and (type.get('name') not in self.vkLayerNotReqList)) or (not self.vulkanLayer): 491 members = type.findall('member') 492 for m in members: 493 n = type.get('name') 494 if m.get('values') and (n in self.vkFeatureLayerList): 495 code += " case %s:" %(m.get('values')) 496 code += "print_%s((%s *) pNext, \"%s\", true);\n" %(n, n, n) 497 code += " break;\n" 498 499 code += " default: assert(false); // No structure type matching\n" 500 code += " }\n" 501 code += " }\n" 502 code += " }\n" 503 504 return code 505 506 507 def beginFile(self, genOpts): 508 OutputGenerator.beginFile(self, genOpts) 509 510 self.vulkanLayer = genOpts.vulkanLayer 511 if self.vulkanLayer: 512 self.createLayerUnusedList() 513 514 self.createvkscFeatureList() 515 516 self.isCTS = genOpts.isCTS 517 518 self.baseTypeListMap = { 519 "int32_t" : "deInt32" if self.isCTS else "int32_t", 520 "uint32_t" : "deUint32" if self.isCTS else "uint32_t", 521 "uint8_t" : "deUint8" if self.isCTS else "uint8_t", 522 "uint64_t" : "deUint64" if self.isCTS else "uint64_t", 523 "float" : "float", 524 "int" : "int", 525 "double" : "double", 526 "int64_t" : "deInt64" if self.isCTS else "int64_t", 527 "uint16_t" : "deUint16" if self.isCTS else "uint16_t", 528 "char" : "char" 529 } 530 531 write(headerGuardTop, file=self.outFile, end='') 532 write(copyright, file=self.outFile) 533 if self.isCTS: 534 write(predefinedCode % ("deUint32", "deUint32"), file=self.outFile) 535 else: 536 write(predefinedCode % ("uint32_t", "uint32_t"), file=self.outFile) 537 self.printBaseTypes() 538 if self.isCTS: 539 write(encodeBase64CodeCTS, file=self.outFile) 540 else: 541 write(encodeBase64Code, file=self.outFile) 542 543 def endFile(self): 544 write(self.printPrototypesAndExtensionDump(), file=self.outFile) 545 write("}//End of namespace vk_json\n", file=self.outFile) # end of namespace 546 write(headerGuardBottom, file=self.outFile, end='') # end of _VULKAN_JSON_DATA_HPP 547 OutputGenerator.endFile(self) 548 549 def beginFeature(self, interface, emit): 550 OutputGenerator.beginFeature(self, interface, emit) 551 self.sections = {section: [] for section in self.ALL_SECTIONS} 552 self.feature_not_empty = False 553 554 def endFeature(self): 555 if self.emit: 556 if self.feature_not_empty: 557 if self.genOpts.conventions.writeFeature(self.featureExtraProtect, self.genOpts.filename): 558 559 for section in self.TYPE_SECTIONS: 560 contents = self.sections[section] 561 if contents: 562 write('\n'.join(contents), file=self.outFile) 563 564 # Finish processing in superclass 565 OutputGenerator.endFeature(self) 566 567 def appendSection(self, section, text): 568 self.sections[section].append(text) 569 self.feature_not_empty = True 570 571 def genEnumData(self, name, obj): 572 code = "" 573 code += " if (str != \"\") _OUT << \"\\\"\" << str << \"\\\"\" << \" : \";\n" 574 code += " if (commaNeeded)\n" 575 code += " _OUT << \"\\\"\" << %s_map[%sobj] << \"\\\",\" << std::endl;\n" %(name, obj) 576 code += " else\n" 577 code += " _OUT << \"\\\"\" << %s_map[%sobj] << \"\\\"\" << std::endl;\n" %(name, obj) 578 return code 579 580 def genEnumCode(self, name): 581 code = "" 582 code += "static void print_%s(%s obj, const std::string& str, bool commaNeeded=true) {\n" %(name, name) 583 code += " PRINT_SPACE\n" 584 code += self.genEnumData(name, "") 585 code += "}\n" 586 587 code += "static void print_%s(const %s * obj, const std::string& str, bool commaNeeded=true) {\n" %(name, name) 588 code += " PRINT_SPACE\n" 589 code += self.genEnumData(name, "*") 590 code += "}\n" 591 592 return code 593 594 def genBasetypeCode(self, str1, str2, name): 595 code = "" 596 code += "static void print_" + name + "(" + str1 + name + str2 + " const std::string& str, bool commaNeeded=true) {\n" 597 code += " PRINT_SPACE\n" 598 if name == "VkBool32": 599 code += " _OUT << \"\\\"\" << str << \"\\\"\" << \" : \" << \"\\\"\" << ((obj == 0) ? (\"VK_FALSE\") : (\"VK_TRUE\")) << \"\\\"\" << (commaNeeded ? \",\" : \"\") << std::endl;\n" 600 else: 601 code += " _OUT << \"\\\"\" << str << \"\\\"\" << \" : \" << \"\\\"\" << obj << \"\\\"\" << (commaNeeded ? \",\" : \"\") << std::endl;\n" 602 code += "}\n" 603 return code 604 605 def genHandleCode(self, str1, str2, name): 606 code = "" 607 code += "static void print_%s(%s%s%s const std::string& str, bool commaNeeded=true) {\n" %(name, str1, name, str2) 608 code += " PRINT_SPACE\n" 609 code += " if (commaNeeded)\n" 610 code += " _OUT << \"\\\"\" << str << \"\\\"\" << \",\" << std::endl;\n" 611 code += " else\n" 612 code += " _OUT << \"\\\"\" << str << \"\\\"\" << std::endl;\n" 613 code += "}\n" 614 return code 615 616 def genBitmaskCode(self, str1, str2, name, mapName): 617 if mapName is not None: 618 code = "" 619 code += "static void print_%s(%s%s%s const std::string& str, bool commaNeeded=true) {\n" %(name, str1, name, str2) 620 code += " PRINT_SPACE\n" 621 code += " if (str != \"\") _OUT << \"\\\"\" << str << \"\\\"\" << \" : \";\n" 622 code += " const int max_bits = 64; // We don't expect the number to be larger.\n" 623 code += " std::bitset<max_bits> b(obj);\n" 624 code += " _OUT << " + "\"\\\"\"" + ";\n" 625 code += " if (obj == 0) _OUT << \"0\";\n" 626 code += " for (unsigned int i = 0, bitCount = 0; i < b.size(); i++) {\n" 627 code += " if (b[i] == 1) {\n" 628 code += " bitCount++;\n" 629 code += " if (bitCount < b.count())\n" 630 code += " _OUT << %s_map[1ULL<<i] << \" | \";\n" %(mapName) 631 code += " else\n" 632 code += " _OUT << %s_map[1ULL<<i];\n" %(mapName) 633 code += " }\n" 634 code += " }\n" 635 code += " if (commaNeeded)\n" 636 code += " _OUT << \"\\\"\" << \",\";\n" 637 code += " else\n" 638 code += " _OUT << \"\\\"\"<< \"\";\n" 639 code += " _OUT << std::endl;\n" 640 code += "}\n" 641 642 else: 643 code = "" 644 code += "static void print_%s(%s%s%s const std::string& str, bool commaNeeded=true) {\n" %(name, str1, name, str2) 645 code += " PRINT_SPACE\n" 646 code += " if (commaNeeded)\n" 647 code += " _OUT << \"\\\"\" << str << \"\\\"\" << \" : \" << obj << \",\" << std::endl;\n" 648 code += " else\n" 649 code += " _OUT << \"\\\"\" << str << \"\\\"\" << \" : \" << obj << std::endl;\n" 650 code += "}\n" 651 652 return code 653 654 def genType(self, typeinfo, name, alias): 655 OutputGenerator.genType(self, typeinfo, name, alias) 656 typeElem = typeinfo.elem 657 body = "" 658 659 self.vkFeatureLayerList.append(name); 660 661 category = typeElem.get('category') 662 if category == 'funcpointer': 663 section = 'struct' 664 else: 665 section = category 666 667 if category in ('struct', 'union'): 668 self.genStruct(typeinfo, name, alias) 669 else: 670 if typeElem.get('category') == 'bitmask': 671 for elem in typeElem: 672 if elem.tag == 'name': 673 body += self.genBitmaskCode("", " obj,", elem.text, typeElem.get('requires')) 674 body += self.genBitmaskCode("const ", " * obj,", elem.text, typeElem.get('requires')) 675 676 elif typeElem.get('category') == 'basetype': 677 for elem in typeElem: 678 if elem.tag == 'name': 679 body += self.genBasetypeCode("", " obj,", elem.text) 680 body += self.genBasetypeCode("const ", " * obj,", elem.text) 681 682 elif typeElem.get('category') == 'handle': 683 for elem in typeElem: 684 if elem.tag == 'name': 685 body += self.genHandleCode("", " obj,", elem.text) 686 body += self.genHandleCode("const ", " * obj,", elem.text) 687 if body: 688 self.appendSection(section, body) 689 690 def paramIsStruct(self, memberType): 691 if str(self.getTypeCategory(memberType)) == 'struct': 692 return 1 693 return 0 694 695 # Helper taken from the validation layers code. 696 def paramIsPointer(self, param): 697 ispointer = False 698 for elem in param: 699 if elem.tag == 'type' and elem.tail is not None and '*' in elem.tail: 700 ispointer = True 701 return ispointer 702 703 # Helper taken from the validation layers code. 704 def paramIsStaticArray(self, param): 705 isstaticarray = 0 706 paramname = param.find('name') 707 if (paramname.tail is not None) and ('[' in paramname.tail) and (']' in paramname.tail): 708 isstaticarray = paramname.tail.count('[') 709 if isstaticarray: 710 arraySize = paramname.tail[1] 711 712 if isstaticarray: 713 return arraySize 714 else: 715 return 0 716 717 def generateStructMembercode(self, param, str1, str2, str3, str4, memberName, typeName, isCommaNeeded): 718 length = "" 719 code = "" 720 isArr = param.get('len') is not None 721 722 if param.get('len') is not None: 723 length = str2 + param.get('len') + ")" 724 length = length.replace(')', '') 725 length = length.replace(',1', '') 726 727 code += " PRINT_SPACE\n" 728 code += " _OUT << \"\\\"%s\\\": \" << std::endl;\n" %(memberName) 729 730 if self.paramIsPointer(param): code += str4 + memberName + ") {\n" 731 else: code += " {\n" 732 733 # TODO: With some tweak, we can use the genArrayCode() here. 734 if isArr is True: 735 code += " PRINT_SPACE\n" 736 code += " _OUT << \"[\" << std::endl;\n" 737 code += " for (unsigned int i = 0; i < %s; i++) {\n" %(length) 738 code += " if (i+1 == %s)\n" %(length) 739 code += " print_%s(%s%s[i], \"%s\", 0);\n" %(typeName, str2, memberName, memberName) 740 code += " else\n" 741 code += " print_%s(%s%s[i], \"%s\", 1);\n" %(typeName, str2, memberName, memberName) 742 code += " }\n" 743 code += " PRINT_SPACE\n" 744 if isCommaNeeded: 745 code += " _OUT << \"],\" << std::endl;\n" 746 else: 747 code += " _OUT << \"]\" << std::endl;\n" 748 code += " }\n" 749 else: 750 if (typeName == "VkAccelerationStructureGeometryKHR"): 751 code += " print_%s(*%s%s, \"%s\", %s);\n" %(typeName, str2, memberName, memberName, str(isCommaNeeded)) 752 else: 753 code += " print_%s(%s%s, \"%s\", %s);\n" %(typeName, str2, memberName, memberName, str(isCommaNeeded)) 754 code += " }\n" 755 756 if self.paramIsPointer(param): 757 code += " else\n" 758 code += " {\n" 759 if isCommaNeeded: 760 code += " PRINT_SPACE _OUT << \"\\\"NULL\\\"\"<< \",\"<< std::endl;\n" 761 else: 762 code += " PRINT_SPACE _OUT << \"\\\"NULL\\\"\"<< \"\"<< std::endl;\n" 763 code += " }\n" 764 765 return code 766 767 def genPNextCode(self, str2): 768 code = "" 769 code += " if (%spNext) {\n" %(str2) 770 code += " dumpPNextChain(%spNext);\n" %(str2) 771 code += " } else {\n" 772 code += " PRINT_SPACE\n" 773 code += " _OUT << \"\\\"pNext\\\":\" << \"\\\"NULL\\\"\"<< \",\"<< std::endl;\n" 774 code += " }\n" 775 776 return code 777 778 # Prints out member name followed by empty string. 779 def genEmptyCode(self, memberName, str2, isCommaNeeded): 780 code = "" 781 if not self.isCTS: 782 code += " /** Note: printing just an empty entry here **/\n" 783 else: 784 code += " // CTS : required value\n" 785 code += " PRINT_SPACE" 786 if isCommaNeeded: 787 if self.isCTS and (memberName == "module" or memberName == "layout" or memberName == "renderPass" or memberName == "conversion"): 788 code += " _OUT << \"\\\"\" << \"%s\" << \"\\\"\" << \" : \" << %s%s.getInternal() << \",\" << std::endl;\n" %(memberName, str2, memberName) 789 else: 790 code += " _OUT << \"\\\"\" << \"%s\" << \"\\\"\" << \" : \" << \"\\\"\" << \"\\\",\" << std::endl;\n" %(memberName) 791 else: 792 if self.isCTS and (memberName == "module" or memberName == "layout" or memberName == "renderPass" or memberName == "conversion"): 793 code += " _OUT << \"\\\"\" << \"%s\" << \"\\\"\" << \" : \" << %s%s.getInternal() << std::endl;\n" %(memberName, str2, memberName) 794 else: 795 code += " _OUT << \"\\\"\" << \"%s\" << \"\\\"\" << \" : \" << \"\\\"\" << \"\\\"\" << std::endl;\n" %(memberName) 796 return code 797 798 def genArrayCode(self, structName, name, typeName, str2, arraySize, needStrPrint, isArrayType, isCommaNeeded): 799 comma = "," if isCommaNeeded else "" 800 code = "" 801 arraySize = arraySize.replace(')', '') 802 needsTmp = needStrPrint or (str(self.getTypeCategory(typeName)) == 'handle') 803 804 if needStrPrint: printStr = "tmp.str()" 805 else: printStr = "\"\"" 806 807 code += " PRINT_SPACE\n" 808 code += " _OUT << \"\\\"%s\\\":\" << std::endl;\n" %(name) 809 code += " PRINT_SPACE\n" 810 if not isArrayType: 811 code += " if (%s%s) {\n" %(str2, name) 812 code += " _OUT << \"[\" << std::endl;\n" 813 code += " for (unsigned int i = 0; i < %s; i++) {\n" %(arraySize) 814 if self.isCTS and (structName == "VkPipelineLayoutCreateInfo" or structName == "VkDescriptorSetLayoutBinding"): 815 code += " bool isCommaNeeded = (i+1) != %s;\n" %(arraySize) 816 code += " if (isCommaNeeded)\n" 817 code += " {\n" 818 code += " PRINT_SPACE\n" 819 code += " _OUT << %s%s[i].getInternal() << \",\" << std::endl;\n" %(str2, name) 820 code += " }\n" 821 code += " else\n" 822 code += " {\n" 823 code += " PRINT_SPACE\n" 824 code += " _OUT << %s%s[i].getInternal() << std::endl;\n" %(str2, name) 825 code += " }\n" 826 else: 827 if needsTmp: 828 code += " std:: stringstream tmp;\n" 829 830 # Special case handling for giving unique names for pImmutableSamplers if there are multiple 831 # bindings in the same Descriptor set layout. 832 if name == "pImmutableSamplers": 833 code += " tmp << \"%s\" << \"_\" << (%sbinding) << \"_\" << i;\n" %(name, str2) 834 else: 835 code += " tmp << \"%s\" << \"_\" << i;\n" %(name) 836 837 code += " bool isCommaNeeded = (i+1) != %s;\n" %(arraySize) 838 839 if str(self.getTypeCategory(typeName)) == 'handle': 840 code += " print_%s(%s%s[i], tmp.str(), isCommaNeeded);\n" %(typeName, str2, name) 841 else: 842 if self.isCTS and name == "pipelineIdentifier": 843 code += " print_uint32_t((%s)%s%s[i], %s, isCommaNeeded);\n" %(self.baseTypeListMap["uint32_t"], str2, name, printStr) 844 else: 845 code += " print_%s(%s%s[i], %s, isCommaNeeded);\n" %(typeName, str2, name, printStr) 846 code += " }\n" 847 code += " PRINT_SPACE\n" 848 code += " _OUT << \"]\" << \"%s\" << std::endl;\n" %(comma) 849 if not isArrayType == True: 850 code += " } else {\n" 851 code += " _OUT << \"\\\"NULL\\\"\" << \"%s\" << std::endl;\n" %(comma) 852 code += " }\n" 853 return code 854 855 def genStructCode(self, param, str1, str2, str3, str4, structName, isCommaNeeded): 856 code = "" 857 memberName = "" 858 typeName = "" 859 860 for elem in param: 861 if elem.text.find('PFN_') != -1: 862 return " /** Note: Ignoring function pointer (%s). **/\n" %(elem.text) 863 864 if elem.text == 'pNext': 865 return self.genPNextCode(str2) 866 867 if elem.tag == 'name': 868 memberName = elem.text 869 870 if elem.tag == 'type': 871 typeName = elem.text 872 873 # Some arrays have constant sizes. 874 if elem.text.find("VK_") != -1: 875 return self.genArrayCode(structName, memberName, typeName, str2, elem.text, False, True, isCommaNeeded) 876 877 if self.paramIsStaticArray(param): 878 return self.genArrayCode(structName, memberName, typeName, str2, self.paramIsStaticArray(param), False, True, isCommaNeeded) 879 880 # If the struct's member is another struct, we need a different way to handle. 881 elif self.paramIsStruct(typeName) == 1: 882 code += self.generateStructMembercode(param, str1, str2, str3, str4, memberName, typeName, isCommaNeeded) 883 884 # Ignore void* data members 885 elif self.paramIsPointer(param) and typeName == 'void': 886 if structName == "VkSpecializationInfo": 887 return " print_void_data(%s%s, int(%sdataSize), \"%s\", 0);\n" %(str2, memberName, str2, memberName) 888 if self.isCTS: 889 if structName == "VkPipelineCacheCreateInfo": 890 return " print_void_data(%s%s, int(%sinitialDataSize), \"%s\", 0);\n" %(str2, memberName, str2, memberName) 891 return " /** Note: Ignoring void* data. **/\n" 892 893 # For pointers where we have the 'len' field, dump them as arrays. 894 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: 895 if memberName == "versionData": 896 return self.genArrayCode(structName, memberName, typeName, str2, param.get('len')+")", False, False, isCommaNeeded) 897 else: 898 return self.genArrayCode(structName, memberName, typeName, str2, str2+param.get('len')+")", False, False, isCommaNeeded) 899 900 # Special handling for VkPipelineMultisampleStateCreateInfo::pSampleMask 901 elif typeName in "VkSampleMask": 902 code += " %s sampleMaskSize = ((%srasterizationSamples + 31) / 32);\n" % (self.baseTypeListMap["uint32_t"], str2) 903 code += self.genArrayCode(structName, memberName, "uint32_t", str2, "sampleMaskSize", False, False, isCommaNeeded) 904 return code 905 906 # If a struct member is just a handle. 907 elif str(self.getTypeCategory(typeName)) == 'handle': 908 return self.genEmptyCode(memberName, str2, isCommaNeeded) 909 910 else: 911 code += " print_%s(%s%s, \"%s\", %s);\n" %(typeName, str2, memberName, memberName, str(isCommaNeeded)) 912 913 return code 914 915 def genStruct(self, typeinfo, typeName, alias): 916 OutputGenerator.genStruct(self, typeinfo, typeName, alias) 917 body = "" 918 typeElem = typeinfo.elem 919 920 if alias: 921 body = 'typedef ' + alias + ' ' + typeName + ';\n' 922 else: 923 genStr1 = ["" , "const "] 924 genStr2 = ["obj.", "obj->" ] 925 genStr3 = [" obj, const std::string& s, bool commaNeeded=true) {" , " * obj, const std::string& s, bool commaNeeded=true) {"] 926 genStr4 = [" if (obj.", " if (obj->"] 927 928 for index in range(len(genStr1)): 929 body += "static void print_%s(%s%s%s\n" %(typeName, genStr1[index], typeName, genStr3[index]) 930 body += " PRINT_SPACE\n" 931 body += " _OUT << \"{\" << std::endl;\n" 932 body += " INDENT(4);\n" 933 body += "\n" 934 count = 0 935 numMembers = len(typeElem.findall('.//member')) 936 937 isCommaNeeded = 1 938 for member in typeElem.findall('.//member'): 939 count = count + 1 940 if count == numMembers: 941 isCommaNeeded = 0 942 943 body += self.genStructCode(member, genStr1[index], genStr2[index], genStr3[index], genStr4[index], typeName, isCommaNeeded) 944 body += "\n" 945 946 body += " INDENT(-4);\n" 947 body += " PRINT_SPACE\n" 948 body += " if (commaNeeded)\n" 949 body += " _OUT << \"},\" << std::endl;\n" 950 body += " else\n" 951 body += " _OUT << \"}\" << std::endl;\n" 952 body += "}\n" 953 954 self.appendSection('struct', body) 955 956 def genGroup(self, groupinfo, groupName, alias=None): 957 OutputGenerator.genGroup(self, groupinfo, groupName, alias) 958 groupElem = groupinfo.elem 959 body = "" 960 section = 'enum' 961 962 body += "static std::map<%s, std::string> %s_map = {\n" %(self.baseTypeListMap["uint64_t"], groupName) 963 enums = groupElem.findall('enum') 964 965 for enum in enums: 966 if enum.get('value'): 967 body += " std::make_pair(%s, \"%s\"),\n" %(enum.get('value'), enum.get('name')) 968 969 elif enum.get('bitpos'): 970 body += " std::make_pair(1ULL << %s, \"%s\"),\n" %(enum.get('bitpos'), enum.get('name')) 971 972 #TODO: Some enums have no offset. How to handle those? 973 elif enum.get('extends') and enum.get("extnumber") and enum.get("offset"): 974 extNumber = int(enum.get("extnumber")) 975 offset = int(enum.get("offset")) 976 enumVal = self.extBase + (extNumber - 1) * self.extBlockSize + offset 977 body += " std::make_pair(%s, \"%s\"),\n" %(str(enumVal), enum.get('name')) 978 979 body += "};\n" 980 body += self.genEnumCode(groupName) 981 982 self.appendSection(section, body) 983