blob: 680bafbb8de7ba241c5ee0914c00ae714b3ed011 [file] [log] [blame]
#!/usr/bin/python3 -i
#
# Copyright 2020-2023 The Khronos Group Inc.
#
# SPDX-License-Identifier: Apache-2.0
# Description:
# -----------
# This script generates a .hpp file that creates VK structures from a
# json file.
import os
import re
import xml.dom.minidom
from generator import (GeneratorOptions, OutputGenerator, noneStr,
regSortFeatures, write)
copyright = """
/*
* Copyright (c) 2021 The Khronos Group Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*//*!
* \\file
* \\brief Defines JSON generators for Vulkan structures
*/
"""
predefinedCode = """
/********************************************************************************************/
/** This code is generated. To make changes, please modify the scripts or the relevant xml **/
/********************************************************************************************/
#pragma once
#include <iostream>
#include <map>
#include <cinttypes>
#include <algorithm>
#include <bitset>
#include <functional>
#include <sstream>
#include <cinttypes>
#include <json/json.h>
namespace vk_json_parser {
template <typename T1, typename T2>
class GlobalMem {
static constexpr size_t MAX_ALIGNMENT = alignof(std::max_align_t);
void grow(T1 size = 0) {
//push_back new single vector of size m_tabSize onto vec
void * p = calloc(size > m_tabSize ? size : m_tabSize, sizeof(T2));
assert(p);
m_vec.push_back(p);
m_pointer = 0U;
}
void * alloc(T1 size) {
// Align to the next multiple of MAX_ALIGNMENT.
size = (size + static_cast<T1>(MAX_ALIGNMENT) - 1) & ~(static_cast<T1>(MAX_ALIGNMENT) - 1);
void* result = static_cast<%s *>(m_vec.back()) + m_pointer;
m_pointer += size;
return result;
}
public:
GlobalMem(T1 tabSize_ = 32768U)
: m_tabSize(tabSize_), m_pointer(0U)
{
}
void* allocate (T1 size)
{
if (m_vec.empty() || m_pointer+size >= m_tabSize) {
grow();
}
return alloc(size);
}
void* allocate (T1 count, T1 size)
{
T1 totalSize = count * size;
if (m_vec.empty() || m_pointer+totalSize >= m_tabSize)
{
grow(totalSize);
}
return alloc(totalSize);
}
// deallocates all memory. Any use of earlier allocated elements is forbidden
void clear()
{
// remove all vectors from vec excluding the one with index 0
for (size_t i=1 ; i<m_vec.size(); i++) {
free(m_vec[i]);
}
if (!m_vec.empty()) {
m_vec.resize(1);
}
m_pointer = 0;
}
~GlobalMem()
{
clear();
if (!m_vec.empty()) {
free(m_vec[0]);
}
}
private:
std::vector< void * > m_vec;
T1 m_tabSize;
T1 m_pointer;
};
static thread_local GlobalMem<%s, %s> s_globalMem(32768U);
// To make sure the generated data is consistent across platforms,
// we typecast to 32-bit.
static void parse_size_t(const char* s, Json::Value& obj, size_t& o)
{
%s _res = static_cast<%s>(obj.asUInt());
o = _res;
}
static void parse_char(const char* s, Json::Value& obj, char o[])
{
std::string _res = obj.asString();
memcpy((void*)o, _res.c_str(), static_cast<%s>(_res.size()));
o[_res.size()] = \'\\0\';
}
static void parse_char(const char* s, Json::Value& obj, const char* const*)
{
}
static void parse_char(const char* s, Json::Value& obj, const char** o)
{
std::string _res = obj.asString();
char *writePtr = (char *)s_globalMem.allocate(static_cast<%s>(_res.size()) + 1);
memcpy((void*)writePtr, _res.c_str(), _res.size());
writePtr[_res.size()] = \'\\0\';
*o = writePtr;
}
"""
base64DecodeCodeCTS = """
// base64 encoder taken from executor/xeTestResultParser.cpp
static
std::vector<deUint8> base64decode(const std::string encoded)
{
int base64DecodeOffset = 0;
std::vector<deUint8> result;
for (std::size_t inNdx = 0; inNdx < encoded.size(); inNdx++)
{
deUint8 byte = encoded[inNdx];
deUint8 decodedBits = 0;
if (de::inRange<deUint8>(byte, 'A', 'Z'))
decodedBits = (deUint8)(byte - 'A');
else if (de::inRange<deUint8>(byte, 'a', 'z'))
decodedBits = (deUint8)(('Z' - 'A' + 1) + (byte - 'a'));
else if (de::inRange<deUint8>(byte, '0', '9'))
decodedBits = (deUint8)(('Z' - 'A' + 1) + ('z' - 'a' + 1) + (byte - '0'));
else if (byte == '+')
decodedBits = ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1);
else if (byte == '/')
decodedBits = ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 2);
else
continue; // Not an B64 input character.
int phase = base64DecodeOffset % 4;
if (phase == 0)
result.resize(result.size() + 3, 0);
// if ((int)image->data.size() < (base64DecodeOffset >> 2) * 3 + 3)
// throw TestResultParseError("Malformed base64 data");
deUint8* outPtr = result.data() + (base64DecodeOffset >> 2) * 3;
switch (phase)
{
case 0: outPtr[0] |= (deUint8)(decodedBits << 2); break;
case 1: outPtr[0] = (deUint8)(outPtr[0] | (deUint8)(decodedBits >> 4)); outPtr[1] = (deUint8)(outPtr[1] | (deUint8)((decodedBits & 0xF) << 4)); break;
case 2: outPtr[1] = (deUint8)(outPtr[1] | (deUint8)(decodedBits >> 2)); outPtr[2] = (deUint8)(outPtr[2] | (deUint8)((decodedBits & 0x3) << 6)); break;
case 3: outPtr[2] |= decodedBits; break;
default:
DE_ASSERT(false);
}
base64DecodeOffset++;
}
return result;
}
static void parse_void_data(const void* s, Json::Value& obj, void* o, int oSize)
{
std::vector<deUint8> data;
if (obj.isString())
{
data = base64decode(obj.asString());
}
else
{
data.resize(oSize);
for (int i = 0; i < std::min(oSize, (int)obj.size()); i++)
{
parse_uint8_t("pData", obj[i], const_cast<deUint8&>(data[i]));
}
}
memcpy(o, data.data(), oSize);
}
"""
base64DecodeCode = """
// base64 encoder taken from executor/xeTestResultParser.cpp
static
std::vector<uint8_t> base64decode(const std::string encoded)
{
int base64DecodeOffset = 0;
std::vector<uint8_t> result;
for (std::size_t inNdx = 0; inNdx < encoded.size(); inNdx++)
{
uint8_t byte = encoded[inNdx];
uint8_t decodedBits = 0;
if ('A' <= byte && byte <= 'Z')
decodedBits = (uint8_t)(byte - 'A');
else if ('a' <= byte && byte <= 'z')
decodedBits = (uint8_t)(('Z' - 'A' + 1) + (byte - 'a'));
else if ('0' <= byte && byte <= '9')
decodedBits = (uint8_t)(('Z' - 'A' + 1) + ('z' - 'a' + 1) + (byte - '0'));
else if (byte == '+')
decodedBits = ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 1);
else if (byte == '/')
decodedBits = ('Z' - 'A' + 1) + ('z' - 'a' + 1) + ('9' - '0' + 2);
else
continue; // Not an B64 input character.
int phase = base64DecodeOffset % 4;
if (phase == 0)
result.resize(result.size() + 3, 0);
// if ((int)image->data.size() < (base64DecodeOffset >> 2) * 3 + 3)
// throw TestResultParseError("Malformed base64 data");
uint8_t* outPtr = result.data() + (base64DecodeOffset >> 2) * 3;
switch (phase)
{
case 0: outPtr[0] |= (uint8_t)(decodedBits << 2); break;
case 1: outPtr[0] = (uint8_t)(outPtr[0] | (uint8_t)(decodedBits >> 4)); outPtr[1] = (uint8_t)(outPtr[1] | (uint8_t)((decodedBits & 0xF) << 4)); break;
case 2: outPtr[1] = (uint8_t)(outPtr[1] | (uint8_t)(decodedBits >> 2)); outPtr[2] = (uint8_t)(outPtr[2] | (uint8_t)((decodedBits & 0x3) << 6)); break;
case 3: outPtr[2] |= decodedBits; break;
default:
assert(false);
}
base64DecodeOffset++;
}
return result;
}
static void parse_void_data(const void* s, Json::Value& obj, void* o, int oSize)
{
std::vector<uint8_t> data;
if (obj.isString())
{
data = base64decode(obj.asString());
}
else
{
data.resize(oSize);
for (int i = 0; i < std::min(oSize, (int)obj.size()); i++)
{
parse_uint8_t("pData", obj[i], const_cast<uint8_t&>(data[i]));
}
}
memcpy(o, data.data(), oSize);
}
"""
headerGuardTop = """#ifndef _VULKAN_JSON_PARSER_HPP
#define _VULKAN_JSON_PARSER_HPP
"""
headerGuardBottom = """#endif // _VULKAN_JSON_PARSER_HPP"""
class JSONParserOptions(GeneratorOptions):
"""JSONParserOptions - subclass of GeneratorOptions.
Adds options used by JSONParserGenerator objects during C language header
generation."""
def __init__(self,
prefixText="",
genFuncPointers=True,
protectFile=True,
protectFeature=True,
protectProto=None,
protectProtoStr=None,
apicall='',
apientry='',
apientryp='',
isCTS = False,
indentFuncProto=True,
indentFuncPointer=False,
alignFuncParam=0,
genEnumBeginEndRange=False,
genAliasMacro=False,
aliasMacro='',
**kwargs
):
GeneratorOptions.__init__(self, **kwargs)
self.isCTS = isCTS
class JSONParserGenerator(OutputGenerator):
# This is an ordered list of sections in the header file.
TYPE_SECTIONS = ['basetype', 'handle', 'enum',
'group', 'bitmask', 'struct']
ALL_SECTIONS = TYPE_SECTIONS
def __init__(self, *args, **kwargs):
super().__init__(*args, **kwargs)
# Internal state - accumulators for different inner block text
self.sections = {section: [] for section in self.ALL_SECTIONS}
self.feature_not_empty = False
self.may_alias = None
self.featureDict = {}
self.vkscFeatureList = []
self.constDict = {}
self.baseTypeDict = {
"int32_t" : "obj.asInt()",
"uint32_t" : "obj.asUInt()",
"uint8_t" : "obj.asUInt()",
"uint64_t" : "obj.asUInt64()",
"float" : "obj.asFloat()",
"int" : "obj.asInt()",
"double" : "obj.asDouble()",
"int64_t" : "obj.asInt64()",
"uint16_t" : "obj.asUInt()",
"NvSciBufAttrList" : "obj.asInt()",
"NvSciBufObj" : "obj.asInt()",
"NvSciSyncAttrList" : "obj.asInt()",
"NvSciSyncObj" : "obj.asInt()"
}
def parseBaseTypes(self):
for baseType in self.baseTypeDict:
printStr = self.baseTypeDict[baseType]
if baseType == "uint8_t" or baseType == "uint16_t" or baseType.startswith('NvSci'):
write("static void parse_%s(const char* s, Json::Value& obj, %s& o)\n" %(baseType, self.baseTypeListMap[baseType]) +
"{\n"
" o = static_cast<%s>(%s);\n" %(self.baseTypeListMap[baseType],printStr) +
"}\n"
, file=self.outFile
)
else:
code = ""
code += "static void parse_%s(const char* s, Json::Value& obj, %s& o)\n" %(baseType, self.baseTypeListMap[baseType])
code += "{\n"
if baseType in self.constDict:
code += " if (obj.isString())\n"
for index, enumValue in enumerate(self.constDict[baseType]):
code += " %sif (obj.asString() == \"%s\")\n" %("else " if index > 0 else "", enumValue[0])
code += " o = %s;\n" %(enumValue[1])
if baseType == "float":
code += " else if (obj.asString() == \"NaN\")\n"
code += " o = std::numeric_limits<float>::quiet_NaN();\n"
code += " else\n"
code += " assert(false);\n"
code += " else\n"
code += " o = %s;\n" %(printStr)
else:
code += " o = %s;\n" %(printStr)
code += "}\n"
write(code, file=self.outFile)
def createvkscFeatureList(self):
for feature in self.registry.reg.findall('feature'):
if feature.get('api').find('vulkansc') != -1:
# Remove entries that are removed in features in VKSC profile.
requiredList = feature.findall("require")
for requiredItem in requiredList:
typeList = requiredItem.findall("type")
for typeName in typeList:
if typeName.get("name") != "":
self.featureDict[typeName.get("name")] = feature.get("name")
self.vkscFeatureList.append(typeName.get("name"))
removeItemList = feature.findall("remove")
for removeItem in removeItemList:
removeTypes = removeItem.findall("type")
for item in removeTypes:
if self.vkscFeatureList.count(item.get("name")) > 0:
self.vkscFeatureList.remove(item.get("name"))
allExtensions = self.registry.reg.findall('extensions')
for extensions in allExtensions:
extensionList = extensions.findall("extension")
for extension in extensionList:
if extension.get("supported").find("vulkansc") != -1:
requiredList = extension.findall("require")
for requiredItem in requiredList:
typeList = requiredItem.findall("type")
for typeName in typeList:
self.featureDict[typeName.get("name")] = extension.get("name")
self.vkscFeatureList.append(typeName.get("name"))
def createConstDict(self):
for enums in self.registry.reg.findall('enums'):
if enums.get("name") == "API Constants":
for enum in enums.findall('enum'):
type = enum.get("type");
if (type):
name = enum.get("name")
value = enum.get("value")
if type not in self.constDict:
self.constDict[type] = [(name, value)]
else:
self.constDict[type].append((name, value))
def printPrototypes(self):
code = ""
code += "/*************************************** Begin prototypes ***********************************/\n"
typesList = self.registry.reg.findall('types')
currentExtension = "VK_VERSION_1_0"
for types in typesList:
typeList = types.findall("type")
for type in typeList:
if type.get("name") != "":
cat = type.get("category")
name = type.get("name")
if cat in {"handle", "bitmask", "basetype", "enum", "struct"} and name in self.vkscFeatureList:
if name in self.featureDict and currentExtension != self.featureDict[name]:
if not self.isCTS and currentExtension != "VK_VERSION_1_0":
code += "#endif\n"
currentExtension = self.featureDict[name]
if self.featureDict[name] != "VK_VERSION_1_0":
if not self.isCTS:
code += "#ifdef %s\n" %(currentExtension)
code += "static void parse_%s(const char* s, Json::Value& obj, %s& o);\n" %(name, name)
if currentExtension != "VK_VERSION_1_0":
if not self.isCTS:
code += "#endif\n"
code += "/*************************************** End prototypes ***********************************/\n\n"
return code
def genStructExtensionCode(self):
code = ""
code += "static\n"
code += "void* parsePNextChain(Json::Value& obj) {\n"
code += " VkBaseInStructure o;\n"
code += " Json::Value& pNextObj = obj[\"pNext\"];\n"
code += " if (pNextObj.empty() || (pNextObj.isString() && pNextObj.asString() == \"NULL\")) return nullptr;\n\n"
code += " parse_VkStructureType(\"sType\", pNextObj[\"sType\"], (o.sType));\n"
code += " void* p = nullptr;\n"
code += " switch (o.sType) {\n"
typesList = self.registry.reg.findall('types')
currentExtension = "VK_VERSION_1_0"
for types in typesList:
typeList = types.findall("type")
for type in typeList:
if type.get('category') == 'struct' and type.get('structextends') is not None and type.get('name') in self.vkscFeatureList:
members = type.findall('member')
for m in members:
n = type.get('name')
if m.get('values'):
if n in self.featureDict and currentExtension != self.featureDict[n]:
if not self.isCTS and currentExtension != "VK_VERSION_1_0":
code += "#endif\n"
currentExtension = self.featureDict[n]
if self.featureDict[n] != "VK_VERSION_1_0":
if not self.isCTS:
code += "#ifdef %s\n" %(currentExtension)
code += " case %s:\n" %(m.get('values'))
code += " {\n"
code += " p = s_globalMem.allocate(sizeof(%s));\n" %(n)
code += " parse_%s(\"\", pNextObj, *((%s*)p));\n" %(n, n)
code += " }\n"
#code += "print_%s(((%s *)pNext), \"%s\", 1);\n" %(n, n, n)
code += " break;\n"
if currentExtension != "VK_VERSION_1_0":
if not self.isCTS:
code += "#endif\n"
code += " default: {/** **/}\n"
code += " }\n"
code += " return p;\n"
code += " }\n"
return code
def beginFile(self, genOpts):
OutputGenerator.beginFile(self, genOpts)
self.createvkscFeatureList()
self.createConstDict()
self.isCTS = genOpts.isCTS
self.baseTypeListMap = {
"int32_t" : "deInt32" if self.isCTS else "int32_t",
"uint32_t" : "deUint32" if self.isCTS else "uint32_t",
"uint8_t" : "deUint8" if self.isCTS else "uint8_t",
"uint64_t" : "deUint64" if self.isCTS else "uint64_t",
"float" : "float",
"int" : "int",
"double" : "double",
"int64_t" : "deInt64" if self.isCTS else "int64_t",
"uint16_t" : "deUint16" if self.isCTS else "uint16_t",
"NvSciBufAttrList" : "vk::pt::NvSciBufAttrList" if self.isCTS else "NvSciBufAttrList",
"NvSciBufObj" : "vk::pt::NvSciBufObj" if self.isCTS else "NvSciBufObj",
"NvSciSyncAttrList" : "vk::pt::NvSciSyncAttrList" if self.isCTS else "NvSciSyncAttrList",
"NvSciSyncObj" : "vk::pt::NvSciSyncObj" if self.isCTS else "NvSciSyncObj"
}
write(headerGuardTop, file=self.outFile, end='')
write(copyright, file=self.outFile)
write(predefinedCode % (self.baseTypeListMap["uint8_t"],
self.baseTypeListMap["uint32_t"],
self.baseTypeListMap["uint8_t"],
self.baseTypeListMap["uint32_t"],
self.baseTypeListMap["uint32_t"],
self.baseTypeListMap["uint32_t"],
self.baseTypeListMap["uint32_t"]), file=self.outFile)
self.parseBaseTypes()
if self.isCTS:
write(base64DecodeCodeCTS, file=self.outFile)
else:
write(base64DecodeCode, file=self.outFile)
write(self.printPrototypes(), file=self.outFile)
write(self.genStructExtensionCode(), file=self.outFile)
def endFile(self):
write("}//End of namespace vk_json_parser\n", file=self.outFile) # end of namespace
write(headerGuardBottom, file=self.outFile, end='') # end of _VULKAN_JSON_PARSER_HPP
OutputGenerator.endFile(self)
def beginFeature(self, interface, emit):
OutputGenerator.beginFeature(self, interface, emit)
self.sections = {section: [] for section in self.ALL_SECTIONS}
self.feature_not_empty = False
def endFeature(self):
if self.emit:
if self.feature_not_empty:
if self.genOpts.conventions.writeFeature(self.featureExtraProtect, self.genOpts.filename):
for section in self.TYPE_SECTIONS:
contents = self.sections[section]
if contents:
write('\n'.join(contents), file=self.outFile)
# Finish processing in superclass
OutputGenerator.endFeature(self)
def appendSection(self, section, text):
self.sections[section].append(text)
self.feature_not_empty = True
def genEnumCode(self, name, endIfdef):
code = ""
code += "static void parse_%s(const char* s, Json::Value& obj, %s& o) {\n" %(name, name)
code += " std::string _res = obj.asString();\n"
code += " o = (%s)%s_map[std::string(_res)];\n" %(name, name)
code += "}\n"
if not self.isCTS and endIfdef:
code += "#endif\n"
return code
def genBasetypeCode(self, str1, str2, name):
code = ""
code += "static void parse_%s(const char* s, Json::Value& obj, %s& o) {\n" %(name, name)
code += " std::string _res = obj.asString();\n"
if name == "VkBool32":
code += " //VkBool is represented as VK_TRUE and VK_FALSE in the json\n"
code += " o = (_res == \"VK_TRUE\") ? (1) : (0);\n"
elif name == "VkDeviceAddress":
code += " sscanf(_res.c_str(), \"%\" SCNu64, &o);\n"
elif name == "VkDeviceSize":
code += " if (_res == \"VK_WHOLE_SIZE\")\n"
code += " o = (~0ULL);\n"
code += " else\n"
code += " sscanf(_res.c_str(), \"%\" SCNu64, &o);\n"
elif name in ["VkFlags64", "VkPipelineStageFlags2KHR", "VkAccessFlags2KHR", "VkFormatFeatureFlags2KHR"]:
code += " sscanf(_res.c_str(), \"%\" SCNd64, &o);\n"
else:
code += " sscanf(_res.c_str(), \"%u\", &o);\n"
code += "}\n"
return code
def genHandleCode(self, str1, str2, name):
code = ""
ifdefName = ""
if name in self.featureDict and self.featureDict[name] != "VK_VERSION_1_0":
ifdefName = self.featureDict[name]
if not self.isCTS and ifdefName != "":
code += "#ifdef %s\n" %(ifdefName)
code += "static void parse_%s(const char* s, Json::Value& obj, %s& o) {\n" %(name, name)
code += "// std::string _res = obj.asString();\n"
code += "}\n"
if not self.isCTS and ifdefName != "":
code += "#endif\n"
return code
def genBitmaskCode(self, str1, str2, name, mapName):
code = ""
ifdefName = ""
if mapName in self.featureDict and self.featureDict[mapName] != "VK_VERSION_1_0":
ifdefName = self.featureDict[mapName]
elif name in self.featureDict and self.featureDict[name] != "VK_VERSION_1_0":
ifdefName = self.featureDict[name]
if ifdefName != "":
if not self.isCTS:
code += "#ifdef %s\n" %(ifdefName)
if mapName is not None:
code += "static void parse_%s(const char* s, Json::Value& obj, %s& o) {\n" %(name, name)
code += " o = (%s)0;\n" %(name)
code += " std::string _res = obj.asString();\n"
code += " std::vector<std::string> bitmasks;\n"
code += " std::istringstream inputStream(_res);\n"
code += " std::string tempStr;\n"
code += " while (getline(inputStream, tempStr, '|')) {\n"
code += " tempStr.erase(std::remove_if(tempStr.begin(), tempStr.end(), isspace), tempStr.end());\n"
code += " bitmasks.push_back(tempStr);\n"
code += " }\n"
code += " for (auto& it : bitmasks) {\n"
code += " o |= (%s)%s_map[it];\n" %(mapName, mapName)
code += " }\n"
code += "}\n"
else:
code += "static void parse_%s(const char* s, Json::Value& obj, %s& o) {\n" %(name, name)
code += " if (obj.isString()) {\n"
code += " std::string _res = obj.asString();\n"
if name in ["VkFlags64", "VkPipelineStageFlags2KHR", "VkAccessFlags2KHR", "VkFormatFeatureFlags2KHR"]:
code += " sscanf(_res.c_str(), \"%\" SCNd64, &o);\n"
else:
code += " sscanf(_res.c_str(), \"%u\", &o);\n"
code += " }\n"
code += " else {\n"
code += " o = obj.asUInt();\n"
code += " }\n"
code += "}\n"
if not self.isCTS and ifdefName != "":
code += "#endif\n"
return code
def genType(self, typeinfo, name, alias):
OutputGenerator.genType(self, typeinfo, name, alias)
typeElem = typeinfo.elem
body = ""
category = typeElem.get('category')
if category == 'funcpointer':
section = 'struct'
else:
section = category
if category in ('struct', 'union'):
self.genStruct(typeinfo, name, alias)
else:
if typeElem.get('category') == 'bitmask':
for elem in typeElem:
if elem.tag == 'name':
body += self.genBitmaskCode("(", " obj,", elem.text, typeElem.get('requires'))
elif typeElem.get('category') == 'basetype':
for elem in typeElem:
if elem.tag == 'name':
body += self.genBasetypeCode("(", " obj,", elem.text)
elif typeElem.get('category') == 'handle':
for elem in typeElem:
if elem.tag == 'name':
body += self.genHandleCode("(", " obj,", elem.text)
if body:
self.appendSection(section, body)
def paramIsStruct(self, memberType):
if str(self.getTypeCategory(memberType)) == 'struct':
return 1
return 0
# Helper taken from the validation layers code.
def paramIsPointer(self, param):
ispointer = False
for elem in param:
if elem.tag == 'type' and elem.tail is not None and '*' in elem.tail:
ispointer = True
return ispointer
# Helper taken from the validation layers code.
def paramIsStaticArray(self, param):
isstaticarray = 0
paramname = param.find('name')
if (paramname.tail is not None) and ('[' in paramname.tail) and (']' in paramname.tail):
isstaticarray = paramname.tail.count('[')
if isstaticarray:
arraySize = paramname.tail[1]
if isstaticarray:
return arraySize
else:
return 0
def paramIsStaticArrayWithMacroSize(self, param):
paramname = param.find('name')
isCharArray = param.find('type') is not None and 'char' in param.find('type').text
hasMacroSize = paramname.tail is not None and '[' in paramname.tail and param.find('enum') is not None
if hasMacroSize and not isCharArray:
return 1
else:
return 0
def paramIsCharStaticArrayWithMacroSize(self, param):
paramname = param.find('name')
if paramname.tail is None and paramname.text == "pName":
return 0
else:
return 1
def generateStructMembercode(self, param, str1, str2, str3, str4, memberName, typeName, isCommaNeeded):
length = ""
code = ""
isArr = param.get('len') is not None
if param.get('len') is not None:
length = str2 + param.get('len') + ")"
if self.paramIsPointer(param) is True and isArr is True:
code += " %s%s) = (%s*)s_globalMem.allocate(%s, sizeof(%s));\n" %(str2, memberName, typeName, length, typeName)
code += " Json::Value& obj_%s = obj[\"%s\"];\n" %(memberName, memberName)
code += " if (obj_%s.size() == 0) %s%s) = nullptr;\n" %(memberName, str2, memberName)
code += " else {\n"
code += " for (unsigned int i = 0; i < %s; i++) {\n" %(length)
code += " parse_%s(\"%s\", obj_%s[i], const_cast<%s&>(%s%s[i])));\n" %(typeName, memberName, memberName, typeName, str2, memberName)
code += " }\n"
code += " }\n"
return code
elif self.paramIsPointer(param) is True:
code += " {\n"
code += " Json::Value& obj_%s = obj[\"%s\"];\n" %(memberName, memberName)
code += " const int sz = obj_%s.size();\n" %(memberName)
code += " if (obj_%s.size() == 0) {\n" %(memberName)
code += " %s%s) = nullptr;\n"%(str2, memberName)
code += " } else {\n"
code += " %s%s) = (%s*)s_globalMem.allocate(1, sizeof(%s));\n" %(str2, memberName, typeName, typeName)
code += " parse_%s(\"%s\", obj_%s, const_cast<%s&>(*%s%s)));\n" %(typeName, memberName, memberName, typeName, str2, memberName)
code += " }\n"
code += " }\n"
return code
# TODO: With some tweak, we can use the genArrayCode() here.
if isArr is True:
code += " Json::Value& obj_%s = obj[\"%s\"];\n" %(memberName, memberName)
code += " for (unsigned int i = 0; i < obj_%s.size(); i++) {\n" %(memberName)
code += " parse_%s(\"%s\", obj_%s[i], const_cast<%s&>(%s%s[i])));\n" %(typeName, memberName, memberName, typeName, str2, memberName)
code += " }\n"
else:
code += " parse_%s(\"%s\", obj[\"%s\"], %s%s));\n" %(typeName, memberName, memberName, str2, memberName)
return code
def genArrayCode(self, structName, name, typeName, str2, arraySize, needStrPrint, isMallocNeeded):
code = ""
mappedType = self.baseTypeListMap[typeName] if self.baseTypeListMap.get(typeName) != None else typeName
if structName == "VkPipelineLayoutCreateInfo" and self.isCTS:
if isMallocNeeded:
code += " %s* %sTab = (%s*)s_globalMem.allocate(%s, sizeof(%s));\n" %(mappedType, name, mappedType, arraySize, mappedType)
code += " Json::Value& obj_%s_arr = obj[\"%s\"];\n" %(name, name)
code += " for (unsigned int i = 0; i < obj_%s_arr.size(); i++) {\n" %(name)
code += " deUint64 %sInternal = 0;\n" %(name)
code += " parse_uint64_t(\"%s\", obj_%s_arr[i], %sInternal);\n" %(name, name, name)
code += " %sTab[i] = %s(%sInternal);\n" %(name, mappedType, name)
code += " }\n"
code += " %s%s = %sTab;\n" %(str2[1:], name, name)
else:
if isMallocNeeded:
code += " %s%s) = (%s*)s_globalMem.allocate(%s, sizeof(%s));\n" %(str2, name, mappedType, arraySize, mappedType)
code += " Json::Value& obj_%s_arr = obj[\"%s\"];\n" %(name, name)
code += " for (unsigned int i = 0; i < obj_%s_arr.size(); i++) {\n" %(name)
code += " parse_%s(\"%s\", obj_%s_arr[i], const_cast<%s&>(%s%s[i])));\n" %(typeName, name, name, mappedType, str2, name)
code += " }\n"
return code
# Prints out member name followed by empty string.
def genEmptyCode(self, memberName, isCommaNeeded):
code = ""
return code
def genCTSHandleCode(self, memberName, typeName):
code = ""
code += " deUint64 %sInternal = 0;\n" %(memberName)
code += " parse_uint64_t(\"%s\", obj[\"%s\"], %sInternal);\n" %(memberName, memberName, memberName)
code += " o.%s = %s(%sInternal);\n" %(memberName, typeName, memberName)
return code
def genStructCode(self, param, str1, str2, str3, str4, structName, isCommaNeeded):
code = ""
memberName = ""
typeName = ""
for elem in param:
if elem.text.find('PFN_') != -1:
return " /** Note: Ignoring function pointer (%s). **/\n" %(elem.text)
if elem.text == 'pNext':
return " o.pNext = (%s*)parsePNextChain(obj);\n" %(structName)
if elem.tag == 'name':
memberName = elem.text
if elem.tag == 'type':
typeName = elem.text
if self.paramIsStaticArray(param):
return self.genArrayCode(structName, memberName, typeName, str2, self.paramIsStaticArray(param), False, isCommaNeeded)
elif self.paramIsStaticArrayWithMacroSize(param):
arraySize = param.find('enum').text
return self.genArrayCode(structName, memberName, typeName, str2, arraySize, False, isCommaNeeded)
# If the struct's member is another struct, we need a different way to handle.
elif self.paramIsStruct(typeName) == 1:
code += self.generateStructMembercode(param, str1, str2, str3, str4, memberName, typeName, isCommaNeeded)
# Ignore void* data members
elif self.paramIsPointer(param) and typeName == 'void':
code = ""
if structName == "VkSpecializationInfo":
code += " if (o.dataSize > 0U)\n"
code += " {\n"
code += " void* data = s_globalMem.allocate(%s(%sdataSize));\n" %(self.baseTypeListMap["uint32_t"] ,str2[1:])
code += " parse_void_data(\"%s\", obj[\"%s\"], data, int(%sdataSize));\n" %(memberName, memberName, str2[1:])
code += " %s%s = data;\n" %(str2[1:], memberName)
code += " }\n"
code += " else\n"
code += " %s%s = NULL;\n" %(str2[1:], memberName)
return code
if self.isCTS:
if structName == "VkPipelineCacheCreateInfo":
code += " if (o.initialDataSize > 0U)\n"
code += " {\n"
code += " void* data = s_globalMem.allocate(%s(%sinitialDataSize));\n" %(self.baseTypeListMap["uint32_t"], str2[1:])
code += " parse_void_data(\"%s\", obj[\"%s\"], data, int(%sinitialDataSize));\n" %(memberName, memberName, str2[1:])
code += " %s%s = data;\n" %(str2[1:], memberName)
code += " }\n"
code += " else\n"
code += " %s%s = NULL;\n" %(str2[1:], memberName)
return code
return " /** Note: Ignoring void* data. **/\n"
# For pointers where we have the 'len' field, dump them as arrays.
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:
# TODO: Check what the optional means here. In some cases, the pointer isn't populated, but the count gets set.
if param.get('optional') != 'true':
return self.genArrayCode(structName, memberName, typeName, str2, str2+param.get('len')+")", False, True)
else:
if structName == "VkDescriptorSetLayoutBinding" and self.isCTS:
code = ""
code += " Json::Value& obj_%s = obj[\"%s\"];\n" %(memberName, memberName)
code += " if (obj_%s.empty() || (obj_%s.isString() && obj_%s.asString() == \"NULL\"))\n" %(memberName, memberName, memberName)
code += " o.%s = nullptr;\n" %(memberName)
code += " else\n"
code += " {\n"
code += " %s* samplers = (%s*)s_globalMem.allocate((o.descriptorCount), sizeof(%s));\n" %(typeName, typeName, typeName)
code += " for (unsigned int i = 0; i < obj_%s.size(); i++)\n" %(memberName)
code += " {\n"
code += " deUint64 sInternal = 0;\n"
code += " parse_uint64_t(\"%s\", obj_%s[i], sInternal);\n" %(memberName, memberName)
code += " samplers[i] = %s(sInternal);\n" %(typeName)
code += " }\n"
code += " o.%s = samplers;\n" %(memberName)
code += " }"
return code
return self.genEmptyCode(memberName, isCommaNeeded)
# Special handling for VkPipelineMultisampleStateCreateInfo::pSampleMask
elif typeName in "VkSampleMask":
arraySize = "(%s(o.rasterizationSamples + 31) / 32)" %(self.baseTypeListMap["uint32_t"])
code += " %s%s) = (%s*)s_globalMem.allocate(%s, sizeof(%s));\n" %(str2, memberName, typeName, arraySize, typeName)
code += " Json::Value& obj_%s = obj[\"%s\"];\n" %(memberName, memberName)
code += " if (o.rasterizationSamples == 0 || obj_%s.size() == 0) {\n" %(memberName)
code += " %s%s) = nullptr;\n" %(str2, memberName)
code += " } else {\n"
code += " for (%s i = 0; i < %s; i++) {\n" %(self.baseTypeListMap["uint32_t"], arraySize)
code += " parse_uint32_t(\"%s\", obj_%s[i], const_cast<%s&>(%s%s[i])));\n" %(memberName, memberName, typeName, str2, memberName)
code += " }\n"
code += " }\n"
# If a struct member is just a handle.
elif str(self.getTypeCategory(typeName)) == 'handle':
if self.isCTS and (memberName == "module" or memberName == "layout" or memberName == "renderPass" or memberName == "conversion"):
return self.genCTSHandleCode(memberName, typeName)
return self.genEmptyCode(memberName, isCommaNeeded)
elif typeName in "char":
if self.paramIsCharStaticArrayWithMacroSize(param) == 0:
code += " %s%s) = (const char*)s_globalMem.allocate(255);\n" %(str2, memberName)
code += " parse_%s(\"%s\", obj[\"%s\"], &%s%s));\n" %(typeName, memberName, memberName, str2, memberName)
else:
code += " /** TODO: Handle this - %s **/\n" %(memberName)
elif typeName in "NvSciSyncFence":
code += " /** TODO: Handle this - %s **/\n" %(memberName)
else:
code += " parse_%s(\"%s\", obj[\"%s\"], %s%s));\n" %(typeName, memberName, memberName, str2, memberName)
return code
def genStruct(self, typeinfo, typeName, alias):
OutputGenerator.genStruct(self, typeinfo, typeName, alias)
body = ""
typeElem = typeinfo.elem
ifdefNeeded = False
if typeName in self.featureDict and self.featureDict[typeName] != "VK_VERSION_1_0":
ifdefNeeded = True
if not self.isCTS:
body = "#ifdef %s\n" %(self.featureDict[typeName])
if alias:
body += 'typedef ' + alias + ' ' + typeName + ';\n'
else:
genStr1 = ["("]
genStr2 = ["(o."]
genStr3 = [" o, const const char* s, bool commaNeeded) {"]
genStr4 = [" if (obj."]
index = 0
body += "static void parse_%s(const char* s, Json::Value& obj, %s& o) {\n" %(typeName, typeName)
body += "\n"
for member in typeElem.findall('.//member'):
body += self.genStructCode(member, genStr1[index], genStr2[index], genStr3[index], genStr4[index], typeName, 0)
body += "\n"
body += "}\n"
if not self.isCTS and ifdefNeeded:
body += "#endif\n"
self.appendSection('struct', body)
def genGroup(self, groupinfo, groupName, alias=None):
OutputGenerator.genGroup(self, groupinfo, groupName, alias)
groupElem = groupinfo.elem
body = ""
section = 'enum'
ifdefNeeded = False
if groupName in self.featureDict and self.featureDict[groupName] != "VK_VERSION_1_0":
ifdefNeeded = True
if not self.isCTS:
body += "#ifdef %s\n" %(self.featureDict[groupName])
if groupName == "VkPipelineStageFlagBits2KHR" or groupName == "VkAccessFlagBits2KHR" or groupName == "VkFormatFeatureFlagBits2KHR":
body += "static std::map<std::string, %s> %s_map = {\n" %(self.baseTypeListMap["uint64_t"],groupName)
else:
body += "static std::map<std::string, int> %s_map = {\n" %(groupName)
enums = groupElem.findall('enum')
for enum in enums:
if enum.get('value'):
body += " std::make_pair(\"%s\", %s),\n" %(enum.get('name'), enum.get('value'))
elif enum.get('bitpos'):
if groupName == "VkPipelineStageFlagBits2KHR" or groupName == "VkAccessFlagBits2KHR" or groupName == "VkFormatFeatureFlagBits2KHR":
body += " std::make_pair(\"%s\", 1ULL << %s),\n" %(enum.get('name'), enum.get('bitpos'))
else:
body += " std::make_pair(\"%s\", 1UL << %s),\n" %(enum.get('name'), enum.get('bitpos'))
elif enum.get('extends') and enum.get("extnumber") and enum.get("offset"):
extNumber = int(enum.get("extnumber"))
offset = int(enum.get("offset"))
enumVal = self.extBase + (extNumber - 1) * self.extBlockSize + offset
body += " std::make_pair(\"%s\", %s),\n" %(enum.get('name'), str(enumVal))
body += "};\n"
body += self.genEnumCode(groupName, ifdefNeeded)
self.appendSection(section, body)