Cleanup work on correctness checks (#2079)

This commit is contained in:
Andreas Süßenbach 2025-02-19 09:11:19 +01:00 committed by GitHub
parent 03f07338be
commit 5f4583c500
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
2 changed files with 152 additions and 117 deletions

View File

@ -794,9 +794,16 @@ void VulkanHppGenerator::checkBitmaskCorrectness() const
// check that the requirement is an enum
if ( !bitmask.second.require.empty() )
{
checkForError( m_enums.contains( bitmask.second.require ),
auto requireTypeIt = m_types.find( bitmask.second.require );
checkForError(
requireTypeIt != m_types.end(), bitmask.second.xmlLine, "bitmask <" + bitmask.first + "> requires unknown type <" + bitmask.second.require + ">" );
checkForError( requireTypeIt->second.category == TypeCategory::Enum,
bitmask.second.xmlLine,
"bitmask <" + bitmask.first + "> requires unknown enum <" + bitmask.second.require + ">" );
"bitmask <" + bitmask.first + "> requires non-enum type <" + bitmask.second.require + ">" );
assert( m_enums.contains( bitmask.second.require ) );
checkForError( !requireTypeIt->second.requiredBy.empty(),
bitmask.second.xmlLine,
"bitmask <" + bitmask.first + "> requires <" + bitmask.second.require + "> which is not required by any feature or extension!" );
}
}
}
@ -804,26 +811,7 @@ void VulkanHppGenerator::checkBitmaskCorrectness() const
void VulkanHppGenerator::checkCommandCorrectness() const
{
// prepare command checks by gathering all result codes (including aliases and not supported ones!) into one set of resultCodes
auto resultIt = m_enums.find( "VkResult" );
assert( resultIt != m_enums.end() );
std::set<std::string> resultCodes;
for ( auto rc : resultIt->second.values )
{
resultCodes.insert( rc.name );
for ( auto ac : rc.aliases )
{
resultCodes.insert( ac.name );
}
}
// some special handling needed for vulkansc!!
if ( m_api == "vulkansc" )
{
resultCodes.insert( { "VK_ERROR_FRAGMENTATION_EXT",
"VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR",
"VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR",
"VK_ERROR_NOT_PERMITTED_EXT",
"VK_PIPELINE_COMPILE_REQUIRED_EXT" } );
}
std::set<std::string> resultCodes = gatherResultCodes();
// command checks
for ( auto const & command : m_commands )
@ -876,9 +864,9 @@ void VulkanHppGenerator::checkCorrectness() const
checkDefineCorrectness();
checkEnumCorrectness();
checkExtensionCorrectness();
checkFeatureCorrectness();
checkFuncPointerCorrectness();
checkHandleCorrectness();
checkRequireCorrectness();
checkSpirVCapabilityCorrectness();
checkStructCorrectness();
checkSyncAccessCorrectness();
@ -905,16 +893,23 @@ void VulkanHppGenerator::checkEnumCorrectness() const
auto typeIt = m_types.find( e.first );
assert( typeIt != m_types.end() );
checkForWarning( !typeIt->second.requiredBy.empty(), e.second.xmlLine, "enum <" + e.first + "> not required in any feature or extension" );
}
// enum checks by features and extensions
for ( auto & feature : m_features )
{
checkEnumCorrectness( feature.requireData );
}
for ( auto & ext : m_extensions )
{
checkEnumCorrectness( ext.requireData );
if ( e.second.isBitmask )
{
if ( std::ranges::any_of( e.second.values, []( auto const & v ) { return v.supported; } ) )
{
// check that any enum of a bitmask with supported values is listed as "require" or "bitvalues" for a bitmask
auto bitmaskIt = std::find_if( m_bitmasks.begin(), m_bitmasks.end(), [&e]( auto const & bitmask ) { return bitmask.second.require == e.first; } );
checkForError( bitmaskIt != m_bitmasks.end(),
e.second.xmlLine,
"enum <" + e.first + "> is not listed as an requires or bitvalues for any bitmask in the types section" );
// check that bitwidth of the enum and type of the corresponding bitmask are equal
checkForError( ( e.second.bitwidth != "64" ) || ( bitmaskIt->second.type == "VkFlags64" ),
e.second.xmlLine,
"enum <" + e.first + "> is marked with bitwidth <64> but corresponding bitmask <" + bitmaskIt->first + "> is not of type <VkFlags64>" );
}
}
}
// special check for VkFormat
@ -932,70 +927,6 @@ void VulkanHppGenerator::checkEnumCorrectness() const
}
}
void VulkanHppGenerator::checkEnumCorrectness( std::vector<RequireData> const & requireData ) const
{
for ( auto const & require : requireData )
{
for ( auto const & type : require.types )
{
auto typeIt = m_types.find( type.name );
assert( typeIt != m_types.end() );
switch ( typeIt->second.category )
{
case TypeCategory::Bitmask:
{
// check that each "require" listed for a bitmask is listed for a feature or an extension
auto bitmaskIt = m_bitmasks.find( type.name );
if ( bitmaskIt != m_bitmasks.end() )
{
// not for every bitmask is a "require" listed
if ( !bitmaskIt->second.require.empty() )
{
auto requireTypeIt = m_types.find( bitmaskIt->second.require );
assert( requireTypeIt != m_types.end() );
checkForError( !requireTypeIt->second.requiredBy.empty(),
bitmaskIt->second.xmlLine,
"bitmask <" + bitmaskIt->first + "> requires <" + bitmaskIt->second.require +
"> which is not required by any feature or extension!" );
}
}
}
break;
case TypeCategory::Enum:
{
auto enumIt = m_enums.find( type.name );
if ( enumIt != m_enums.end() )
{
if ( enumIt->second.isBitmask && !enumIt->second.values.empty() )
{
// check that any non-empty enum of a bitmask is listed as "require" or "bitvalues" for a bitmask
auto bitmaskIt =
std::find_if( m_bitmasks.begin(), m_bitmasks.end(), [&enumIt]( auto const & bitmask ) { return bitmask.second.require == enumIt->first; } );
checkForError( bitmaskIt != m_bitmasks.end(),
enumIt->second.xmlLine,
"enum <" + enumIt->first + "> is not listed as an requires or bitvalues for any bitmask in the types section" );
// check that bitwidth of the enum and type of the corresponding bitmask are equal
checkForError( ( enumIt->second.bitwidth != "64" ) || ( bitmaskIt->second.type == "VkFlags64" ),
enumIt->second.xmlLine,
"enum <" + enumIt->first + "> is marked with bitwidth <64> but corresponding bitmask <" + bitmaskIt->first +
"> is not of type <VkFlags64>" );
}
}
else
{
// every enum not listed in the m_enums, should be an alias of such a thing
checkForError(
findByNameOrAlias( m_enums, type.name ) != m_enums.end(), typeIt->second.xmlLine, "enum type <" + type.name + "> is not listed as an enum" );
}
}
break;
default: break;
}
}
}
}
bool VulkanHppGenerator::checkEquivalentSingularConstructor( std::vector<std::map<std::string, CommandData>::const_iterator> const & constructorIts,
std::map<std::string, CommandData>::const_iterator constructorIt,
std::vector<ParamData>::const_iterator lenIt ) const
@ -1079,23 +1010,6 @@ void VulkanHppGenerator::checkExtensionCorrectness() const
}
}
void VulkanHppGenerator::checkFeatureCorrectness() const
{
// check that each require depends actually is an extension
// remove this check temporarily !
// for ( auto const & feature : m_features )
//{
// for ( auto const & require : feature.requireData )
// {
// checkForError(
// require.depends.empty() ||
// std::any_of( m_extensions.begin(), m_extensions.end(), [&depends = require.depends]( ExtensionData const & ed ) { return ed.name == depends; } ),
// require.xmlLine,
// "feature <" + feature.name + "> depends on an unknown extension <" + require.depends + ">" );
// }
//}
}
void VulkanHppGenerator::checkFuncPointerCorrectness() const
{
for ( auto const & funcPointer : m_funcPointers )
@ -1152,6 +1066,101 @@ void VulkanHppGenerator::checkHandleCorrectness() const
}
}
void VulkanHppGenerator::checkRequireCorrectness() const
{
// checks by features and extensions
for ( auto & feature : m_features )
{
checkRequireCorrectness( feature.requireData, "feature", feature.name );
}
for ( auto & extension : m_extensions )
{
checkRequireCorrectness( extension.requireData, "extension", extension.name );
}
}
void VulkanHppGenerator::checkRequireCorrectness( std::vector<RequireData> const & requireData, std::string const & section, std::string const & name ) const
{
for ( auto const & require : requireData )
{
std::vector<std::string> dependencies = tokenize( require.depends, "," );
for ( auto const & depends : dependencies )
{
size_t separatorPos = depends.find( "::" );
if ( separatorPos == std::string::npos )
{
checkForError( isFeature( depends ) || isExtension( depends ),
require.xmlLine,
section + " <" + name + "> depends on unknown extension or feature <" + depends + ">" );
}
else
{
std::string structure = depends.substr( 0, separatorPos );
std::string member = depends.substr( separatorPos + 2 );
auto structIt = m_structs.find( structure );
checkForError( structIt != m_structs.end(), require.xmlLine, section + " <" + name + "> requires member of an unknown struct <" + structure + ">" );
checkForError( std::ranges::find_if( structIt->second.members, [&member]( auto const & md ) { return md.name == member; } ) !=
structIt->second.members.end(),
require.xmlLine,
section + " <" + name + "> requires unknown member <" + member + "> as part of the struct <" + structure + ">" );
}
}
for ( auto const & type : require.types )
{
auto typeIt = m_types.find( type.name );
assert( typeIt != m_types.end() );
// every required type should be listed in the corresponding map
switch ( typeIt->second.category )
{
case TypeCategory::Bitmask:
checkForError( findByNameOrAlias( m_bitmasks, type.name ) != m_bitmasks.end(),
typeIt->second.xmlLine,
"required bitmask type <" + type.name + "> is not listed as bitmask" );
break;
case TypeCategory::BaseType:
checkForError( m_baseTypes.contains( type.name ), typeIt->second.xmlLine, "required base type <" + type.name + "> is not listed as a base type" );
break;
case TypeCategory::Constant:
checkForError( m_constants.contains( type.name ), typeIt->second.xmlLine, "required constant <" + type.name + "> is not listed as a constant" );
break;
case TypeCategory::Define:
checkForError( m_defines.contains( type.name ), typeIt->second.xmlLine, "required define <" + type.name + "> is not listed as a define" );
break;
case TypeCategory::Enum:
checkForError( findByNameOrAlias( m_enums, type.name ) != m_enums.end(),
typeIt->second.xmlLine,
"required enum type <" + type.name + "> is not listed as an enum" );
break;
case TypeCategory::ExternalType:
checkForError(
m_externalTypes.contains( type.name ), typeIt->second.xmlLine, "required external type <" + type.name + "> is not listed as an external type" );
break;
case TypeCategory::FuncPointer:
checkForError(
m_funcPointers.contains( type.name ), typeIt->second.xmlLine, "required funcpointer <" + type.name + "> is not listed as a funcpointer" );
break;
case TypeCategory::Handle:
checkForError( findByNameOrAlias( m_handles, type.name ) != m_handles.end(),
typeIt->second.xmlLine,
"required handle type <" + type.name + "> is not listed as a handle" );
break;
case TypeCategory::Include:
checkForError( m_includes.contains( type.name ), typeIt->second.xmlLine, "required include <" + type.name + "> is not listed as an include" );
break;
case TypeCategory::Struct:
case TypeCategory::Union:
checkForError( findByNameOrAlias( m_structs, type.name ) != m_structs.end(),
typeIt->second.xmlLine,
"required struct type <" + type.name + "> is not listed as a struct" );
break;
case TypeCategory::Unknown: break;
default : assert( false ); break;
}
}
}
}
void VulkanHppGenerator::checkSpirVCapabilityCorrectness() const
{
for ( auto const & capability : m_spirVCapabilities )
@ -1600,8 +1609,8 @@ size_t VulkanHppGenerator::determineDefaultStartIndex( std::vector<ParamData> co
bool VulkanHppGenerator::determineEnumeration( std::map<size_t, VectorParamData> const & vectorParams, std::vector<size_t> const & returnParams ) const
{
// a command is considered to be enumerating some data, if for at least one vectorParam the data is a returnParam and either the vectorParams is specified
// by a structure or the lenParam is a returnParam as well
// a command is considered to be enumerating some data, if for at least one vectorParam the data is a returnParam and either the vectorParams is
// specified by a structure or the lenParam is a returnParam as well
return std::any_of( vectorParams.begin(),
vectorParams.end(),
[&returnParams]( auto const & vp )
@ -2099,6 +2108,31 @@ std::string VulkanHppGenerator::findTag( std::string const & name, std::string c
return ( tagIt != m_tags.end() ) ? tagIt->first : "";
}
std::set<std::string> VulkanHppGenerator::gatherResultCodes() const
{
auto resultIt = m_enums.find( "VkResult" );
assert( resultIt != m_enums.end() );
std::set<std::string> resultCodes;
for ( auto rc : resultIt->second.values )
{
resultCodes.insert( rc.name );
for ( auto ac : rc.aliases )
{
resultCodes.insert( ac.name );
}
}
// some special handling needed for vulkansc!!
if ( m_api == "vulkansc" )
{
resultCodes.insert( { "VK_ERROR_FRAGMENTATION_EXT",
"VK_ERROR_INVALID_EXTERNAL_HANDLE_KHR",
"VK_ERROR_INVALID_OPAQUE_CAPTURE_ADDRESS_KHR",
"VK_ERROR_NOT_PERMITTED_EXT",
"VK_PIPELINE_COMPILE_REQUIRED_EXT" } );
}
return resultCodes;
}
std::pair<std::string, std::string> VulkanHppGenerator::generateAllocatorTemplates( std::vector<size_t> const & returnParams,
std::vector<std::string> const & returnDataTypes,
std::map<size_t, VectorParamData> const & vectorParams,

View File

@ -521,14 +521,14 @@ private:
void checkCorrectness() const;
void checkDefineCorrectness() const;
void checkEnumCorrectness() const;
void checkEnumCorrectness( std::vector<RequireData> const & requireData ) const;
bool checkEquivalentSingularConstructor( std::vector<std::map<std::string, CommandData>::const_iterator> const & constructorIts,
std::map<std::string, CommandData>::const_iterator constructorIt,
std::vector<ParamData>::const_iterator lenIt ) const;
void checkExtensionCorrectness() const;
void checkFeatureCorrectness() const;
void checkFuncPointerCorrectness() const;
void checkHandleCorrectness() const;
void checkRequireCorrectness() const;
void checkRequireCorrectness( std::vector<RequireData> const & requireData, std::string const & section, std::string const & name ) const;
void checkSpirVCapabilityCorrectness() const;
void checkStructCorrectness() const;
void checkStructMemberCorrectness( std::string const & structureName, std::vector<MemberData> const & members, std::set<std::string> & sTypeValues ) const;
@ -582,6 +582,7 @@ private:
std::vector<MemberData>::const_iterator findStructMemberItByType( std::string const & type, std::vector<MemberData> const & memberData ) const;
std::vector<ExtensionData>::const_iterator findSupportedExtension( std::string const & name ) const;
std::string findTag( std::string const & name, std::string const & postfix = "" ) const;
std::set<std::string> gatherResultCodes() const;
std::pair<std::string, std::string> generateAllocatorTemplates( std::vector<size_t> const & returnParams,
std::vector<std::string> const & returnDataTypes,
std::map<size_t, VectorParamData> const & vectorParams,