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 creates VK structures from a 10# json file. 11 12import os 13import re 14import xml.dom.minidom 15from generator import (GeneratorOptions, OutputGenerator, noneStr, 16 regSortFeatures, write) 17 18copyright = """ 19/* 20 * Copyright (c) 2021 The Khronos Group Inc. 21 * 22 * Licensed under the Apache License, Version 2.0 (the "License"); 23 * you may not use this file except in compliance with the License. 24 * You may obtain a copy of the License at 25 * 26 * http://www.apache.org/licenses/LICENSE-2.0 27 * 28 * Unless required by applicable law or agreed to in writing, software 29 * distributed under the License is distributed on an "AS IS" BASIS, 30 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 31 * See the License for the specific language governing permissions and 32 * limitations under the License. 33 * 34 *//*! 35 * \\file 36 * \\brief Defines JSON generators for Vulkan structures 37 */ 38""" 39 40predefinedCode = """ 41/********************************************************************************************/ 42/** This code is generated. To make changes, please modify the scripts or the relevant xml **/ 43/********************************************************************************************/ 44 45#pragma once 46#include <iostream> 47#include <map> 48#include <cinttypes> 49#include <algorithm> 50#include <bitset> 51#include <functional> 52#include <sstream> 53#include <cinttypes> 54#include <json/json.h> 55 56namespace vk_json_parser { 57 58template <typename T1, typename T2> 59class GlobalMem { 60 static constexpr size_t MAX_ALIGNMENT = alignof(std::max_align_t); 61 62 void grow(T1 size = 0) { 63 //push_back new single vector of size m_tabSize onto vec 64 void * p = calloc(size > m_tabSize ? size : m_tabSize, sizeof(T2)); 65 assert(p); 66 m_vec.push_back(p); 67 m_pointer = 0U; 68 } 69 void * alloc(T1 size) { 70 // Align to the next multiple of MAX_ALIGNMENT. 71 size = (size + static_cast<T1>(MAX_ALIGNMENT) - 1) & ~(static_cast<T1>(MAX_ALIGNMENT) - 1); 72 73 void* result = static_cast<%s *>(m_vec.back()) + m_pointer; 74 m_pointer += size; 75 return result; 76 } 77public: 78 79 GlobalMem(T1 tabSize_ = 32768U) 80 : m_tabSize(tabSize_), m_pointer(0U) 81 { 82 } 83 84 void* allocate (T1 size) 85 { 86 if (m_vec.empty() || m_pointer+size >= m_tabSize) { 87 grow(); 88 } 89 return alloc(size); 90 } 91 92 void* allocate (T1 count, T1 size) 93 { 94 T1 totalSize = count * size; 95 if (m_vec.empty() || m_pointer+totalSize >= m_tabSize) 96 { 97 grow(totalSize); 98 } 99 return alloc(totalSize); 100 } 101 // deallocates all memory. Any use of earlier allocated elements is forbidden 102 void clear() 103 { 104 // remove all vectors from vec excluding the one with index 0 105 for (size_t i=1 ; i<m_vec.size(); i++) { 106 free(m_vec[i]); 107 } 108 if (!m_vec.empty()) { 109 m_vec.resize(1); 110 } 111 m_pointer = 0; 112 } 113 114 ~GlobalMem() 115 { 116 clear(); 117 if (!m_vec.empty()) { 118 free(m_vec[0]); 119 } 120 } 121 122private: 123 std::vector< void * > m_vec; 124 T1 m_tabSize; 125 T1 m_pointer; 126}; 127 128static thread_local GlobalMem<%s, %s> s_globalMem(32768U); 129 130// To make sure the generated data is consistent across platforms, 131// we typecast to 32-bit. 132static void parse_size_t(const char* s, Json::Value& obj, size_t& o) 133{ 134 %s _res = static_cast<%s>(obj.asUInt()); 135 o = _res; 136} 137 138static void parse_char(const char* s, Json::Value& obj, char o[]) 139{ 140 std::string _res = obj.asString(); 141 memcpy((void*)o, _res.c_str(), static_cast<%s>(_res.size())); 142 o[_res.size()] = \'\\0\'; 143} 144static void parse_char(const char* s, Json::Value& obj, const char* const*) 145{ 146} 147static void parse_char(const char* s, Json::Value& obj, const char** o) 148{ 149 std::string _res = obj.asString(); 150 char *writePtr = (char *)s_globalMem.allocate(static_cast<%s>(_res.size()) + 1); 151 memcpy((void*)writePtr, _res.c_str(), _res.size()); 152 writePtr[_res.size()] = \'\\0\'; 153 *o = writePtr; 154} 155 156""" 157 158base64DecodeCodeCTS = """ 159// base64 encoder taken from executor/xeTestResultParser.cpp 160 161static 162std::vector<deUint8> base64decode(const std::string encoded) 163{ 164 int base64DecodeOffset = 0; 165 std::vector<deUint8> result; 166 167 for (std::size_t inNdx = 0; inNdx < encoded.size(); inNdx++) 168 { 169 deUint8 byte = encoded[inNdx]; 170 deUint8 decodedBits = 0; 171 172 if (de::inRange<deUint8>(byte, 'A', 'Z')) 173 decodedBits = (deUint8)(byte - 'A'); 174 else if (de::inRange<deUint8>(byte, 'a', 'z')) 175 decodedBits = (deUint8)(('Z' - 'A' + 1) + (byte - 'a')); 176 else if (de::inRange<deUint8>(byte, '0', '9')) 177 decodedBits = (deUint8)(('Z' - 'A' + 1) + ('z' - 'a' + 1) + (byte - '0')); 178 else if (byte == '+') 179 decodedBits = ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1); 180 else if (byte == '/') 181 decodedBits = ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 2); 182 else 183 continue; // Not an B64 input character. 184 185 int phase = base64DecodeOffset % 4; 186 187 if (phase == 0) 188 result.resize(result.size() + 3, 0); 189 190 // if ((int)image->data.size() < (base64DecodeOffset >> 2) * 3 + 3) 191 // throw TestResultParseError("Malformed base64 data"); 192 deUint8* outPtr = result.data() + (base64DecodeOffset >> 2) * 3; 193 194 switch (phase) 195 { 196 case 0: outPtr[0] |= (deUint8)(decodedBits << 2); break; 197 case 1: outPtr[0] = (deUint8)(outPtr[0] | (deUint8)(decodedBits >> 4)); outPtr[1] = (deUint8)(outPtr[1] | (deUint8)((decodedBits & 0xF) << 4)); break; 198 case 2: outPtr[1] = (deUint8)(outPtr[1] | (deUint8)(decodedBits >> 2)); outPtr[2] = (deUint8)(outPtr[2] | (deUint8)((decodedBits & 0x3) << 6)); break; 199 case 3: outPtr[2] |= decodedBits; break; 200 default: 201 DE_ASSERT(false); 202 } 203 204 base64DecodeOffset++; 205 } 206 return result; 207} 208 209static void parse_void_data(const void* s, Json::Value& obj, void* o, int oSize) 210{ 211 std::vector<deUint8> data; 212 if (obj.isString()) 213 { 214 data = base64decode(obj.asString()); 215 } 216 else 217 { 218 data.resize(oSize); 219 for (int i = 0; i < std::min(oSize, (int)obj.size()); i++) 220 { 221 parse_uint8_t("pData", obj[i], const_cast<deUint8&>(data[i])); 222 } 223 } 224 memcpy(o, data.data(), oSize); 225} 226 227""" 228 229base64DecodeCode = """ 230// base64 encoder taken from executor/xeTestResultParser.cpp 231 232static 233std::vector<uint8_t> base64decode(const std::string encoded) 234{ 235 int base64DecodeOffset = 0; 236 std::vector<uint8_t> result; 237 238 for (std::size_t inNdx = 0; inNdx < encoded.size(); inNdx++) 239 { 240 uint8_t byte = encoded[inNdx]; 241 uint8_t decodedBits = 0; 242 243 if ('A' <= byte && byte <= 'Z') 244 decodedBits = (uint8_t)(byte - 'A'); 245 else if ('a' <= byte && byte <= 'z') 246 decodedBits = (uint8_t)(('Z' - 'A' + 1) + (byte - 'a')); 247 else if ('0' <= byte && byte <= '9') 248 decodedBits = (uint8_t)(('Z' - 'A' + 1) + ('z' - 'a' + 1) + (byte - '0')); 249 else if (byte == '+') 250 decodedBits = ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1); 251 else if (byte == '/') 252 decodedBits = ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 2); 253 else 254 continue; // Not an B64 input character. 255 256 int phase = base64DecodeOffset % 4; 257 258 if (phase == 0) 259 result.resize(result.size() + 3, 0); 260 261 // if ((int)image->data.size() < (base64DecodeOffset >> 2) * 3 + 3) 262 // throw TestResultParseError("Malformed base64 data"); 263 uint8_t* outPtr = result.data() + (base64DecodeOffset >> 2) * 3; 264 265 switch (phase) 266 { 267 case 0: outPtr[0] |= (uint8_t)(decodedBits << 2); break; 268 case 1: outPtr[0] = (uint8_t)(outPtr[0] | (uint8_t)(decodedBits >> 4)); outPtr[1] = (uint8_t)(outPtr[1] | (uint8_t)((decodedBits & 0xF) << 4)); break; 269 case 2: outPtr[1] = (uint8_t)(outPtr[1] | (uint8_t)(decodedBits >> 2)); outPtr[2] = (uint8_t)(outPtr[2] | (uint8_t)((decodedBits & 0x3) << 6)); break; 270 case 3: outPtr[2] |= decodedBits; break; 271 default: 272 assert(false); 273 } 274 275 base64DecodeOffset++; 276 } 277 return result; 278} 279 280static void parse_void_data(const void* s, Json::Value& obj, void* o, int oSize) 281{ 282 std::vector<uint8_t> data; 283 if (obj.isString()) 284 { 285 data = base64decode(obj.asString()); 286 } 287 else 288 { 289 data.resize(oSize); 290 for (int i = 0; i < std::min(oSize, (int)obj.size()); i++) 291 { 292 parse_uint8_t("pData", obj[i], const_cast<uint8_t&>(data[i])); 293 } 294 } 295 memcpy(o, data.data(), oSize); 296} 297 298""" 299 300headerGuardTop = """#ifndef _VULKAN_JSON_PARSER_HPP 301#define _VULKAN_JSON_PARSER_HPP 302""" 303 304headerGuardBottom = """#endif // _VULKAN_JSON_PARSER_HPP""" 305 306class JSONParserOptions(GeneratorOptions): 307 """JSONParserOptions - subclass of GeneratorOptions. 308 309 Adds options used by JSONParserGenerator objects during C language header 310 generation.""" 311 312 def __init__(self, 313 prefixText="", 314 genFuncPointers=True, 315 protectFile=True, 316 protectFeature=True, 317 protectProto=None, 318 protectProtoStr=None, 319 apicall='', 320 apientry='', 321 apientryp='', 322 isCTS = False, 323 indentFuncProto=True, 324 indentFuncPointer=False, 325 alignFuncParam=0, 326 genEnumBeginEndRange=False, 327 genAliasMacro=False, 328 aliasMacro='', 329 **kwargs 330 ): 331 332 GeneratorOptions.__init__(self, **kwargs) 333 self.isCTS = isCTS 334 335 336class JSONParserGenerator(OutputGenerator): 337 # This is an ordered list of sections in the header file. 338 TYPE_SECTIONS = ['basetype', 'handle', 'enum', 339 'group', 'bitmask', 'struct'] 340 ALL_SECTIONS = TYPE_SECTIONS 341 342 def __init__(self, *args, **kwargs): 343 super().__init__(*args, **kwargs) 344 # Internal state - accumulators for different inner block text 345 self.sections = {section: [] for section in self.ALL_SECTIONS} 346 self.feature_not_empty = False 347 self.may_alias = None 348 self.featureDict = {} 349 self.vkscFeatureList = [] 350 self.constDict = {} 351 self.baseTypeDict = { 352 "int32_t" : "obj.asInt()", 353 "uint32_t" : "obj.asUInt()", 354 "uint8_t" : "obj.asUInt()", 355 "uint64_t" : "obj.asUInt64()", 356 "float" : "obj.asFloat()", 357 "int" : "obj.asInt()", 358 "double" : "obj.asDouble()", 359 "int64_t" : "obj.asInt64()", 360 "uint16_t" : "obj.asUInt()", 361 "NvSciBufAttrList" : "obj.asInt()", 362 "NvSciBufObj" : "obj.asInt()", 363 "NvSciSyncAttrList" : "obj.asInt()", 364 "NvSciSyncObj" : "obj.asInt()" 365 } 366 367 def parseBaseTypes(self): 368 for baseType in self.baseTypeDict: 369 printStr = self.baseTypeDict[baseType] 370 if baseType == "uint8_t" or baseType == "uint16_t" or baseType.startswith('NvSci'): 371 write("static void parse_%s(const char* s, Json::Value& obj, %s& o)\n" %(baseType, self.baseTypeListMap[baseType]) + 372 "{\n" 373 " o = static_cast<%s>(%s);\n" %(self.baseTypeListMap[baseType],printStr) + 374 "}\n" 375 , file=self.outFile 376 ) 377 else: 378 code = "" 379 code += "static void parse_%s(const char* s, Json::Value& obj, %s& o)\n" %(baseType, self.baseTypeListMap[baseType]) 380 code += "{\n" 381 if baseType in self.constDict: 382 code += " if (obj.isString())\n" 383 for index, enumValue in enumerate(self.constDict[baseType]): 384 code += " %sif (obj.asString() == \"%s\")\n" %("else " if index > 0 else "", enumValue[0]) 385 code += " o = %s;\n" %(enumValue[1]) 386 if baseType == "float": 387 code += " else if (obj.asString() == \"NaN\")\n" 388 code += " o = std::numeric_limits<float>::quiet_NaN();\n" 389 code += " else\n" 390 code += " assert(false);\n" 391 code += " else\n" 392 code += " o = %s;\n" %(printStr) 393 else: 394 code += " o = %s;\n" %(printStr) 395 code += "}\n" 396 write(code, file=self.outFile) 397 398 def createvkscFeatureList(self): 399 for feature in self.registry.reg.findall('feature'): 400 if feature.get('api').find('vulkansc') != -1: 401 # Remove entries that are removed in features in VKSC profile. 402 requiredList = feature.findall("require") 403 404 for requiredItem in requiredList: 405 typeList = requiredItem.findall("type") 406 for typeName in typeList: 407 if typeName.get("name") != "": 408 self.featureDict[typeName.get("name")] = feature.get("name") 409 self.vkscFeatureList.append(typeName.get("name")) 410 411 removeItemList = feature.findall("remove") 412 for removeItem in removeItemList: 413 removeTypes = removeItem.findall("type") 414 for item in removeTypes: 415 if self.vkscFeatureList.count(item.get("name")) > 0: 416 self.vkscFeatureList.remove(item.get("name")) 417 418 allExtensions = self.registry.reg.findall('extensions') 419 for extensions in allExtensions: 420 extensionList = extensions.findall("extension") 421 for extension in extensionList: 422 if extension.get("supported").find("vulkansc") != -1: 423 requiredList = extension.findall("require") 424 for requiredItem in requiredList: 425 typeList = requiredItem.findall("type") 426 for typeName in typeList: 427 self.featureDict[typeName.get("name")] = extension.get("name") 428 self.vkscFeatureList.append(typeName.get("name")) 429 430 def createConstDict(self): 431 for enums in self.registry.reg.findall('enums'): 432 if enums.get("name") == "API Constants": 433 for enum in enums.findall('enum'): 434 type = enum.get("type"); 435 if (type): 436 name = enum.get("name") 437 value = enum.get("value") 438 if type not in self.constDict: 439 self.constDict[type] = [(name, value)] 440 else: 441 self.constDict[type].append((name, value)) 442 443 def printPrototypes(self): 444 code = "" 445 446 code += "/*************************************** Begin prototypes ***********************************/\n" 447 typesList = self.registry.reg.findall('types') 448 currentExtension = "VK_VERSION_1_0" 449 for types in typesList: 450 typeList = types.findall("type") 451 452 for type in typeList: 453 if type.get("name") != "": 454 cat = type.get("category") 455 name = type.get("name") 456 457 if cat in {"handle", "bitmask", "basetype", "enum", "struct"} and name in self.vkscFeatureList: 458 if name in self.featureDict and currentExtension != self.featureDict[name]: 459 if not self.isCTS and currentExtension != "VK_VERSION_1_0": 460 code += "#endif\n" 461 currentExtension = self.featureDict[name] 462 if self.featureDict[name] != "VK_VERSION_1_0": 463 if not self.isCTS: 464 code += "#ifdef %s\n" %(currentExtension) 465 code += "static void parse_%s(const char* s, Json::Value& obj, %s& o);\n" %(name, name) 466 467 if currentExtension != "VK_VERSION_1_0": 468 if not self.isCTS: 469 code += "#endif\n" 470 code += "/*************************************** End prototypes ***********************************/\n\n" 471 472 return code 473 474 def genStructExtensionCode(self): 475 code = "" 476 code += "static\n" 477 code += "void* parsePNextChain(Json::Value& obj) {\n" 478 code += " VkBaseInStructure o;\n" 479 code += " Json::Value& pNextObj = obj[\"pNext\"];\n" 480 code += " if (pNextObj.empty() || (pNextObj.isString() && pNextObj.asString() == \"NULL\")) return nullptr;\n\n" 481 code += " parse_VkStructureType(\"sType\", pNextObj[\"sType\"], (o.sType));\n" 482 code += " void* p = nullptr;\n" 483 code += " switch (o.sType) {\n" 484 485 typesList = self.registry.reg.findall('types') 486 currentExtension = "VK_VERSION_1_0" 487 for types in typesList: 488 typeList = types.findall("type") 489 for type in typeList: 490 if type.get('category') == 'struct' and type.get('structextends') is not None and type.get('name') in self.vkscFeatureList: 491 members = type.findall('member') 492 for m in members: 493 n = type.get('name') 494 if m.get('values'): 495 if n in self.featureDict and currentExtension != self.featureDict[n]: 496 if not self.isCTS and currentExtension != "VK_VERSION_1_0": 497 code += "#endif\n" 498 currentExtension = self.featureDict[n] 499 if self.featureDict[n] != "VK_VERSION_1_0": 500 if not self.isCTS: 501 code += "#ifdef %s\n" %(currentExtension) 502 code += " case %s:\n" %(m.get('values')) 503 code += " {\n" 504 code += " p = s_globalMem.allocate(sizeof(%s));\n" %(n) 505 code += " parse_%s(\"\", pNextObj, *((%s*)p));\n" %(n, n) 506 code += " }\n" 507 #code += "print_%s(((%s *)pNext), \"%s\", 1);\n" %(n, n, n) 508 code += " break;\n" 509 510 if currentExtension != "VK_VERSION_1_0": 511 if not self.isCTS: 512 code += "#endif\n" 513 code += " default: {/** **/}\n" 514 code += " }\n" 515 code += " return p;\n" 516 code += " }\n" 517 518 return code 519 520 def beginFile(self, genOpts): 521 OutputGenerator.beginFile(self, genOpts) 522 523 self.createvkscFeatureList() 524 self.createConstDict() 525 526 self.isCTS = genOpts.isCTS 527 528 self.baseTypeListMap = { 529 "int32_t" : "deInt32" if self.isCTS else "int32_t", 530 "uint32_t" : "deUint32" if self.isCTS else "uint32_t", 531 "uint8_t" : "deUint8" if self.isCTS else "uint8_t", 532 "uint64_t" : "deUint64" if self.isCTS else "uint64_t", 533 "float" : "float", 534 "int" : "int", 535 "double" : "double", 536 "int64_t" : "deInt64" if self.isCTS else "int64_t", 537 "uint16_t" : "deUint16" if self.isCTS else "uint16_t", 538 "NvSciBufAttrList" : "vk::pt::NvSciBufAttrList" if self.isCTS else "NvSciBufAttrList", 539 "NvSciBufObj" : "vk::pt::NvSciBufObj" if self.isCTS else "NvSciBufObj", 540 "NvSciSyncAttrList" : "vk::pt::NvSciSyncAttrList" if self.isCTS else "NvSciSyncAttrList", 541 "NvSciSyncObj" : "vk::pt::NvSciSyncObj" if self.isCTS else "NvSciSyncObj" 542 } 543 544 write(headerGuardTop, file=self.outFile, end='') 545 write(copyright, file=self.outFile) 546 write(predefinedCode % (self.baseTypeListMap["uint8_t"], 547 self.baseTypeListMap["uint32_t"], 548 self.baseTypeListMap["uint8_t"], 549 self.baseTypeListMap["uint32_t"], 550 self.baseTypeListMap["uint32_t"], 551 self.baseTypeListMap["uint32_t"], 552 self.baseTypeListMap["uint32_t"]), file=self.outFile) 553 554 self.parseBaseTypes() 555 if self.isCTS: 556 write(base64DecodeCodeCTS, file=self.outFile) 557 else: 558 write(base64DecodeCode, file=self.outFile) 559 560 write(self.printPrototypes(), file=self.outFile) 561 562 write(self.genStructExtensionCode(), file=self.outFile) 563 564 def endFile(self): 565 write("}//End of namespace vk_json_parser\n", file=self.outFile) # end of namespace 566 write(headerGuardBottom, file=self.outFile, end='') # end of _VULKAN_JSON_PARSER_HPP 567 OutputGenerator.endFile(self) 568 569 def beginFeature(self, interface, emit): 570 OutputGenerator.beginFeature(self, interface, emit) 571 self.sections = {section: [] for section in self.ALL_SECTIONS} 572 self.feature_not_empty = False 573 574 def endFeature(self): 575 if self.emit: 576 if self.feature_not_empty: 577 if self.genOpts.conventions.writeFeature(self.featureExtraProtect, self.genOpts.filename): 578 579 for section in self.TYPE_SECTIONS: 580 contents = self.sections[section] 581 if contents: 582 write('\n'.join(contents), file=self.outFile) 583 584 # Finish processing in superclass 585 OutputGenerator.endFeature(self) 586 587 def appendSection(self, section, text): 588 self.sections[section].append(text) 589 self.feature_not_empty = True 590 591 def genEnumCode(self, name, endIfdef): 592 code = "" 593 code += "static void parse_%s(const char* s, Json::Value& obj, %s& o) {\n" %(name, name) 594 code += " std::string _res = obj.asString();\n" 595 code += " o = (%s)%s_map[std::string(_res)];\n" %(name, name) 596 code += "}\n" 597 if not self.isCTS and endIfdef: 598 code += "#endif\n" 599 600 return code 601 602 def genBasetypeCode(self, str1, str2, name): 603 code = "" 604 code += "static void parse_%s(const char* s, Json::Value& obj, %s& o) {\n" %(name, name) 605 code += " std::string _res = obj.asString();\n" 606 if name == "VkBool32": 607 code += " //VkBool is represented as VK_TRUE and VK_FALSE in the json\n" 608 code += " o = (_res == \"VK_TRUE\") ? (1) : (0);\n" 609 elif name == "VkDeviceAddress": 610 code += " sscanf(_res.c_str(), \"%\" SCNu64, &o);\n" 611 elif name == "VkDeviceSize": 612 code += " if (_res == \"VK_WHOLE_SIZE\")\n" 613 code += " o = (~0ULL);\n" 614 code += " else\n" 615 code += " sscanf(_res.c_str(), \"%\" SCNu64, &o);\n" 616 elif name in ["VkFlags64", "VkPipelineStageFlags2KHR", "VkAccessFlags2KHR", "VkFormatFeatureFlags2KHR"]: 617 code += " sscanf(_res.c_str(), \"%\" SCNd64, &o);\n" 618 else: 619 code += " sscanf(_res.c_str(), \"%u\", &o);\n" 620 code += "}\n" 621 return code 622 623 def genHandleCode(self, str1, str2, name): 624 code = "" 625 ifdefName = "" 626 if name in self.featureDict and self.featureDict[name] != "VK_VERSION_1_0": 627 ifdefName = self.featureDict[name] 628 if not self.isCTS and ifdefName != "": 629 code += "#ifdef %s\n" %(ifdefName) 630 code += "static void parse_%s(const char* s, Json::Value& obj, %s& o) {\n" %(name, name) 631 code += "// std::string _res = obj.asString();\n" 632 code += "}\n" 633 if not self.isCTS and ifdefName != "": 634 code += "#endif\n" 635 return code 636 637 def genBitmaskCode(self, str1, str2, name, mapName): 638 code = "" 639 ifdefName = "" 640 if mapName in self.featureDict and self.featureDict[mapName] != "VK_VERSION_1_0": 641 ifdefName = self.featureDict[mapName] 642 elif name in self.featureDict and self.featureDict[name] != "VK_VERSION_1_0": 643 ifdefName = self.featureDict[name] 644 if ifdefName != "": 645 if not self.isCTS: 646 code += "#ifdef %s\n" %(ifdefName) 647 648 if mapName is not None: 649 code += "static void parse_%s(const char* s, Json::Value& obj, %s& o) {\n" %(name, name) 650 code += " o = (%s)0;\n" %(name) 651 code += " std::string _res = obj.asString();\n" 652 code += " std::vector<std::string> bitmasks;\n" 653 code += " std::istringstream inputStream(_res);\n" 654 code += " std::string tempStr;\n" 655 code += " while (getline(inputStream, tempStr, '|')) {\n" 656 code += " tempStr.erase(std::remove_if(tempStr.begin(), tempStr.end(), isspace), tempStr.end());\n" 657 code += " bitmasks.push_back(tempStr);\n" 658 code += " }\n" 659 code += " for (auto& it : bitmasks) {\n" 660 code += " o |= (%s)%s_map[it];\n" %(mapName, mapName) 661 code += " }\n" 662 code += "}\n" 663 else: 664 code += "static void parse_%s(const char* s, Json::Value& obj, %s& o) {\n" %(name, name) 665 code += " if (obj.isString()) {\n" 666 code += " std::string _res = obj.asString();\n" 667 if name in ["VkFlags64", "VkPipelineStageFlags2KHR", "VkAccessFlags2KHR", "VkFormatFeatureFlags2KHR"]: 668 code += " sscanf(_res.c_str(), \"%\" SCNd64, &o);\n" 669 else: 670 code += " sscanf(_res.c_str(), \"%u\", &o);\n" 671 code += " }\n" 672 code += " else {\n" 673 code += " o = obj.asUInt();\n" 674 code += " }\n" 675 676 code += "}\n" 677 678 if not self.isCTS and ifdefName != "": 679 code += "#endif\n" 680 681 return code 682 683 def genType(self, typeinfo, name, alias): 684 OutputGenerator.genType(self, typeinfo, name, alias) 685 typeElem = typeinfo.elem 686 body = "" 687 688 category = typeElem.get('category') 689 if category == 'funcpointer': 690 section = 'struct' 691 else: 692 section = category 693 694 if category in ('struct', 'union'): 695 self.genStruct(typeinfo, name, alias) 696 else: 697 if typeElem.get('category') == 'bitmask': 698 for elem in typeElem: 699 if elem.tag == 'name': 700 body += self.genBitmaskCode("(", " obj,", elem.text, typeElem.get('requires')) 701 702 elif typeElem.get('category') == 'basetype': 703 for elem in typeElem: 704 if elem.tag == 'name': 705 body += self.genBasetypeCode("(", " obj,", elem.text) 706 707 elif typeElem.get('category') == 'handle': 708 for elem in typeElem: 709 if elem.tag == 'name': 710 body += self.genHandleCode("(", " obj,", elem.text) 711 712 if body: 713 self.appendSection(section, body) 714 715 def paramIsStruct(self, memberType): 716 if str(self.getTypeCategory(memberType)) == 'struct': 717 return 1 718 return 0 719 720 # Helper taken from the validation layers code. 721 def paramIsPointer(self, param): 722 ispointer = False 723 for elem in param: 724 if elem.tag == 'type' and elem.tail is not None and '*' in elem.tail: 725 ispointer = True 726 return ispointer 727 728 # Helper taken from the validation layers code. 729 def paramIsStaticArray(self, param): 730 isstaticarray = 0 731 paramname = param.find('name') 732 if (paramname.tail is not None) and ('[' in paramname.tail) and (']' in paramname.tail): 733 isstaticarray = paramname.tail.count('[') 734 if isstaticarray: 735 arraySize = paramname.tail[1] 736 737 if isstaticarray: 738 return arraySize 739 else: 740 return 0 741 742 def paramIsStaticArrayWithMacroSize(self, param): 743 paramname = param.find('name') 744 isCharArray = param.find('type') is not None and 'char' in param.find('type').text 745 hasMacroSize = paramname.tail is not None and '[' in paramname.tail and param.find('enum') is not None 746 if hasMacroSize and not isCharArray: 747 return 1 748 else: 749 return 0 750 751 def paramIsCharStaticArrayWithMacroSize(self, param): 752 paramname = param.find('name') 753 if paramname.tail is None and paramname.text == "pName": 754 return 0 755 else: 756 return 1 757 758 def generateStructMembercode(self, param, str1, str2, str3, str4, memberName, typeName, isCommaNeeded): 759 length = "" 760 code = "" 761 isArr = param.get('len') is not None 762 763 if param.get('len') is not None: 764 length = str2 + param.get('len') + ")" 765 766 if self.paramIsPointer(param) is True and isArr is True: 767 code += " %s%s) = (%s*)s_globalMem.allocate(%s, sizeof(%s));\n" %(str2, memberName, typeName, length, typeName) 768 code += " Json::Value& obj_%s = obj[\"%s\"];\n" %(memberName, memberName) 769 code += " if (obj_%s.size() == 0) %s%s) = nullptr;\n" %(memberName, str2, memberName) 770 code += " else {\n" 771 code += " for (unsigned int i = 0; i < %s; i++) {\n" %(length) 772 code += " parse_%s(\"%s\", obj_%s[i], const_cast<%s&>(%s%s[i])));\n" %(typeName, memberName, memberName, typeName, str2, memberName) 773 code += " }\n" 774 code += " }\n" 775 return code 776 elif self.paramIsPointer(param) is True: 777 code += " {\n" 778 code += " Json::Value& obj_%s = obj[\"%s\"];\n" %(memberName, memberName) 779 code += " const int sz = obj_%s.size();\n" %(memberName) 780 code += " if (obj_%s.size() == 0) {\n" %(memberName) 781 code += " %s%s) = nullptr;\n"%(str2, memberName) 782 code += " } else {\n" 783 code += " %s%s) = (%s*)s_globalMem.allocate(1, sizeof(%s));\n" %(str2, memberName, typeName, typeName) 784 code += " parse_%s(\"%s\", obj_%s, const_cast<%s&>(*%s%s)));\n" %(typeName, memberName, memberName, typeName, str2, memberName) 785 code += " }\n" 786 code += " }\n" 787 return code 788 789 # TODO: With some tweak, we can use the genArrayCode() here. 790 if isArr is True: 791 code += " Json::Value& obj_%s = obj[\"%s\"];\n" %(memberName, memberName) 792 code += " for (unsigned int i = 0; i < obj_%s.size(); i++) {\n" %(memberName) 793 code += " parse_%s(\"%s\", obj_%s[i], const_cast<%s&>(%s%s[i])));\n" %(typeName, memberName, memberName, typeName, str2, memberName) 794 code += " }\n" 795 else: 796 code += " parse_%s(\"%s\", obj[\"%s\"], %s%s));\n" %(typeName, memberName, memberName, str2, memberName) 797 798 return code 799 800 def genArrayCode(self, structName, name, typeName, str2, arraySize, needStrPrint, isMallocNeeded): 801 code = "" 802 mappedType = self.baseTypeListMap[typeName] if self.baseTypeListMap.get(typeName) != None else typeName 803 if structName == "VkPipelineLayoutCreateInfo" and self.isCTS: 804 if isMallocNeeded: 805 code += " %s* %sTab = (%s*)s_globalMem.allocate(%s, sizeof(%s));\n" %(mappedType, name, mappedType, arraySize, mappedType) 806 code += " Json::Value& obj_%s_arr = obj[\"%s\"];\n" %(name, name) 807 code += " for (unsigned int i = 0; i < obj_%s_arr.size(); i++) {\n" %(name) 808 code += " deUint64 %sInternal = 0;\n" %(name) 809 code += " parse_uint64_t(\"%s\", obj_%s_arr[i], %sInternal);\n" %(name, name, name) 810 code += " %sTab[i] = %s(%sInternal);\n" %(name, mappedType, name) 811 code += " }\n" 812 code += " %s%s = %sTab;\n" %(str2[1:], name, name) 813 else: 814 if isMallocNeeded: 815 code += " %s%s) = (%s*)s_globalMem.allocate(%s, sizeof(%s));\n" %(str2, name, mappedType, arraySize, mappedType) 816 code += " Json::Value& obj_%s_arr = obj[\"%s\"];\n" %(name, name) 817 code += " for (unsigned int i = 0; i < obj_%s_arr.size(); i++) {\n" %(name) 818 code += " parse_%s(\"%s\", obj_%s_arr[i], const_cast<%s&>(%s%s[i])));\n" %(typeName, name, name, mappedType, str2, name) 819 code += " }\n" 820 821 return code 822 823 # Prints out member name followed by empty string. 824 def genEmptyCode(self, memberName, isCommaNeeded): 825 code = "" 826 return code 827 828 def genCTSHandleCode(self, memberName, typeName): 829 code = "" 830 code += " deUint64 %sInternal = 0;\n" %(memberName) 831 code += " parse_uint64_t(\"%s\", obj[\"%s\"], %sInternal);\n" %(memberName, memberName, memberName) 832 code += " o.%s = %s(%sInternal);\n" %(memberName, typeName, memberName) 833 return code 834 835 def genStructCode(self, param, str1, str2, str3, str4, structName, isCommaNeeded): 836 code = "" 837 memberName = "" 838 typeName = "" 839 840 for elem in param: 841 if elem.text.find('PFN_') != -1: 842 return " /** Note: Ignoring function pointer (%s). **/\n" %(elem.text) 843 844 if elem.text == 'pNext': 845 return " o.pNext = (%s*)parsePNextChain(obj);\n" %(structName) 846 847 if elem.tag == 'name': 848 memberName = elem.text 849 850 if elem.tag == 'type': 851 typeName = elem.text 852 853 if self.paramIsStaticArray(param): 854 return self.genArrayCode(structName, memberName, typeName, str2, self.paramIsStaticArray(param), False, isCommaNeeded) 855 856 elif self.paramIsStaticArrayWithMacroSize(param): 857 arraySize = param.find('enum').text 858 return self.genArrayCode(structName, memberName, typeName, str2, arraySize, False, isCommaNeeded) 859 860 # If the struct's member is another struct, we need a different way to handle. 861 elif self.paramIsStruct(typeName) == 1: 862 code += self.generateStructMembercode(param, str1, str2, str3, str4, memberName, typeName, isCommaNeeded) 863 864 # Ignore void* data members 865 elif self.paramIsPointer(param) and typeName == 'void': 866 code = "" 867 if structName == "VkSpecializationInfo": 868 code += " if (o.dataSize > 0U)\n" 869 code += " {\n" 870 code += " void* data = s_globalMem.allocate(%s(%sdataSize));\n" %(self.baseTypeListMap["uint32_t"] ,str2[1:]) 871 code += " parse_void_data(\"%s\", obj[\"%s\"], data, int(%sdataSize));\n" %(memberName, memberName, str2[1:]) 872 code += " %s%s = data;\n" %(str2[1:], memberName) 873 code += " }\n" 874 code += " else\n" 875 code += " %s%s = NULL;\n" %(str2[1:], memberName) 876 return code 877 if self.isCTS: 878 if structName == "VkPipelineCacheCreateInfo": 879 code += " if (o.initialDataSize > 0U)\n" 880 code += " {\n" 881 code += " void* data = s_globalMem.allocate(%s(%sinitialDataSize));\n" %(self.baseTypeListMap["uint32_t"], str2[1:]) 882 code += " parse_void_data(\"%s\", obj[\"%s\"], data, int(%sinitialDataSize));\n" %(memberName, memberName, str2[1:]) 883 code += " %s%s = data;\n" %(str2[1:], memberName) 884 code += " }\n" 885 code += " else\n" 886 code += " %s%s = NULL;\n" %(str2[1:], memberName) 887 return code 888 return " /** Note: Ignoring void* data. **/\n" 889 890 # For pointers where we have the 'len' field, dump them as arrays. 891 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: 892 # TODO: Check what the optional means here. In some cases, the pointer isn't populated, but the count gets set. 893 if param.get('optional') != 'true': 894 return self.genArrayCode(structName, memberName, typeName, str2, str2+param.get('len')+")", False, True) 895 else: 896 if structName == "VkDescriptorSetLayoutBinding" and self.isCTS: 897 code = "" 898 code += " Json::Value& obj_%s = obj[\"%s\"];\n" %(memberName, memberName) 899 code += " if (obj_%s.empty() || (obj_%s.isString() && obj_%s.asString() == \"NULL\"))\n" %(memberName, memberName, memberName) 900 code += " o.%s = nullptr;\n" %(memberName) 901 code += " else\n" 902 code += " {\n" 903 code += " %s* samplers = (%s*)s_globalMem.allocate((o.descriptorCount), sizeof(%s));\n" %(typeName, typeName, typeName) 904 code += " for (unsigned int i = 0; i < obj_%s.size(); i++)\n" %(memberName) 905 code += " {\n" 906 code += " deUint64 sInternal = 0;\n" 907 code += " parse_uint64_t(\"%s\", obj_%s[i], sInternal);\n" %(memberName, memberName) 908 code += " samplers[i] = %s(sInternal);\n" %(typeName) 909 code += " }\n" 910 code += " o.%s = samplers;\n" %(memberName) 911 code += " }" 912 return code 913 return self.genEmptyCode(memberName, isCommaNeeded) 914 915 # Special handling for VkPipelineMultisampleStateCreateInfo::pSampleMask 916 elif typeName in "VkSampleMask": 917 arraySize = "(%s(o.rasterizationSamples + 31) / 32)" %(self.baseTypeListMap["uint32_t"]) 918 code += " %s%s) = (%s*)s_globalMem.allocate(%s, sizeof(%s));\n" %(str2, memberName, typeName, arraySize, typeName) 919 code += " Json::Value& obj_%s = obj[\"%s\"];\n" %(memberName, memberName) 920 code += " if (o.rasterizationSamples == 0 || obj_%s.size() == 0) {\n" %(memberName) 921 code += " %s%s) = nullptr;\n" %(str2, memberName) 922 code += " } else {\n" 923 code += " for (%s i = 0; i < %s; i++) {\n" %(self.baseTypeListMap["uint32_t"], arraySize) 924 code += " parse_uint32_t(\"%s\", obj_%s[i], const_cast<%s&>(%s%s[i])));\n" %(memberName, memberName, typeName, str2, memberName) 925 code += " }\n" 926 code += " }\n" 927 928 # If a struct member is just a handle. 929 elif str(self.getTypeCategory(typeName)) == 'handle': 930 if self.isCTS and (memberName == "module" or memberName == "layout" or memberName == "renderPass" or memberName == "conversion"): 931 return self.genCTSHandleCode(memberName, typeName) 932 return self.genEmptyCode(memberName, isCommaNeeded) 933 934 elif typeName in "char": 935 if self.paramIsCharStaticArrayWithMacroSize(param) == 0: 936 code += " %s%s) = (const char*)s_globalMem.allocate(255);\n" %(str2, memberName) 937 code += " parse_%s(\"%s\", obj[\"%s\"], &%s%s));\n" %(typeName, memberName, memberName, str2, memberName) 938 else: 939 code += " /** TODO: Handle this - %s **/\n" %(memberName) 940 941 elif typeName in "NvSciSyncFence": 942 code += " /** TODO: Handle this - %s **/\n" %(memberName) 943 944 else: 945 code += " parse_%s(\"%s\", obj[\"%s\"], %s%s));\n" %(typeName, memberName, memberName, str2, memberName) 946 947 return code 948 949 def genStruct(self, typeinfo, typeName, alias): 950 OutputGenerator.genStruct(self, typeinfo, typeName, alias) 951 body = "" 952 typeElem = typeinfo.elem 953 ifdefNeeded = False 954 955 if typeName in self.featureDict and self.featureDict[typeName] != "VK_VERSION_1_0": 956 ifdefNeeded = True 957 if not self.isCTS: 958 body = "#ifdef %s\n" %(self.featureDict[typeName]) 959 960 if alias: 961 body += 'typedef ' + alias + ' ' + typeName + ';\n' 962 else: 963 genStr1 = ["("] 964 genStr2 = ["(o."] 965 genStr3 = [" o, const const char* s, bool commaNeeded) {"] 966 genStr4 = [" if (obj."] 967 968 index = 0 969 body += "static void parse_%s(const char* s, Json::Value& obj, %s& o) {\n" %(typeName, typeName) 970 body += "\n" 971 972 for member in typeElem.findall('.//member'): 973 body += self.genStructCode(member, genStr1[index], genStr2[index], genStr3[index], genStr4[index], typeName, 0) 974 body += "\n" 975 976 body += "}\n" 977 978 if not self.isCTS and ifdefNeeded: 979 body += "#endif\n" 980 981 self.appendSection('struct', body) 982 983 def genGroup(self, groupinfo, groupName, alias=None): 984 OutputGenerator.genGroup(self, groupinfo, groupName, alias) 985 groupElem = groupinfo.elem 986 body = "" 987 section = 'enum' 988 ifdefNeeded = False 989 990 if groupName in self.featureDict and self.featureDict[groupName] != "VK_VERSION_1_0": 991 ifdefNeeded = True 992 if not self.isCTS: 993 body += "#ifdef %s\n" %(self.featureDict[groupName]) 994 995 if groupName == "VkPipelineStageFlagBits2KHR" or groupName == "VkAccessFlagBits2KHR" or groupName == "VkFormatFeatureFlagBits2KHR": 996 body += "static std::map<std::string, %s> %s_map = {\n" %(self.baseTypeListMap["uint64_t"],groupName) 997 else: 998 body += "static std::map<std::string, int> %s_map = {\n" %(groupName) 999 enums = groupElem.findall('enum') 1000 1001 for enum in enums: 1002 if enum.get('value'): 1003 body += " std::make_pair(\"%s\", %s),\n" %(enum.get('name'), enum.get('value')) 1004 1005 elif enum.get('bitpos'): 1006 if groupName == "VkPipelineStageFlagBits2KHR" or groupName == "VkAccessFlagBits2KHR" or groupName == "VkFormatFeatureFlagBits2KHR": 1007 body += " std::make_pair(\"%s\", 1ULL << %s),\n" %(enum.get('name'), enum.get('bitpos')) 1008 else: 1009 body += " std::make_pair(\"%s\", 1UL << %s),\n" %(enum.get('name'), enum.get('bitpos')) 1010 1011 elif enum.get('extends') and enum.get("extnumber") and enum.get("offset"): 1012 extNumber = int(enum.get("extnumber")) 1013 offset = int(enum.get("offset")) 1014 enumVal = self.extBase + (extNumber - 1) * self.extBlockSize + offset 1015 body += " std::make_pair(\"%s\", %s),\n" %(enum.get('name'), str(enumVal)) 1016 1017 body += "};\n" 1018 body += self.genEnumCode(groupName, ifdefNeeded) 1019 1020 self.appendSection(section, body) 1021