• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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