diff --git a/generator/VkXMLParser.cpp b/generator/VkXMLParser.cpp index 1bc2f5bb9..126196b5e 100644 --- a/generator/VkXMLParser.cpp +++ b/generator/VkXMLParser.cpp @@ -19,18 +19,15 @@ #include void checkNoList( std::string const & item, int line ); +bool containsByNameAndExport( std::vector const & commands, std::string const & name, std::vector const & exports ); bool isLenByStructMember( std::string const & name, std::vector const & params, std::map const & structs ); std::pair parseBaseType( tinyxml2::XMLElement const * element, std::map const & attributes, std::string const & api ); std::pair, std::pair> parseBitmask( tinyxml2::XMLElement const * element, std::map const & attributes ); -void parseCommand( tinyxml2::XMLElement const * element, - std::string const & api, - std::map & commands, - std::vector> & skippedCommands ); -std::pair, std::vector>> parseCommands( tinyxml2::XMLElement const * element, - std::string const & api ); -std::pair parseConstant( tinyxml2::XMLElement const * element ); +void parseCommand( tinyxml2::XMLElement const * element, std::vector & commands ); +std::vector parseCommands( tinyxml2::XMLElement const * element ); +std::pair parseConstant( tinyxml2::XMLElement const * element ); CategoryAlias parseCategoryAlias( tinyxml2::XMLElement const * element, std::map const & attributes, std::string const & category ); std::pair, std::pair> parseDefine( tinyxml2::XMLElement const * element, std::map const & attributes ); @@ -68,6 +65,21 @@ void checkNoList( std::string const & item, int line ) checkForError( "vk.xml", item.find( ',' ) == std::string::npos, line, "item <" + item + "> contains unexpected coma, looks like list" ); } +bool containsByNameAndExport( std::vector const & commands, std::string const & name, std::vector const & exports ) +{ + // check if there is a command with the specified name and at least one export in the specified exports list + return std::ranges::any_of( + commands, + [&name, &exports]( Command const & command ) + { + return ( command.name == name ) && + std::ranges::any_of( + command.exports, + [&exports]( std::string const & commandExport ) + { return std::ranges::any_of( exports, [&commandExport]( std::string const & exportItem ) { return exportItem == commandExport; } ); } ); + } ); +} + bool isLenByStructMember( std::string const & name, std::vector const & params, std::map const & structs ) { // check if name specifies a member of a struct @@ -167,10 +179,7 @@ std::pair, std::pair> parseBitmas return { api, { name, { .require = require, .type = type, .xmlLine = line } } }; } -void parseCommand( tinyxml2::XMLElement const * element, - std::string const & api, - std::map & commands, - std::vector> & skippedCommands ) +void parseCommand( tinyxml2::XMLElement const * element, std::vector & commands ) { int const line = element->GetLineNum(); std::map attributes = getAttributes( element ); @@ -195,12 +204,14 @@ void parseCommand( tinyxml2::XMLElement const * element, } } - auto commandIt = commands.find( alias ); + auto commandIt = findByName( commands, alias ); checkForError( "vk.xml", commandIt != commands.end(), line, "command <" + name + "> is aliased to unknown command <" + alias + ">" ); checkForError( "vk.xml", - commandIt->second.aliases.insert( { name, line } ).second, + std::find_if( std::next( commandIt ), commands.end(), [&alias]( Command const & c ) { return c.name == alias; } ) == commands.end(), line, - "command <" + name + "> is already listed as alias for command <" + alias + ">" ); + "command <" + name + "> is aliased to multiply specfied command <" + alias + ">" ); + checkForError( + "vk.xml", commandIt->aliases.insert( { name, line } ).second, line, "command <" + name + "> is already listed as alias for command <" + alias + ">" ); } else { @@ -255,7 +266,7 @@ void parseCommand( tinyxml2::XMLElement const * element, } else if ( attribute.first == "export" ) { - command.export_ = tokenize( attribute.second, "," ); + command.exports = tokenize( attribute.second, "," ); } else if ( attribute.first == "queues" ) { @@ -281,7 +292,6 @@ void parseCommand( tinyxml2::XMLElement const * element, } } - std::string name; for ( auto child : children ) { std::string value = child->Value(); @@ -291,15 +301,29 @@ void parseCommand( tinyxml2::XMLElement const * element, } else if ( value == "param" ) { - Param param = parseParam( child ); - if ( param.api.empty() || ( std::ranges::find( param.api, api ) != param.api.end() ) ) + Param param = parseParam( child ); + auto paramIt = findByName( command.params, param.name ); + if ( paramIt == command.params.end() ) { command.params.push_back( std::move( param ) ); } + else + { + checkForError( "vk.xml", + param.api != paramIt->api, + param.xmlLine, + "command <" + command.name + "> has the parameter <" + param.name + "> multiply defined for the same set of apis" ); + std::vector api = param.api; + param.api = paramIt->api; + checkForError( "vk.xml", + param == *paramIt, + param.xmlLine, + "command <" + command.name + "> has the parameter <" + param.name + "> multiply defined with different attributes" ); + } } else if ( value == "proto" ) { - std::tie( name, command.returnType ) = parseProto( child ); + std::tie( command.name, command.returnType ) = parseProto( child ); } } @@ -330,31 +354,24 @@ void parseCommand( tinyxml2::XMLElement const * element, checkForError( "vk.xml", ( command.returnType.name == "VkResult" ) || command.errorCodes.empty(), line, - "command <" + name + "> does not return a VkResult but specifies errorcodes" ); + "command <" + command.name + "> does not return a VkResult but specifies errorcodes" ); checkForError( "vk.xml", ( command.returnType.name == "VkResult" ) || command.successCodes.empty(), line, - "command <" + name + "> does not return a VkResult but specifies successcodes" ); + "command <" + command.name + "> does not return a VkResult but specifies successcodes" ); checkForError( "vk.xml", - command.api.empty() || command.export_.empty() || - ( ( command.export_.size() == 1 ) && std::ranges::any_of( command.api, [&command]( auto const & a ) { return a == command.export_.front(); } ) ), + command.api.empty() || command.exports.empty() || + ( ( command.exports.size() == 1 ) && std::ranges::any_of( command.api, [&command]( auto const & a ) { return a == command.exports.front(); } ) ), line, - "command <" + name + "> has disjunct attributes and " ); + "command <" + command.name + "> has disjunct attributes and " ); - if ( command.api.empty() || ( std::ranges::find( command.api, api ) != command.api.end() ) ) - { - checkForError( "vk.xml", commands.insert( { name, command } ).second, line, "command <" + name + "> already specified for api <" + api + ">" ); - } - else - { - skippedCommands.push_back( { name, command } ); - } + checkForError( "vk.xml", !containsByNameAndExport( commands, command.name, command.exports ), line, "command <" + command.name + "> already specified" ); + commands.push_back( std::move( command ) ); } } -std::pair, std::vector>> parseCommands( tinyxml2::XMLElement const * element, - std::string const & api ) +std::vector parseCommands( tinyxml2::XMLElement const * element ) { int const line = element->GetLineNum(); checkAttributes( "vk.xml", line, getAttributes( element ), {}, { { "comment", {} } } ); @@ -362,14 +379,13 @@ std::pair, std::vector children = getChildElements( element ); checkElements( "vk.xml", line, children, { { "command", MultipleAllowed::Yes } } ); - std::map commands; - std::vector> skippedCommands; + std::vector commands; for ( auto child : children ) { - parseCommand( child, api, commands, skippedCommands ); + parseCommand( child, commands ); } - return { commands, skippedCommands }; + return commands; } std::pair parseConstant( tinyxml2::XMLElement const * element ) @@ -1020,12 +1036,11 @@ Vkxml parseRegistry( tinyxml2::XMLElement const * element, std::string const & a std::string const value = child->Value(); if ( value == "commands" ) { - std::vector> skippedCommands; - std::tie( vkxml.commands, skippedCommands ) = parseCommands( child, api ); + vkxml.commands = parseCommands( child ); for ( auto const & command : vkxml.commands ) { - for ( auto const & param : command.second.params ) + for ( auto const & param : command.params ) { if ( param.externSync.starts_with( "maybe:" ) ) { @@ -1034,36 +1049,36 @@ Vkxml parseRegistry( tinyxml2::XMLElement const * element, std::string const & a pos != std::string::npos, param.xmlLine, "unexpected value <" + param.externSync + "> for attribute externsync of parameter <" + param.name + "> of command <" + - command.first + ">, expected format is \"maybe:[].\"" ); + command.name + ">, expected format is \"maybe:[].\"" ); std::string memberName = param.externSync.substr( pos + 1 ); auto structIt = vkxml.structs.find( param.type.name ); checkForError( "vk.xml", structIt != vkxml.structs.end(), param.xmlLine, - "type <" + param.type.name + "> of parameter <" + param.name + "> of command <" + command.first + + "type <" + param.type.name + "> of parameter <" + param.name + "> of command <" + command.name + "> with externsync attribute is not a struct" ); checkForError( "vk.xml", containsByName( structIt->second.members, memberName ), param.xmlLine, - "struct <" + param.type.name + "> used in externsync attribute of parameter <" + param.name + "> of command <" + command.first + + "struct <" + param.type.name + "> used in externsync attribute of parameter <" + param.name + "> of command <" + command.name + "> does not have member <" + memberName + ">" ); } checkForError( "vk.xml", param.len.empty() || ( param.len == "null-terminated" ) || ( param.len == "1" ) || param.len.starts_with( "latexmath:" ) || - containsByName( command.second.params, param.len ) || isLenByStructMember( param.len, command.second.params, vkxml.structs ), + containsByName( command.params, param.len ) || isLenByStructMember( param.len, command.params, vkxml.structs ), param.xmlLine, - "unknown len <" + param.len + "> specified for parameter <" + param.name + "> of command <" + command.first + ">" ); + "unknown len <" + param.len + "> specified for parameter <" + param.name + "> of command <" + command.name + ">" ); checkForError( "vk.xml", vkxml.baseTypes.contains( param.type.name ) || vkxml.bitmasks.contains( param.type.name ) || containsByNameOrAlias( vkxml.enums, param.type.name ) || vkxml.externalTypes.contains( param.type.name ) || vkxml.handles.contains( param.type.name ) || containsByNameOrAlias( vkxml.structs, param.type.name ) || vkxml.unions.contains( param.type.name ), param.xmlLine, - "unknown type <" + param.type.name + "> of parameter <" + param.name + "> of command <" + command.first + ">" ); + "unknown type <" + param.type.name + "> of parameter <" + param.name + "> of command <" + command.name + ">" ); checkForError( "vk.xml", param.validStructs.empty() || vkxml.structs.contains( param.validStructs ), param.xmlLine, - "unknown validstructs <" + param.validStructs + "> specified for parameter <" + param.name + "> of command <" + command.first + ">" ); + "unknown validstructs <" + param.validStructs + "> specified for parameter <" + param.name + "> of command <" + command.name + ">" ); } } } diff --git a/generator/VkXMLParser.hpp b/generator/VkXMLParser.hpp index 202a098ba..749bdedd6 100644 --- a/generator/VkXMLParser.hpp +++ b/generator/VkXMLParser.hpp @@ -58,17 +58,25 @@ struct Param Type type = {}; std::string validStructs = {}; int xmlLine = {}; + + bool operator==( Param const & rhs ) const noexcept + { + return ( altLen == rhs.altLen ) && ( api == rhs.api ) && ( arraySizes == rhs.arraySizes ) && ( externSync == rhs.externSync ) && + ( len == rhs.len ) && ( name == rhs.name ) && ( noAutoValidity == rhs.noAutoValidity ) && ( objectType == rhs.objectType ) && + ( optional == rhs.optional ) && ( stride == rhs.stride ) && ( type == rhs.type ) && ( validStructs == rhs.validStructs ); + } }; struct Command { + std::string name = {}; std::string allowNoQueues = {}; std::map aliases = {}; std::vector api = {}; std::vector cmdBufferLevel = {}; std::string conditionalRendering = {}; std::vector errorCodes = {}; - std::vector export_ = {}; + std::vector exports = {}; std::vector params = {}; std::vector queues = {}; std::string renderPass = {}; @@ -269,7 +277,7 @@ struct Vkxml { std::map baseTypes = {}; std::map bitmasks = {}; - std::map commands = {}; // lists only commands of the requested export + std::vector commands = {}; std::map constants = {}; Comment copyright = {}; std::map defines = {}; diff --git a/generator/VulkanHppGenerator.cpp b/generator/VulkanHppGenerator.cpp index 0bfe8fd89..5152855c4 100644 --- a/generator/VulkanHppGenerator.cpp +++ b/generator/VulkanHppGenerator.cpp @@ -83,56 +83,60 @@ VulkanHppGenerator::VulkanHppGenerator( Vkxml && vkxml, tinyxml2::XMLDocument co } for ( auto const & command : m_vkxml.commands ) { - auto [commandIt, inserted] = m_commands.insert( { command.first, { .xmlLine = command.second.xmlLine } } ); - assert( inserted ); - commandIt->second.aliases = command.second.aliases; - commandIt->second.errorCodes = command.second.errorCodes; - commandIt->second.exports = command.second.export_; + if ( command.api.empty() || std::ranges::any_of( command.api, [&api]( std::string const & commandApi ) { return commandApi == api; } ) ) + { + auto [commandIt, inserted] = m_commands.insert( { command.name, { .xmlLine = command.xmlLine } } ); + assert( inserted ); + commandIt->second.aliases = command.aliases; + commandIt->second.errorCodes = command.errorCodes; + commandIt->second.exports = command.exports; - // find the handle this command is going to be associated to - auto handleIt = m_vkxml.handles.find( command.second.params[0].type.name ); - commandIt->second.handle = ( handleIt != m_vkxml.handles.end() ) ? handleIt->first : ""; + // find the handle this command is going to be associated to + auto handleIt = m_vkxml.handles.find( command.params[0].type.name ); + commandIt->second.handle = ( handleIt != m_vkxml.handles.end() ) ? handleIt->first : ""; - for ( auto const & param : command.second.params ) - { - commandIt->second.params.emplace_back( param.name, param.type, param.xmlLine ); - commandIt->second.params.back().arraySizes = std::move( param.arraySizes ); - if ( !param.altLen.empty() ) + for ( auto const & param : command.params ) { - commandIt->second.params.back().lenParams = filterNumbers( tokenizeAny( param.altLen, " /()+" ) ); - for ( auto & lenParam : commandIt->second.params.back().lenParams ) + commandIt->second.params.emplace_back( param.name, param.type, param.xmlLine ); + commandIt->second.params.back().arraySizes = std::move( param.arraySizes ); + if ( !param.altLen.empty() ) { - auto paramIt = findByName( command.second.params, lenParam.first ); - checkForError( paramIt != command.second.params.end(), - param.xmlLine, - "param <" + param.name + "> uses unknown len parameter <" + lenParam.first + "> in its \"altlen\" attribute <" + param.altLen + ">" ); - lenParam.second = std::distance( command.second.params.begin(), paramIt ); + commandIt->second.params.back().lenParams = filterNumbers( tokenizeAny( param.altLen, " /()+" ) ); + for ( auto & lenParam : commandIt->second.params.back().lenParams ) + { + auto paramIt = findByName( command.params, lenParam.first ); + checkForError( paramIt != command.params.end(), + param.xmlLine, + "param <" + param.name + "> uses unknown len parameter <" + lenParam.first + "> in its \"altlen\" attribute <" + param.altLen + + ">" ); + lenParam.second = std::distance( command.params.begin(), paramIt ); + } + commandIt->second.params.back().lenExpression = std::move( param.altLen ); } - commandIt->second.params.back().lenExpression = std::move( param.altLen ); - } - else if ( !param.len.empty() ) - { - auto paramIt = findByName( command.second.params, param.len ); - if ( paramIt != command.second.params.end() ) + else if ( !param.len.empty() ) + { + auto paramIt = findByName( command.params, param.len ); + if ( paramIt != command.params.end() ) + { + commandIt->second.params.back().lenParams.push_back( { param.len, std::distance( command.params.begin(), paramIt ) } ); + } + commandIt->second.params.back().lenExpression = std::move( param.len ); + } + commandIt->second.params.back().optional = param.optional.size() == 1 && ( param.optional[0] == "true" ); + if ( !param.stride.empty() ) { - commandIt->second.params.back().lenParams.push_back( { param.len, std::distance( command.second.params.begin(), paramIt ) } ); + auto paramIt = findByName( command.params, param.stride ); + assert( paramIt != command.params.end() ); + commandIt->second.params.back().strideParam = { param.stride, std::distance( command.params.begin(), paramIt ) }; } - commandIt->second.params.back().lenExpression = std::move( param.len ); - } - commandIt->second.params.back().optional = param.optional.size() == 1 && ( param.optional[0] == "true" ); - if ( !param.stride.empty() ) - { - auto paramIt = findByName( command.second.params, param.stride ); - assert( paramIt != command.second.params.end() ); - commandIt->second.params.back().strideParam = { param.stride, std::distance( command.second.params.begin(), paramIt ) }; } - } - // commandIt->second.requiredBy is filled later on by distributeRequirements - commandIt->second.returnType = command.second.returnType; - commandIt->second.successCodes = command.second.successCodes; + // commandIt->second.requiredBy is filled later on by distributeRequirements + commandIt->second.returnType = command.returnType; + commandIt->second.successCodes = command.successCodes; - m_commandQueues.insert( command.second.queues.begin(), command.second.queues.end() ); + m_commandQueues.insert( command.queues.begin(), command.queues.end() ); + } } for ( auto const & constant : m_vkxml.constants ) { @@ -848,10 +852,9 @@ void VulkanHppGenerator::checkCommandCorrectness() const assert( queueFlagBitsIt != m_enums.end() ); for ( auto const & command : m_vkxml.commands ) { - for ( auto const & q : command.second.queues ) + for ( auto const & q : command.queues ) { - checkForError( - containsByName( queueFlagBitsIt->second.values, q ), command.second.xmlLine, "command <" + command.first + "> uses unknown queue <" + q + ">" ); + checkForError( containsByName( queueFlagBitsIt->second.values, q ), command.xmlLine, "command <" + command.name + "> uses unknown queue <" + q + ">" ); } } }