From 594acb2ecddca663eb102c5ebfe7a27776ac84df Mon Sep 17 00:00:00 2001 From: asuessenbach Date: Thu, 5 Mar 2020 11:02:55 +0100 Subject: [PATCH] Improve handling of disabled extensions. (Partly) resolves #531 --- VulkanHppGenerator.cpp | 205 +++++++++++++++++++++++++++++------------ VulkanHppGenerator.hpp | 21 ++++- 2 files changed, 163 insertions(+), 63 deletions(-) diff --git a/VulkanHppGenerator.cpp b/VulkanHppGenerator.cpp index eacc84a..a86f4d9 100644 --- a/VulkanHppGenerator.cpp +++ b/VulkanHppGenerator.cpp @@ -3470,9 +3470,14 @@ void VulkanHppGenerator::checkCorrectness() { check(resultCodes.find(sc) != resultCodes.end(), command.second.xmlLine, "command uses unknown success code <" + sc + ">"); } - // check that functions returning a VkResult specify successcodes check((command.second.returnType != "VkResult") || !command.second.successCodes.empty(), command.second.xmlLine, "missing successcodes on command <" + command.first + "> returning VkResult!"); + + for (auto const& p : command.second.params) + { + check(m_types.find(p.type.type) != m_types.end(), p.xmlLine, "comand uses parameter of unknown type <" + p.type.type + ">"); + } + check(m_types.find(command.second.returnType) != m_types.end(), command.second.xmlLine, "command uses unknown return type <" + command.second.returnType + ">"); } } } @@ -3758,7 +3763,7 @@ void VulkanHppGenerator::readBaseType(tinyxml2::XMLElement const* element, std:: check(typeData.postfix.empty(), line, "unexpected type postfix <" + typeData.postfix + ">"); check(m_baseTypes.insert(std::make_pair(nameData.name, BaseTypeData(typeData.type, line))).second, line, "basetype <" + nameData.name + "> already specified"); - check(m_types.insert(nameData.name).second, line, "basetype <" + nameData.name + "> already specified as a type"); + check(m_types.insert(std::make_pair(nameData.name, TypeCategory::BaseType)).second, line, "basetype <" + nameData.name + "> already specified as a type"); } void VulkanHppGenerator::readBitmask(tinyxml2::XMLElement const* element, std::map const& attributes) @@ -3797,7 +3802,7 @@ void VulkanHppGenerator::readBitmask(tinyxml2::XMLElement const* element, std::m check(m_commandToHandle.find(nameData.name) == m_commandToHandle.end(), line, "command <" + nameData.name + "> already specified"); m_bitmasks.insert(std::make_pair(nameData.name, BitmaskData(requirements, typeData.type, line))); - check(m_types.insert(nameData.name).second, line, "bitmask <" + nameData.name + "> already specified as a type"); + check(m_types.insert(std::make_pair(nameData.name, TypeCategory::Bitmask)).second, line, "bitmask <" + nameData.name + "> already specified as a type"); } } @@ -3824,7 +3829,7 @@ void VulkanHppGenerator::readBitmaskAlias(tinyxml2::XMLElement const* element, s check(bitmasksIt != m_bitmasks.end(), line, "missing alias <" + alias + ">."); check(bitmasksIt->second.alias.empty(), line, "alias for bitmask <" + bitmasksIt->first + "> already specified as <" + bitmasksIt->second.alias + ">"); bitmasksIt->second.alias = name; - check(m_types.insert(name).second, line, "aliased bitmask <" + name + "> already specified as a type"); + check(m_types.insert(std::make_pair(name, TypeCategory::Bitmask)).second, line, "aliased bitmask <" + name + "> already specified as a type"); } void VulkanHppGenerator::readCommand(tinyxml2::XMLElement const* element) @@ -3937,7 +3942,7 @@ VulkanHppGenerator::ParamData VulkanHppGenerator::readCommandParam(tinyxml2::XML std::map attributes = getAttributes(element); checkAttributes(line, attributes, {}, { { "externsync",{} },{ "len",{} },{ "noautovalidity",{ "true" } },{ "optional",{ "false", "true" } } }); - ParamData paramData; + ParamData paramData(line); for (auto attribute : attributes) { if (attribute.first == "len") @@ -4048,7 +4053,7 @@ void VulkanHppGenerator::readDefine(tinyxml2::XMLElement const* element, std::ma tinyxml2::XMLElement const* child = element->FirstChildElement(); check(child && (strcmp(child->Value(), "name") == 0) && child->GetText(), line, "unexpected formatting of type category=define"); name = child->GetText(); - check(m_types.insert(name).second, line, "type <" + name + "> has already been speficied"); + check(m_types.insert(std::make_pair(name, TypeCategory::Define)).second, line, "type <" + name + "> has already been speficied"); } else { @@ -4355,16 +4360,23 @@ void VulkanHppGenerator::readExtensionDisabledCommand(tinyxml2::XMLElement const checkElements(line, getChildElements(element), {}); std::string name = attributes.find("name")->second; - std::string strippedName = startLowerCase(stripPrefix(name, "vk")); // first unlink the command from its class auto commandToHandleIt = m_commandToHandle.find(name); check(commandToHandleIt != m_commandToHandle.end(), line, "try to remove unknown command <" + name + ">"); auto handlesIt = m_handles.find(m_commandToHandle.find(name)->second); check(handlesIt != m_handles.end(), line, "cannot find handle corresponding to command <" + name + ">"); - auto it = handlesIt->second.commands.find(name); - check(it != handlesIt->second.commands.end(), line, "cannot find command <" + name + "> in commands associated with handle <" + handlesIt->first + ">"); - handlesIt->second.commands.erase(it); + auto commandIt = handlesIt->second.commands.find(name); + check(commandIt != handlesIt->second.commands.end(), line, "cannot find command <" + name + "> in commands associated with handle <" + handlesIt->first + ">"); + if (!commandIt->second.aliases.empty()) + { + // if there's an alias of the to-be-removed command, insert that as a new command with the very same CommandData (minus its alias) + check(commandIt->second.aliases.size() == 1, line, "try to disable command <" + name + "> with more than one alias -> don't know what to do"); + std::string aliasName = *commandIt->second.aliases.begin(); + commandIt->second.aliases.clear(); + handlesIt->second.commands.insert(std::make_pair(aliasName, commandIt->second)); + } + handlesIt->second.commands.erase(commandIt); // then remove the command from the command-to-handle map m_commandToHandle.erase(commandToHandleIt); @@ -4436,10 +4448,40 @@ void VulkanHppGenerator::readExtensionDisabledType(tinyxml2::XMLElement const* e checkElements(line, getChildElements(element), {}); std::string name = attributes.find("name")->second; - std::string strippedName = stripPrefix(name, "Vk"); - // a type simply needs to be removed from the structs, bitmasks, or enums - check(m_bitmasks.erase(name) + m_enums.erase(name) + m_structures.erase(name) == 1, line, "element <" + name + "> was removed from more than one set of elements"); + auto typeIt = m_types.find(name); + check(typeIt != m_types.end(), line, "trying to remove unknown type <" + name + ">"); + + switch (typeIt->second) + { + case TypeCategory::Bitmask: + { + auto bitmasksIt = m_bitmasks.find(name); + check(bitmasksIt != m_bitmasks.end(), line, "trying to remove unknown bitmask <" + name + ">"); + check(bitmasksIt->second.alias.empty(), line, "trying to remove disabled bitmask <" + name + "> which has alias <" + bitmasksIt->second.alias + ">"); + m_bitmasks.erase(bitmasksIt); + } + break; + case TypeCategory::Enum: + { + auto enumIt = m_enums.find(name); + check(enumIt != m_enums.end(), line, "trying to remove unknown enum <" + name + ">"); + check(enumIt->second.alias.empty(), line, "trying to remove disabled enum <" + name + "> which has alias <" + enumIt->second.alias + ">"); + m_enums.erase(enumIt); + } + break; + case TypeCategory::Struct: + { + auto structIt = m_structures.find(name); + check(structIt != m_structures.end(), line, "trying to remove unknown struct <" + name + ">"); + check(structIt->second.aliases.empty(), line, "trying to remove disabled structure <" + name + "> which has " + std::to_string(structIt->second.aliases.size()) + "aliases"); + m_structures.erase(structIt); + } + break; + default: + check(false, line, "trying to remove <" + name + "> of unhandled type <" + toString(typeIt->second) + ">"); + break; + } } void VulkanHppGenerator::readExtensionRequire(tinyxml2::XMLElement const* element, std::string const& platform, std::string const& tag, std::map & requirements) @@ -4518,57 +4560,73 @@ void VulkanHppGenerator::readExtensionRequireType(tinyxml2::XMLElement const* el // add the protect-string to the appropriate type: enum, flag, handle, scalar, or struct std::string name = attributes.find("name")->second; - auto handleIt = m_handles.find(name); - if (handleIt != m_handles.end()) + auto typeIt = m_types.find(name); + check(typeIt != m_types.end(), line, "failed to find required type <" + name + ">"); + + if (typeIt->second == TypeCategory::Handle) { assert(beginsWith(name, "Vk")); auto objectTypeIt = m_enums.find("VkObjectType"); assert(objectTypeIt != m_enums.end()); - std::string objectTypeName = "e" + stripPrefix(handleIt->first, "Vk"); - auto valueIt = std::find_if(objectTypeIt->second.values.begin(), objectTypeIt->second.values.end(), [objectTypeName](EnumValueData const& evd) {return evd.vkValue == objectTypeName; }); - check(valueIt != objectTypeIt->second.values.end(), line, "missing entry in VkObjectType enum for handle <" + name + ">."); + std::string objectTypeName = "e" + stripPrefix(name, "Vk"); + + auto handleIt = m_handles.find(name); + if (handleIt != m_handles.end()) + { + auto valueIt = std::find_if(objectTypeIt->second.values.begin(), objectTypeIt->second.values.end(), [objectTypeName](EnumValueData const& evd) {return evd.vkValue == objectTypeName; }); + check(valueIt != objectTypeIt->second.values.end(), line, "missing entry in VkObjectType enum for handle <" + name + ">."); + } + else + { + handleIt = std::find_if(m_handles.begin(), m_handles.end(), [name](auto const& h) { return h.second.alias == name; }); + auto aliasIt = std::find_if(objectTypeIt->second.aliases.begin(), objectTypeIt->second.aliases.end(), [objectTypeName](auto const& alias) { return alias.second == objectTypeName; }); + check(aliasIt != objectTypeIt->second.aliases.end(), line, "missing alias entry in VkObjectType enum for alias handle <" + name + ">."); + } } if (!platform.empty()) { - auto bmit = m_bitmasks.find(name); - if (bmit != m_bitmasks.end()) + switch (typeIt->second) { - check(bmit->second.platform.empty(), line, "platform already specified for bitmask <" + name + ">"); - bmit->second.platform = platform; - assert((m_enums.find(bmit->second.requirements) == m_enums.end()) || (m_enums.find(bmit->second.requirements)->second.isBitmask)); - } - else - { - auto eit = m_enums.find(name); - if (eit != m_enums.end()) + case TypeCategory::Bitmask: { - check(eit->second.platform.empty(), line, "platform already specified for enum <" + name + ">"); - eit->second.platform = platform; + auto bitmaskIt = m_bitmasks.find(name); + check(bitmaskIt != m_bitmasks.end(), line, "failed to find required bitmask <" + name + ">"); + check(bitmaskIt->second.platform.empty(), line, "platform already specified for bitmask <" + name + ">"); + bitmaskIt->second.platform = platform; + assert((m_enums.find(bitmaskIt->second.requirements) == m_enums.end()) || (m_enums.find(bitmaskIt->second.requirements)->second.isBitmask)); } - else + break; + case TypeCategory::Define: + // no need to protect a "defined" type + break; + case TypeCategory::Enum: { - auto hit = m_handles.find(name); - if (hit != m_handles.end()) - { - check(hit->second.platform.empty(), line, "platform already specified for handle <" + name + ">"); - hit->second.platform = platform; - } - else - { - auto stit = m_structures.find(name); - if (stit != m_structures.end()) - { - assert(m_handles.find(name) == m_handles.end()); - check(stit->second.platform.empty(), line, "platform already specified for structure <" + name + ">"); - stit->second.platform = platform; - } - else - { - assert((m_types.find(name) != m_types.end())); - } - } + auto enumIt = m_enums.find(name); + check(enumIt != m_enums.end(), line, "failed to find required enum <" + name + ">"); + check(enumIt->second.platform.empty(), line, "platform already specified for enum <" + name + ">"); + enumIt->second.platform = platform; } + break; + case TypeCategory::Handle: + { + auto handleIt = m_handles.find(name); + check(handleIt != m_handles.end(), line, "failed to find required handle <" + name + ">"); + check(handleIt->second.platform.empty(), line, "platform already specified for handle <" + name + ">"); + handleIt->second.platform = platform; + } + break; + case TypeCategory::Struct: + { + auto structIt = m_structures.find(name); + check(structIt != m_structures.end(), line, "failed to find required struct <" + name + ">"); + check(structIt->second.platform.empty(), line, "platform already specified for structure <" + name + ">"); + structIt->second.platform = platform; + } + break; + default: + check(false, line, "trying to protect <" + name + "> of unhandled type <" + toString(typeIt->second) + ">"); + break; } } } @@ -4672,7 +4730,7 @@ void VulkanHppGenerator::readFuncpointer(tinyxml2::XMLElement const* element, st std::string name = child->GetText(); check(!name.empty(), childLine, "funcpointer with empty name"); check(m_funcPointers.insert(std::make_pair(name, FuncPointerData(requirements, line))).second, childLine, "funcpointer <" + name + "> already specified"); - check(m_types.insert(name).second, childLine, "funcpointer <" + name + "> already specified as a type"); + check(m_types.insert(std::make_pair(name, TypeCategory::FuncPointer)).second, childLine, "funcpointer <" + name + "> already specified as a type"); } else if (value == "type") { @@ -4697,7 +4755,7 @@ void VulkanHppGenerator::readHandle(tinyxml2::XMLElement const* element, std::ma check(handlesIt != m_handles.end(), line, "using unspecified alias <" + aliasIt->second + ">."); check(handlesIt->second.alias.empty(), line, "handle <" + handlesIt->first + "> already has an alias <" + handlesIt->second.alias + ">"); handlesIt->second.alias = attributes.find("name")->second; - check(m_types.insert(handlesIt->second.alias).second, line, "handle alias <" + handlesIt->second.alias + "> already specified as a type"); + check(m_types.insert(std::make_pair(handlesIt->second.alias, TypeCategory::Handle)).second, line, "handle alias <" + handlesIt->second.alias + "> already specified as a type"); } else { @@ -4725,7 +4783,7 @@ void VulkanHppGenerator::readHandle(tinyxml2::XMLElement const* element, std::ma check(typeData.postfix == "(", line, "unexpected type postfix <" + typeData.postfix + ">"); check(m_handles.insert(std::make_pair(nameData.name, HandleData(tokenize(parent, ','), line))).second, line, "handle <" + nameData.name + "> already specified"); - check(m_types.insert(nameData.name).second, line, "handle <" + nameData.name + "> already specified as a type"); + check(m_types.insert(std::make_pair(nameData.name, TypeCategory::Handle)).second, line, "handle <" + nameData.name + "> already specified as a type"); } } @@ -4989,7 +5047,7 @@ void VulkanHppGenerator::readRequires(tinyxml2::XMLElement const* element, std:: { if (attribute.first == "name") { - check(m_types.insert(attribute.second).second, line, "type named <" + attribute.second + "> already specified"); + check(m_types.insert(std::make_pair(attribute.second, TypeCategory::Requires)).second, line, "type named <" + attribute.second + "> already specified"); } else { @@ -5029,12 +5087,16 @@ void VulkanHppGenerator::readStruct(tinyxml2::XMLElement const* element, bool is std::vector children = getChildElements(element); checkElements(line, children, {}, { "member", "comment" }); - std::string name; + std::string category, name; std::vector structExtends; bool returnedOnly = false; for (auto const& attribute : attributes) { - if (attribute.first == "name") + if (attribute.first == "category") + { + category = attribute.second; + } + else if (attribute.first == "name") { name = attribute.second; } @@ -5070,7 +5132,7 @@ void VulkanHppGenerator::readStruct(tinyxml2::XMLElement const* element, bool is it->second.subStruct = determineSubStruct(*it); m_extendedStructs.insert(structExtends.begin(), structExtends.end()); - check(m_types.insert(name).second, line, "struct <" + name + "> already specified as a type"); // log type and alias in m_types + check(m_types.insert(std::make_pair(name, (category == "struct") ? TypeCategory::Struct : TypeCategory::Union)).second, line, "struct <" + name + "> already specified as a type"); // log type and alias in m_types } } @@ -5098,7 +5160,7 @@ void VulkanHppGenerator::readStructAlias(tinyxml2::XMLElement const* element, st check(structIt != m_structures.end(), line, "missing alias <" + alias + ">."); check(structIt->second.aliases.insert(name).second, line, "struct <" + alias + "> already uses alias <" + name + ">"); check(m_structureAliases.insert(std::make_pair(name, alias)).second, line, "structure alias <" + name + "> already used"); - check(m_types.insert(name).second, line, "struct <" + name + "> already specified as a type"); + check(m_types.insert(std::make_pair(name, TypeCategory::Struct)).second, line, "struct <" + name + "> already specified as a type"); } void VulkanHppGenerator::readStructMember(tinyxml2::XMLElement const* element, std::vector & members) @@ -5274,7 +5336,7 @@ void VulkanHppGenerator::readType(tinyxml2::XMLElement const* element) else { check((attributes.size() == 1) && (attributes.begin()->first == "name") && (attributes.begin()->second == "int"), line, "unknown type"); - check(m_types.insert(attributes.begin()->second).second, line, "type <" + attributes.begin()->second + "> already specified"); + check(m_types.insert(std::make_pair(attributes.begin()->second, TypeCategory::Unknown)).second, line, "type <" + attributes.begin()->second + "> already specified"); } } } @@ -5313,7 +5375,7 @@ void VulkanHppGenerator::readTypeEnum(tinyxml2::XMLElement const* element, std:: check(enumIt->second.alias.empty(), line, "enum <" + enumIt->first + "> already has an alias <" + enumIt->second.alias + ">"); enumIt->second.alias = name; } - check(m_types.insert(name).second, line, "enum <" + name + "> already specified as a type"); + check(m_types.insert(std::make_pair(name, TypeCategory::Enum)).second, line, "enum <" + name + "> already specified as a type"); } void VulkanHppGenerator::readTypeInclude(tinyxml2::XMLElement const* element, std::map const& attributes) @@ -5398,6 +5460,27 @@ void VulkanHppGenerator::setVulkanLicenseHeader(int line, std::string const& com m_vulkanLicenseHeader = trim(m_vulkanLicenseHeader) + "\n"; } +std::string VulkanHppGenerator::toString(TypeCategory category) +{ + switch (category) + { + case TypeCategory::Bitmask: return "bitmask"; + case TypeCategory::BaseType: return "basetype"; + case TypeCategory::Define: return "define"; + case TypeCategory::Enum: return "enum"; + case TypeCategory::FuncPointer: return "funcpointer"; + case TypeCategory::Handle: return "handle"; + case TypeCategory::Requires: return "requires"; + case TypeCategory::Struct: return "struct"; + case TypeCategory::Union: return "union"; + case TypeCategory::Unknown: return "unkown"; + default: + assert(false); + return ""; + } +} + + std::string VulkanHppGenerator::TypeData::compose() const { return prefix + (prefix.empty() ? "" : " ") + ((type.substr(0, 2) == "Vk") ? "VULKAN_HPP_NAMESPACE::" : "") + stripPrefix(type, "Vk") + postfix; diff --git a/VulkanHppGenerator.hpp b/VulkanHppGenerator.hpp index 5010cfe..6d4efa0 100644 --- a/VulkanHppGenerator.hpp +++ b/VulkanHppGenerator.hpp @@ -92,8 +92,9 @@ class VulkanHppGenerator struct ParamData { - ParamData() + ParamData(int line) : optional(false) + , xmlLine(line) {} TypeData type; @@ -101,6 +102,7 @@ class VulkanHppGenerator std::vector arraySizes; std::string len; bool optional; + int xmlLine; }; struct CommandData @@ -217,6 +219,20 @@ class VulkanHppGenerator int xmlLine; }; + enum class TypeCategory + { + Bitmask, + BaseType, + Define, + Enum, + FuncPointer, + Handle, + Requires, + Struct, + Union, + Unknown + }; + private: void appendArgumentPlainType(std::string & str, ParamData const& paramData) const; void appendArguments(std::string & str, CommandData const& commandData, size_t returnParamIndex, size_t templateParamIndex, std::map const& vectorParamIndices, bool twoStep, bool firstCall, bool singular, size_t from, size_t to) const; @@ -331,6 +347,7 @@ class VulkanHppGenerator void readTypes(tinyxml2::XMLElement const* element); void registerDeleter(std::string const& name, std::pair const& commandData); void setVulkanLicenseHeader(int line, std::string const& comment); + std::string toString(TypeCategory category); private: std::map m_baseTypes; @@ -349,7 +366,7 @@ class VulkanHppGenerator std::map m_structureAliases; std::map m_structures; std::set m_tags; - std::set m_types; + std::map m_types; std::string m_typesafeCheck; std::string m_version; std::string m_vulkanLicenseHeader;