1 // Copyright(c) 2015-2020, NVIDIA CORPORATION. All rights reserved.
2 //
3 // Licensed under the Apache License, Version 2.0 (the "License");
4 // you may not use this file except in compliance with the License.
5 // You may obtain a copy of the License at
6 //
7 // http://www.apache.org/licenses/LICENSE-2.0
8 //
9 // Unless required by applicable law or agreed to in writing, software
10 // distributed under the License is distributed on an "AS IS" BASIS,
11 // WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 // See the License for the specific language governing permissions and
13 // limitations under the License.
14 //
15 // Modifications Copyright (C) 2023 The Android Open Source Project
16 // * Updated RAII to work with VULKAN_HPP_NO_EXCEPTIONS.
17
18 #include "VulkanHppGenerator.hpp"
19
20 #include <algorithm>
21 #include <cassert>
22 #include <fstream>
23 #include <regex>
24 #include <sstream>
25
26 // Uncomment to generate function definitions with cpp comment saying
27 // which function generated it.
28 //#define DEBUG_GENERATOR 1
29
30 void checkAttributes( int line,
31 std::map<std::string, std::string> const & attributes,
32 std::map<std::string, std::set<std::string>> const & required,
33 std::map<std::string, std::set<std::string>> const & optional );
34 void checkElements( int line,
35 std::vector<tinyxml2::XMLElement const *> const & elements,
36 std::map<std::string, bool> const & required,
37 std::set<std::string> const & optional = {} );
38 void checkForError( bool condition, int line, std::string const & message );
39 void checkForWarning( bool condition, int line, std::string const & message );
40 std::string findTag( std::set<std::string> const & tags, std::string const & name, std::string const & postfix = "" );
41 std::string generateCArraySizes( std::vector<std::string> const & sizes );
42 std::pair<std::string, std::string> generateEnumSuffixes( std::string const & name, bool bitmask, std::set<std::string> const & tags );
43 std::string generateEnumValueName( std::string const & enumName, std::string const & valueName, bool bitmask, std::set<std::string> const & tags );
44 std::string generateNamespacedType( std::string const & type );
45 std::string generateNoDiscard( bool returnsSomething, bool multiSuccessCodes, bool multiErrorCodes );
46 std::string generateStandardArray( std::string const & type, std::vector<std::string> const & sizes );
47 std::string generateStandardArrayWrapper( std::string const & type, std::vector<std::string> const & sizes );
48 std::string generateSuccessCode( std::string const & code, std::set<std::string> const & tags );
49 std::map<std::string, std::string> getAttributes( tinyxml2::XMLElement const * element );
50 template <typename ElementContainer>
51 std::vector<tinyxml2::XMLElement const *> getChildElements( ElementContainer const * element );
52 std::pair<std::vector<std::string>, std::string> readModifiers( tinyxml2::XMLNode const * node );
53 std::string readSnippet( std::string const & snippetFile );
54 std::string replaceWithMap( std::string const & input, std::map<std::string, std::string> replacements );
55 std::string startLowerCase( std::string const & input );
56 std::string startUpperCase( std::string const & input );
57 std::string stripPostfix( std::string const & value, std::string const & postfix );
58 std::string stripPluralS( std::string const & name, std::set<std::string> const & tags );
59 std::string stripPrefix( std::string const & value, std::string const & prefix );
60 std::string toCamelCase( std::string const & value );
61 std::string toUpperCase( std::string const & name );
62 std::vector<std::string> tokenize( std::string const & tokenString, std::string const & separator );
63 std::vector<std::string> tokenizeAny( std::string const & tokenString, std::string const & separators );
64 std::string toString( tinyxml2::XMLError error );
65 std::string trim( std::string const & input );
66 std::string trimEnd( std::string const & input );
67 std::string trimStars( std::string const & input );
68 void writeToFile( std::string const & str, std::string const & fileName );
69
70 const std::set<std::string> altLens = { "2*VK_UUID_SIZE", "codeSize / 4", "(rasterizationSamples + 31) / 32", "(samples + 31) / 32" };
71 const std::set<std::string> specialPointerTypes = { "Display", "IDirectFB", "wl_display", "xcb_connection_t", "_screen_window" };
72
73 //
74 // VulkanHppGenerator public interface
75 //
76
VulkanHppGenerator(tinyxml2::XMLDocument const & document)77 VulkanHppGenerator::VulkanHppGenerator( tinyxml2::XMLDocument const & document )
78 {
79 // insert the default "handle" without class (for createInstance, and such)
80 m_handles.insert( std::make_pair( "", HandleData( {}, "", false, 0 ) ) );
81
82 // read the document and check its correctness
83 int line = document.GetLineNum();
84 std::vector<tinyxml2::XMLElement const *> elements = getChildElements( &document );
85 checkElements( line, elements, { { "registry", true } } );
86 checkForError( elements.size() == 1, line, "encountered " + std::to_string( elements.size() ) + " elements named <registry> but only one is allowed" );
87 readRegistry( elements[0] );
88 checkCorrectness();
89
90 // add the commands to the respective handles
91 for ( auto & command : m_commands )
92 {
93 auto handleIt = m_handles.find( command.second.handle );
94 assert( handleIt != m_handles.end() );
95 assert( handleIt->second.commands.find( command.first ) == handleIt->second.commands.end() );
96 handleIt->second.commands.insert( command.first );
97
98 registerDeleter( command.first, command );
99 }
100
101 // some "FlagBits" enums are not specified, but needed for our "Flags" handling -> add them here
102 for ( auto & feature : m_features )
103 {
104 addMissingFlagBits( feature.second.requireData, feature.first );
105 }
106 for ( auto & extension : m_extensions )
107 {
108 addMissingFlagBits( extension.second.requireData, extension.first );
109 }
110
111 // determine the extensionsByNumber map
112 for ( auto extensionIt = m_extensions.begin(); extensionIt != m_extensions.end(); ++extensionIt )
113 {
114 int number = stoi( extensionIt->second.number );
115 assert( m_extensionsByNumber.find( number ) == m_extensionsByNumber.end() );
116 m_extensionsByNumber[number] = extensionIt;
117 }
118 }
119
generateVulkanEnumsHppFile() const120 void VulkanHppGenerator::generateVulkanEnumsHppFile() const
121 {
122 std::string const vulkan_enums_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_enums.hpp";
123 std::cout << "VulkanHppGenerator: Generating " << vulkan_enums_hpp << " ..." << std::endl;
124
125 std::string const vulkanEnumsHppTemplate = R"(${licenseHeader}
126 #ifndef VULKAN_ENUMS_HPP
127 # define VULKAN_ENUMS_HPP
128
129 namespace VULKAN_HPP_NAMESPACE
130 {
131 template <typename EnumType, EnumType value>
132 struct CppType
133 {};
134 ${enums}
135 ${indexTypeTraits}
136 } // namespace VULKAN_HPP_NAMESPACE
137 #endif
138 )";
139
140 std::string str = replaceWithMap(
141 vulkanEnumsHppTemplate, { { "enums", generateEnums() }, { "indexTypeTraits", generateIndexTypeTraits() }, { "licenseHeader", m_vulkanLicenseHeader } } );
142
143 writeToFile( str, vulkan_enums_hpp );
144 }
145
generateVulkanFormatTraitsHppFile() const146 void VulkanHppGenerator::generateVulkanFormatTraitsHppFile() const
147 {
148 std::string const vulkan_format_traits_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_format_traits.hpp";
149 std::cout << "VulkanHppGenerator: Generating " << vulkan_format_traits_hpp << " ..." << std::endl;
150
151 std::string const vulkanFormatTraitsHppTemplate = R"(${licenseHeader}
152 #ifndef VULKAN_FORMAT_TRAITS_HPP
153 # define VULKAN_FORMAT_TRAITS_HPP
154
155 #include <vulkan/vulkan.hpp>
156
157 namespace VULKAN_HPP_NAMESPACE
158 {
159 ${formatTraits}
160 } // namespace VULKAN_HPP_NAMESPACE
161 #endif
162 )";
163
164 std::string str = replaceWithMap( vulkanFormatTraitsHppTemplate, { { "formatTraits", generateFormatTraits() }, { "licenseHeader", m_vulkanLicenseHeader } } );
165
166 writeToFile( str, vulkan_format_traits_hpp );
167 }
168
generateVulkanFuncsHppFile() const169 void VulkanHppGenerator::generateVulkanFuncsHppFile() const
170 {
171 std::string const vulkan_funcs_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_funcs.hpp";
172 std::cout << "VulkanHppGenerator: Generating " << vulkan_funcs_hpp << " ..." << std::endl;
173
174 std::string const vulkanFuncsHppTemplate = R"(${licenseHeader}
175 #ifndef VULKAN_FUNCS_HPP
176 # define VULKAN_FUNCS_HPP
177
178 namespace VULKAN_HPP_NAMESPACE
179 {
180 ${commandDefinitions}
181 } // namespace VULKAN_HPP_NAMESPACE
182 #endif
183 )";
184
185 std::string str =
186 replaceWithMap( vulkanFuncsHppTemplate, { { "commandDefinitions", generateCommandDefinitions() }, { "licenseHeader", m_vulkanLicenseHeader } } );
187
188 writeToFile( str, vulkan_funcs_hpp );
189 }
190
generateVulkanHandlesHppFile() const191 void VulkanHppGenerator::generateVulkanHandlesHppFile() const
192 {
193 std::string const vulkan_handles_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_handles.hpp";
194 std::cout << "VulkanHppGenerator: Generating " << vulkan_handles_hpp << " ..." << std::endl;
195
196 std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
197 #ifndef VULKAN_HANDLES_HPP
198 # define VULKAN_HANDLES_HPP
199
200 namespace VULKAN_HPP_NAMESPACE
201 {
202 ${structForwardDeclarations}
203 ${handles}
204 } // namespace VULKAN_HPP_NAMESPACE
205 #endif
206 )";
207
208 std::string str = replaceWithMap(
209 vulkanHandlesHppTemplate,
210 { { "handles", generateHandles() }, { "licenseHeader", m_vulkanLicenseHeader }, { "structForwardDeclarations", generateStructForwardDeclarations() } } );
211
212 writeToFile( str, vulkan_handles_hpp );
213 }
214
generateVulkanHashHppFile() const215 void VulkanHppGenerator::generateVulkanHashHppFile() const
216 {
217 std::string const vulkan_hash_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_hash.hpp";
218 std::cout << "VulkanHppGenerator: Generating " << vulkan_hash_hpp << " ..." << std::endl;
219
220 std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
221 #ifndef VULKAN_HASH_HPP
222 # define VULKAN_HASH_HPP
223
224 #include <vulkan/vulkan.hpp>
225
226 namespace std
227 {
228 //=======================================
229 //=== HASH structures for Flags types ===
230 //=======================================
231
232 template <typename BitType>
233 struct hash<VULKAN_HPP_NAMESPACE::Flags<BitType>>
234 {
235 std::size_t operator()( VULKAN_HPP_NAMESPACE::Flags<BitType> const & flags ) const VULKAN_HPP_NOEXCEPT
236 {
237 return std::hash<typename std::underlying_type<BitType>::type>{}(
238 static_cast<typename std::underlying_type<BitType>::type>( flags ) );
239 }
240 };
241
242 ${handleHashStructures}
243 ${structHashStructures}
244 } // namespace std
245 #endif
246 )";
247
248 std::string str = replaceWithMap( vulkanHandlesHppTemplate,
249 { { "handleHashStructures", generateHandleHashStructures() },
250 { "licenseHeader", m_vulkanLicenseHeader },
251 { "structHashStructures", generateStructHashStructures() } } );
252
253 writeToFile( str, vulkan_hash_hpp );
254 }
255
generateVulkanHppFile() const256 void VulkanHppGenerator::generateVulkanHppFile() const
257 {
258 std::string const vulkan_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan.hpp";
259 std::cout << "VulkanHppGenerator: Generating " << vulkan_hpp << " ... " << std::endl;
260
261 std::string const vulkanHppTemplate = R"(${licenseHeader}
262 ${includes}
263
264 static_assert( VK_HEADER_VERSION == ${headerVersion}, "Wrong VK_HEADER_VERSION!" );
265
266 // 32-bit vulkan is not typesafe for non-dispatchable handles, so don't allow copy constructors on this platform by default.
267 // To enable this feature on 32-bit platforms please define VULKAN_HPP_TYPESAFE_CONVERSION
268 ${typesafeCheck}
269 # if !defined( VULKAN_HPP_TYPESAFE_CONVERSION )
270 # define VULKAN_HPP_TYPESAFE_CONVERSION
271 # endif
272 #endif
273
274 ${defines}
275
276 namespace VULKAN_HPP_NAMESPACE
277 {
278 ${ArrayWrapper1D}
279 ${ArrayWrapper2D}
280 ${Flags}
281 #if !defined( VULKAN_HPP_DISABLE_ENHANCED_MODE )
282 ${ArrayProxy}
283 ${ArrayProxyNoTemporaries}
284 ${StridedArrayProxy}
285 ${Optional}
286 ${StructureChain}
287 ${UniqueHandle}
288 #endif // VULKAN_HPP_DISABLE_ENHANCED_MODE
289
290 ${DispatchLoaderBase}
291 ${DispatchLoaderStatic}
292 ${DispatchLoaderDefault}
293 #if !defined( VULKAN_HPP_NO_SMART_HANDLE )
294 ${ObjectDestroy}
295 ${ObjectFree}
296 ${ObjectRelease}
297 ${PoolFree}
298 #endif // !VULKAN_HPP_NO_SMART_HANDLE
299 ${baseTypes}
300 } // namespace VULKAN_HPP_NAMESPACE
301
302 #include <vulkan/vulkan_enums.hpp>
303 #if !defined( VULKAN_HPP_NO_TO_STRING )
304 #include <vulkan/vulkan_to_string.hpp>
305 #endif
306
307 #ifndef VULKAN_HPP_NO_EXCEPTIONS
308 namespace std
309 {
310 template <>
311 struct is_error_code_enum<VULKAN_HPP_NAMESPACE::Result> : public true_type
312 {};
313 } // namespace std
314 #endif
315
316 namespace VULKAN_HPP_NAMESPACE
317 {
318 #ifndef VULKAN_HPP_NO_EXCEPTIONS
319 ${Exceptions}
320 ${resultExceptions}
321 ${throwResultException}
322 #endif
323
324 ${ResultValue}
325 ${resultChecks}
326 } // namespace VULKAN_HPP_NAMESPACE
327
328 // clang-format off
329 #include <vulkan/vulkan_handles.hpp>
330 #include <vulkan/vulkan_structs.hpp>
331 #include <vulkan/vulkan_funcs.hpp>
332 // clang-format on
333
334 namespace VULKAN_HPP_NAMESPACE
335 {
336 #if !defined( VULKAN_HPP_DISABLE_ENHANCED_MODE )
337 ${structExtendsStructs}
338 #endif // VULKAN_HPP_DISABLE_ENHANCED_MODE
339
340 ${DynamicLoader}
341 ${DispatchLoaderDynamic}
342 } // namespace VULKAN_HPP_NAMESPACE
343 #endif
344 )";
345
346 std::string str = replaceWithMap( vulkanHppTemplate,
347 { { "ArrayProxy", readSnippet( "ArrayProxy.hpp" ) },
348 { "ArrayProxyNoTemporaries", readSnippet( "ArrayProxyNoTemporaries.hpp" ) },
349 { "ArrayWrapper1D", readSnippet( "ArrayWrapper1D.hpp" ) },
350 { "ArrayWrapper2D", readSnippet( "ArrayWrapper2D.hpp" ) },
351 { "baseTypes", generateBaseTypes() },
352 { "defines", readSnippet( "defines.hpp" ) },
353 { "DispatchLoaderBase", readSnippet( "DispatchLoaderBase.hpp" ) },
354 { "DispatchLoaderDefault", readSnippet( "DispatchLoaderDefault.hpp" ) },
355 { "DispatchLoaderDynamic", generateDispatchLoaderDynamic() },
356 { "DispatchLoaderStatic", generateDispatchLoaderStatic() },
357 { "DynamicLoader", readSnippet( "DynamicLoader.hpp" ) },
358 { "Exceptions", readSnippet( "Exceptions.hpp" ) },
359 { "Flags", readSnippet( "Flags.hpp" ) },
360 { "headerVersion", m_version },
361 { "includes", readSnippet( "includes.hpp" ) },
362 { "licenseHeader", m_vulkanLicenseHeader },
363 { "ObjectDestroy", readSnippet( "ObjectDestroy.hpp" ) },
364 { "ObjectFree", readSnippet( "ObjectFree.hpp" ) },
365 { "ObjectRelease", readSnippet( "ObjectRelease.hpp" ) },
366 { "Optional", readSnippet( "Optional.hpp" ) },
367 { "PoolFree", readSnippet( "PoolFree.hpp" ) },
368 { "resultChecks", readSnippet( "resultChecks.hpp" ) },
369 { "resultExceptions", generateResultExceptions() },
370 { "structExtendsStructs", generateStructExtendsStructs() },
371 { "ResultValue", readSnippet( "ResultValue.hpp" ) },
372 { "StridedArrayProxy", readSnippet( "StridedArrayProxy.hpp" ) },
373 { "StructureChain", readSnippet( "StructureChain.hpp" ) },
374 { "throwResultException", generateThrowResultException() },
375 { "typesafeCheck", m_typesafeCheck },
376 { "UniqueHandle", readSnippet( "UniqueHandle.hpp" ) } } );
377
378 writeToFile( str, vulkan_hpp );
379 }
380
generateVulkanRAIIHppFile() const381 void VulkanHppGenerator::generateVulkanRAIIHppFile() const
382 {
383 std::string const vulkan_raii_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_raii.hpp";
384 std::cout << "VulkanHppGenerator: Generating " << vulkan_raii_hpp << " ..." << std::endl;
385
386 std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
387 #ifndef VULKAN_RAII_HPP
388 #define VULKAN_RAII_HPP
389
390 #include <memory>
391 #include <utility> // std::exchange, std::forward
392 #include <vulkan/vulkan.hpp>
393
394 #include <android-base/expected.h>
395 #include <android-base/logging.h>
396
397 #if !defined( VULKAN_HPP_RAII_NAMESPACE )
398 # define VULKAN_HPP_RAII_NAMESPACE raii
399 #endif
400
401 #if !defined( VULKAN_HPP_DISABLE_ENHANCED_MODE )
402 namespace VULKAN_HPP_NAMESPACE
403 {
404 namespace VULKAN_HPP_RAII_NAMESPACE
405 {
406 template <class T, class U = T>
407 VULKAN_HPP_CONSTEXPR_14 VULKAN_HPP_INLINE T exchange( T & obj, U && newValue )
408 {
409 # if ( 14 <= VULKAN_HPP_CPP_VERSION )
410 return std::exchange<T>( obj, std::forward<U>( newValue ) );
411 # else
412 T oldValue = std::move( obj );
413 obj = std::forward<U>( newValue );
414 return oldValue;
415 # endif
416 }
417
418 ${RAIIDispatchers}
419 ${RAIIHandles}
420 ${RAIICommandDefinitions}
421 } // namespace VULKAN_HPP_RAII_NAMESPACE
422 } // namespace VULKAN_HPP_NAMESPACE
423 #endif
424 #endif
425 )";
426
427 std::string str = replaceWithMap( vulkanHandlesHppTemplate,
428 { { "licenseHeader", m_vulkanLicenseHeader },
429 { "RAIICommandDefinitions", generateRAIICommandDefinitions() },
430 { "RAIIDispatchers", generateRAIIDispatchers() },
431 { "RAIIHandles", generateRAIIHandles() } } );
432
433 writeToFile( str, vulkan_raii_hpp );
434 }
435
generateVulkanStaticAssertionsHppFile() const436 void VulkanHppGenerator::generateVulkanStaticAssertionsHppFile() const
437 {
438 std::string const static_assertions_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_static_assertions.hpp";
439 std::cout << "VulkanHppGenerator: Generating " << static_assertions_hpp << " ..." << std::endl;
440
441 std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
442 #ifndef VULKAN_STATIC_ASSERTIONS_HPP
443 # define VULKAN_STATIC_ASSERTIONS_HPP
444
445 #include <vulkan/vulkan.hpp>
446
447 //=========================
448 //=== static_assertions ===
449 //=========================
450
451 ${staticAssertions}
452 #endif
453 )";
454
455 std::string str =
456 replaceWithMap( vulkanHandlesHppTemplate, { { "licenseHeader", m_vulkanLicenseHeader }, { "staticAssertions", generateStaticAssertions() } } );
457
458 writeToFile( str, static_assertions_hpp );
459 }
460
generateVulkanStructsHppFile() const461 void VulkanHppGenerator::generateVulkanStructsHppFile() const
462 {
463 std::string const vulkan_structs_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_structs.hpp";
464 std::cout << "VulkanHppGenerator: Generating " << vulkan_structs_hpp << " ..." << std::endl;
465
466 std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
467 #ifndef VULKAN_STRUCTS_HPP
468 # define VULKAN_STRUCTS_HPP
469
470 #include <cstring> // strcmp
471
472 namespace VULKAN_HPP_NAMESPACE
473 {
474 ${structs}
475 } // namespace VULKAN_HPP_NAMESPACE
476 #endif
477 )";
478
479 std::string str = replaceWithMap( vulkanHandlesHppTemplate, { { "licenseHeader", m_vulkanLicenseHeader }, { "structs", generateStructs() } } );
480
481 writeToFile( str, vulkan_structs_hpp );
482 }
483
generateVulkanToStringHppFile() const484 void VulkanHppGenerator::generateVulkanToStringHppFile() const
485 {
486 std::string const vulkan_to_string_hpp = std::string( BASE_PATH ) + "/vulkan/vulkan_to_string.hpp";
487 std::cout << "VulkanHppGenerator: Generating " << vulkan_to_string_hpp << "..." << std::endl;
488
489 std::string const vulkanHandlesHppTemplate = R"(${licenseHeader}
490 #ifndef VULKAN_TO_STRING_HPP
491 # define VULKAN_TO_STRING_HPP
492
493 #include <vulkan/vulkan_enums.hpp>
494
495 #if __cpp_lib_format
496 # include <format> // std::format
497 #else
498 # include <sstream> // std::stringstream
499 #endif
500
501 namespace VULKAN_HPP_NAMESPACE
502 {
503 ${bitmasksToString}
504 ${enumsToString}
505 } // namespace VULKAN_HPP_NAMESPACE
506 #endif
507 )";
508
509 std::string str = replaceWithMap(
510 vulkanHandlesHppTemplate,
511 { { "bitmasksToString", generateBitmasksToString() }, { "enumsToString", generateEnumsToString() }, { "licenseHeader", m_vulkanLicenseHeader } } );
512
513 writeToFile( str, vulkan_to_string_hpp );
514 }
515
prepareRAIIHandles()516 void VulkanHppGenerator::prepareRAIIHandles()
517 {
518 // filter out functions that are not usefull on this level of abstraction (like vkGetInstanceProcAddr)
519 // and all the construction and destruction functions, as they are used differently
520 assert( m_handles.begin()->first.empty() );
521 for ( auto handleIt = std::next( m_handles.begin() ); handleIt != m_handles.end(); ++handleIt )
522 {
523 handleIt->second.destructorIt = determineRAIIHandleDestructor( handleIt->first );
524 if ( handleIt->second.destructorIt != m_commands.end() )
525 {
526 m_RAIISpecialFunctions.insert( handleIt->second.destructorIt->first );
527 }
528 handleIt->second.constructorIts = determineRAIIHandleConstructors( handleIt->first, handleIt->second.destructorIt );
529 }
530
531 distributeSecondLevelCommands( m_RAIISpecialFunctions );
532 }
533
prepareVulkanFuncs()534 void VulkanHppGenerator::prepareVulkanFuncs()
535 {
536 // rename a couple of function parameters to prevent this warning, treated as an error:
537 // warning C4458: declaration of 'objectType' hides class member
538 for ( auto & command : m_commands )
539 {
540 for ( auto & param : command.second.params )
541 {
542 if ( param.name == "objectType" )
543 {
544 param.name += "_";
545 }
546 }
547 }
548 }
549
550 //
551 // VulkanHppGenerator private interface
552 //
553
addCommand(std::string const & name,CommandData & commandData)554 void VulkanHppGenerator::addCommand( std::string const & name, CommandData & commandData )
555 {
556 // find the handle this command is going to be associated to
557 checkForError( !commandData.params.empty(), commandData.xmlLine, "command <" + name + "> with no params" );
558 std::map<std::string, HandleData>::iterator handleIt = m_handles.find( commandData.params[0].type.type );
559 if ( handleIt == m_handles.end() )
560 {
561 handleIt = m_handles.begin();
562 assert( handleIt->first == "" );
563 }
564 commandData.handle = handleIt->first;
565
566 // add this command to the list of commands
567 checkForError( m_commands.insert( std::make_pair( name, commandData ) ).second, commandData.xmlLine, "already encountered command <" + name + ">" );
568 }
569
addMissingFlagBits(std::vector<RequireData> & requireData,std::string const & referencedIn)570 void VulkanHppGenerator::addMissingFlagBits( std::vector<RequireData> & requireData, std::string const & referencedIn )
571 {
572 for ( auto & require : requireData )
573 {
574 std::vector<std::string> newTypes;
575 for ( auto const & type : require.types )
576 {
577 auto bitmaskIt = m_bitmasks.find( type );
578 if ( ( bitmaskIt != m_bitmasks.end() ) && bitmaskIt->second.requirements.empty() )
579 {
580 // generate the flagBits enum name out of the bitmask name: VkFooFlagsXXX -> VkFooFlagBitsXXX
581 size_t pos = bitmaskIt->first.find( "Flags" );
582 assert( pos != std::string::npos );
583 std::string flagBits = bitmaskIt->first.substr( 0, pos + 4 ) + "Bit" + bitmaskIt->first.substr( pos + 4 );
584
585 // as the bitmask's requirement is still empty, this flagBits should not be listed in the require list!
586 assert( std::find_if( require.types.begin(), require.types.end(), [&flagBits]( std::string const & type ) { return ( type == flagBits ); } ) ==
587 require.types.end() );
588
589 bitmaskIt->second.requirements = flagBits;
590
591 // some flagsBits are specified but never listed as required for any flags!
592 // so, even if this bitmask has no enum listed as required, it might still already exist in the enums list
593 auto enumIt = m_enums.find( flagBits );
594 if ( enumIt == m_enums.end() )
595 {
596 m_enums.insert( std::make_pair( flagBits, EnumData{ .isBitmask = true, .xmlLine = 0 } ) );
597
598 assert( m_types.find( flagBits ) == m_types.end() );
599 m_types.insert( std::make_pair( flagBits, TypeData{ .category = TypeCategory::Bitmask, .referencedIn = referencedIn } ) );
600 }
601 else
602 {
603 assert( m_types.find( flagBits ) != m_types.end() );
604 enumIt->second.isBitmask = true;
605 }
606
607 newTypes.push_back( flagBits );
608 }
609 }
610 // add all the newly created flagBits types to the require list as if they had been part of the vk.xml!
611 require.types.insert( require.types.end(), newTypes.begin(), newTypes.end() );
612 }
613 }
614
addTitleAndProtection(std::string const & title,std::string const & strIf,std::string const & strElse) const615 std::string VulkanHppGenerator::addTitleAndProtection( std::string const & title, std::string const & strIf, std::string const & strElse ) const
616 {
617 std::string str;
618 if ( !strIf.empty() )
619 {
620 auto [enter, leave] = generateProtection( getProtectFromTitle( title ) );
621 str = "\n" + enter + " //=== " + title + " ===\n" + strIf;
622 if ( !enter.empty() && !strElse.empty() )
623 {
624 str += "#else \n" + strElse;
625 }
626 str += leave;
627 }
628 return str;
629 }
630
allVectorSizesSupported(std::vector<ParamData> const & params,std::map<size_t,VectorParamData> const & vectorParams) const631 bool VulkanHppGenerator::allVectorSizesSupported( std::vector<ParamData> const & params, std::map<size_t, VectorParamData> const & vectorParams ) const
632 {
633 // check if all vector sizes are by value and their type is one of "uint32_t", "VkDeviceSize", or "VkSampleCountFlagBits"
634 return std::find_if_not( vectorParams.begin(),
635 vectorParams.end(),
636 [¶ms]( auto const & vpi )
637 {
638 return params[vpi.second.lenParam].type.isValue() &&
639 ( ( params[vpi.second.lenParam].type.type == "uint32_t" ) || ( params[vpi.second.lenParam].type.type == "VkDeviceSize" ) ||
640 ( params[vpi.second.lenParam].type.type == "VkSampleCountFlagBits" ) );
641 } ) == vectorParams.end();
642 }
643
appendDispatchLoaderDynamicCommands(std::vector<RequireData> const & requireData,std::set<std::string> & listedCommands,std::string const & title,std::string & commandMembers,std::string & initialCommandAssignments,std::string & instanceCommandAssignments,std::string & deviceCommandAssignments) const644 void VulkanHppGenerator::appendDispatchLoaderDynamicCommands( std::vector<RequireData> const & requireData,
645 std::set<std::string> & listedCommands,
646 std::string const & title,
647 std::string & commandMembers,
648 std::string & initialCommandAssignments,
649 std::string & instanceCommandAssignments,
650 std::string & deviceCommandAssignments ) const
651 {
652 std::string members, initial, instance, device, placeholders;
653 for ( auto const & require : requireData )
654 {
655 for ( auto const & command : require.commands )
656 {
657 if ( listedCommands.insert( command ).second )
658 {
659 auto commandIt = m_commands.find( command );
660 assert( commandIt != m_commands.end() );
661
662 members += " PFN_" + commandIt->first + " " + commandIt->first + " = 0;\n";
663 placeholders += " PFN_dummy " + commandIt->first + "_placeholder = 0;\n";
664 if ( commandIt->second.handle.empty() )
665 {
666 initial += generateDispatchLoaderDynamicCommandAssignment( commandIt->first, commandIt->second, "NULL" );
667 }
668 else
669 {
670 instance += generateDispatchLoaderDynamicCommandAssignment( commandIt->first, commandIt->second, "instance" );
671 if ( isDeviceCommand( commandIt->second ) )
672 {
673 device += generateDispatchLoaderDynamicCommandAssignment( commandIt->first, commandIt->second, "device" );
674 }
675 }
676 }
677 }
678 }
679 auto [enter, leave] = generateProtection( getProtectFromTitle( title ) );
680 std::string header = "\n" + enter + " //=== " + title + " ===\n";
681 if ( !members.empty() )
682 {
683 commandMembers += header + members;
684 if ( !enter.empty() )
685 {
686 commandMembers += "#else\n" + placeholders;
687 }
688 commandMembers += leave;
689 }
690 if ( !initial.empty() )
691 {
692 initialCommandAssignments += header + initial + leave;
693 }
694 if ( !instance.empty() )
695 {
696 instanceCommandAssignments += header + instance + leave;
697 }
698 if ( !device.empty() )
699 {
700 deviceCommandAssignments += header + device + leave;
701 }
702 }
703
appendRAIIDispatcherCommands(std::vector<RequireData> const & requireData,std::set<std::string> & listedCommands,std::string const & title,std::string & contextInitializers,std::string & contextMembers,std::string & deviceAssignments,std::string & deviceMembers,std::string & instanceAssignments,std::string & instanceMembers) const704 void VulkanHppGenerator::appendRAIIDispatcherCommands( std::vector<RequireData> const & requireData,
705 std::set<std::string> & listedCommands,
706 std::string const & title,
707 std::string & contextInitializers,
708 std::string & contextMembers,
709 std::string & deviceAssignments,
710 std::string & deviceMembers,
711 std::string & instanceAssignments,
712 std::string & instanceMembers ) const
713 {
714 std::string ci, cm, da, dm, dmp, ia, im, imp;
715 for ( auto const & require : requireData )
716 {
717 for ( auto const & command : require.commands )
718 {
719 if ( listedCommands.insert( command ).second )
720 {
721 auto commandIt = m_commands.find( command );
722 assert( commandIt != m_commands.end() );
723 if ( commandIt->second.handle.empty() )
724 {
725 assert( commandIt->second.alias.empty() );
726
727 ci += ", " + commandIt->first + "( PFN_" + commandIt->first + "( getProcAddr( NULL, \"" + commandIt->first + "\" ) ) )";
728
729 cm += " PFN_" + commandIt->first + " " + commandIt->first + " = 0;\n";
730 }
731 else if ( ( commandIt->second.handle == "VkDevice" ) || hasParentHandle( commandIt->second.handle, "VkDevice" ) )
732 {
733 da += " " + commandIt->first + " = PFN_" + commandIt->first + "( vkGetDeviceProcAddr( device, \"" + commandIt->first + "\" ) );\n";
734 // if this is an alias'ed function, use it as a fallback for the original one
735 if ( !commandIt->second.alias.empty() )
736 {
737 da += " if ( !" + commandIt->second.alias + " ) " + commandIt->second.alias + " = " + commandIt->first + ";\n";
738 }
739
740 dm += " PFN_" + commandIt->first + " " + commandIt->first + " = 0;\n";
741 dmp += " PFN_dummy " + commandIt->first + "_placeholder = 0;\n";
742 }
743 else
744 {
745 assert( ( commandIt->second.handle == "VkInstance" ) || hasParentHandle( commandIt->second.handle, "VkInstance" ) );
746
747 // filter out vkGetInstanceProcAddr, as starting with Vulkan 1.2 it can resolve itself only (!) with an
748 // instance nullptr !
749 if ( command != "vkGetInstanceProcAddr" )
750 {
751 ia += " " + commandIt->first + " = PFN_" + commandIt->first + "( vkGetInstanceProcAddr( instance, \"" + commandIt->first + "\" ) );\n";
752 // if this is an alias'ed function, use it as a fallback for the original one
753 if ( !commandIt->second.alias.empty() )
754 {
755 ia += " if ( !" + commandIt->second.alias + " ) " + commandIt->second.alias + " = " + commandIt->first + ";\n";
756 }
757 }
758
759 im += +" PFN_" + commandIt->first + " " + commandIt->first + " = 0;\n";
760 imp += " PFN_dummy " + commandIt->first + "_placeholder = 0;\n";
761 }
762 }
763 }
764 }
765 contextInitializers += addTitleAndProtection( title, ci );
766 contextMembers += addTitleAndProtection( title, cm );
767 deviceAssignments += addTitleAndProtection( title, da );
768 deviceMembers += addTitleAndProtection( title, dm, dmp );
769 instanceAssignments += addTitleAndProtection( title, ia );
770 instanceMembers += addTitleAndProtection( title, im, imp );
771 }
772
checkBitmaskCorrectness() const773 void VulkanHppGenerator::checkBitmaskCorrectness() const
774 {
775 for ( auto const & bitmask : m_bitmasks )
776 {
777 // check that a bitmask is referenced somewhere
778 // I think, it's not forbidden to not reference a bitmask, but it would probably be not intended?
779 auto typeIt = m_types.find( bitmask.first );
780 assert( typeIt != m_types.end() );
781 checkForError( !typeIt->second.referencedIn.empty(), bitmask.second.xmlLine, "bitmask <" + bitmask.first + "> not listed in any feature or extension" );
782
783 // check that the requirement is an enum
784 if ( !bitmask.second.requirements.empty() )
785 {
786 checkForError( m_enums.find( bitmask.second.requirements ) != m_enums.end(),
787 bitmask.second.xmlLine,
788 "bitmask requires unknown <" + bitmask.second.requirements + ">" );
789 }
790 }
791 }
792
checkCommandCorrectness() const793 void VulkanHppGenerator::checkCommandCorrectness() const
794 {
795 // prepare command checks by gathering all result codes and aliases into one set of resultCodes
796 auto resultIt = m_enums.find( "VkResult" );
797 assert( resultIt != m_enums.end() );
798 std::set<std::string> resultCodes;
799 for ( auto rc : resultIt->second.values )
800 {
801 resultCodes.insert( rc.name );
802 }
803 for ( auto rc : resultIt->second.aliases )
804 {
805 resultCodes.insert( rc.first );
806 }
807
808 // command checks
809 for ( auto const & command : m_commands )
810 {
811 // check that a command is referenced somewhere
812 // I think, it's not forbidden to not reference a function, but it would probably be not intended?
813 checkForError( !command.second.referencedIn.empty(), command.second.xmlLine, "command <" + command.first + "> not listed in any feature or extension" );
814
815 // check for unknown error or succes codes
816 for ( auto const & ec : command.second.errorCodes )
817 {
818 checkForError( resultCodes.find( ec ) != resultCodes.end(), command.second.xmlLine, "command uses unknown error code <" + ec + ">" );
819 }
820 for ( auto const & sc : command.second.successCodes )
821 {
822 checkForError( resultCodes.find( sc ) != resultCodes.end(), command.second.xmlLine, "command uses unknown success code <" + sc + ">" );
823 }
824
825 // check that functions returning a VkResult specify successcodes
826 checkForError( ( command.second.returnType != "VkResult" ) || !command.second.successCodes.empty(),
827 command.second.xmlLine,
828 "missing successcodes on command <" + command.first + "> returning VkResult!" );
829
830 // check that all parameter types as well as the return type are known types
831 for ( auto const & p : command.second.params )
832 {
833 checkForError( m_types.find( p.type.type ) != m_types.end(), p.xmlLine, "comand uses parameter of unknown type <" + p.type.type + ">" );
834 }
835 checkForError( m_types.find( command.second.returnType ) != m_types.end(),
836 command.second.xmlLine,
837 "command uses unknown return type <" + command.second.returnType + ">" );
838 }
839 }
840
checkCorrectness() const841 void VulkanHppGenerator::checkCorrectness() const
842 {
843 checkForError( !m_vulkanLicenseHeader.empty(), -1, "missing license header" );
844 checkBitmaskCorrectness();
845 checkCommandCorrectness();
846 checkDefineCorrectness();
847 checkEnumCorrectness();
848 checkExtensionCorrectness();
849 checkFuncPointerCorrectness();
850 checkHandleCorrectness();
851 checkStructCorrectness();
852 }
853
checkDefineCorrectness() const854 void VulkanHppGenerator::checkDefineCorrectness() const
855 {
856 for ( auto const & d : m_defines )
857 {
858 checkForError( d.second.require.empty() || ( m_defines.find( d.second.require ) != m_defines.end() ),
859 d.second.xmlLine,
860 "using undefined require <" + d.second.require + ">" );
861 }
862 }
863
checkEnumCorrectness() const864 void VulkanHppGenerator::checkEnumCorrectness() const
865 {
866 for ( auto const & e : m_enums )
867 {
868 // check that a bitmask is referenced somewhere
869 // it's not forbidden to not reference a bitmask, and in fact that happens! So just warn here
870 auto typeIt = m_types.find( e.first );
871 assert( typeIt != m_types.end() );
872 checkForWarning( !typeIt->second.referencedIn.empty(), e.second.xmlLine, "enum <" + e.first + "> not listed in any feature or extension" );
873
874 // check that the aliasNames are known enum values or known aliases
875 for ( auto const & alias : e.second.aliases )
876 {
877 checkForError(
878 ( std::find_if( e.second.values.begin(), e.second.values.end(), [&alias]( EnumValueData const & evd ) { return evd.name == alias.second.name; } ) !=
879 e.second.values.end() ) ||
880 ( e.second.aliases.find( alias.second.name ) != e.second.aliases.end() ),
881 alias.second.xmlLine,
882 "enum <" + alias.first + "> uses unknown alias <" + alias.second.name + ">" );
883 }
884
885 // check that any protection fits to the corresponding extension
886 for ( auto const & v : e.second.values )
887 {
888 if ( !v.protect.empty() )
889 {
890 auto extIt = m_extensions.find( v.extension );
891 assert( extIt != m_extensions.end() );
892 auto platformIt = m_platforms.find( extIt->second.platform );
893 assert( platformIt != m_platforms.end() );
894 checkForError( v.protect == platformIt->second.protect,
895 v.xmlLine,
896 "attribute <protect> of enum value <" + v.name + "> is \"" + v.protect + "\" but corresponding extension <" + v.extension +
897 "> belongs to platform <" + platformIt->first + "> with protection \"" + platformIt->second.protect + "\"" );
898 }
899 }
900 }
901
902 // enum checks by features and extensions
903 for ( auto & feature : m_features )
904 {
905 checkEnumCorrectness( feature.second.requireData );
906 }
907 for ( auto & ext : m_extensions )
908 {
909 checkEnumCorrectness( ext.second.requireData );
910 }
911
912 // special check for VkFormat
913 if ( !m_formats.empty() )
914 {
915 auto enumIt = m_enums.find( "VkFormat" );
916 assert( enumIt != m_enums.end() );
917 assert( enumIt->second.values.front().name == "VK_FORMAT_UNDEFINED" );
918 for ( auto enumValueIt = std::next( enumIt->second.values.begin() ); enumValueIt != enumIt->second.values.end(); ++enumValueIt )
919 {
920 auto formatIt = m_formats.find( enumValueIt->name );
921 if ( formatIt == m_formats.end() )
922 {
923 auto aliasIt = std::find_if(
924 enumIt->second.aliases.begin(), enumIt->second.aliases.end(), [&enumValueIt]( auto const & ead ) { return ead.second.name == enumValueIt->name; } );
925 checkForError( aliasIt != enumIt->second.aliases.end(), enumValueIt->xmlLine, "missing format specification for <" + enumValueIt->name + ">" );
926 }
927 }
928 }
929 }
930
checkEnumCorrectness(std::vector<RequireData> const & requireData) const931 void VulkanHppGenerator::checkEnumCorrectness( std::vector<RequireData> const & requireData ) const
932 {
933 for ( auto const & require : requireData )
934 {
935 for ( auto const & type : require.types )
936 {
937 auto typeIt = m_types.find( type );
938 assert( typeIt != m_types.end() );
939 switch ( typeIt->second.category )
940 {
941 case TypeCategory::Bitmask:
942 {
943 // check that each "require" listed for a bitmask is listed for a feature or an extension
944 auto bitmaskIt = m_bitmasks.find( type );
945 if ( bitmaskIt != m_bitmasks.end() )
946 {
947 // not for every bitmask is a "require" listed
948 if ( !bitmaskIt->second.requirements.empty() )
949 {
950 auto requireTypeIt = m_types.find( bitmaskIt->second.requirements );
951 assert( requireTypeIt != m_types.end() );
952 checkForError( !requireTypeIt->second.referencedIn.empty(),
953 bitmaskIt->second.xmlLine,
954 "bitmask <" + bitmaskIt->first + "> requires <" + bitmaskIt->second.requirements +
955 "> which is not listed for any feature or extension!" );
956 }
957 }
958 else
959 {
960 // every bitmask not listed in the m_bitmasks, should be an alias of such a thing
961 assert( std::find_if( m_bitmasks.begin(),
962 m_bitmasks.end(),
963 [&type]( std::pair<const std::string, BitmaskData> const & bd ) { return bd.second.alias == type; } ) != m_bitmasks.end() );
964 }
965 }
966 break;
967 case TypeCategory::Enum:
968 {
969 auto enumIt = m_enums.find( type );
970 if ( enumIt != m_enums.end() )
971 {
972 if ( enumIt->second.isBitmask )
973 {
974 // check that any enum of a bitmask is listed as "require" or "bitvalues" for a bitmask
975 auto bitmaskIt = std::find_if(
976 m_bitmasks.begin(), m_bitmasks.end(), [&enumIt]( auto const & bitmask ) { return bitmask.second.requirements == enumIt->first; } );
977 checkForError( bitmaskIt != m_bitmasks.end(),
978 enumIt->second.xmlLine,
979 "enum <" + enumIt->first + "> is not listed as an requires or bitvalues for any bitmask in the types section" );
980
981 // check that bitwidth of the enum and type of the corresponding bitmask are equal
982 checkForError( ( enumIt->second.bitwidth != "64" ) || ( bitmaskIt->second.type == "VkFlags64" ),
983 enumIt->second.xmlLine,
984 "enum <" + enumIt->first + "> is marked with bitwidth <64> but corresponding bitmask <" + bitmaskIt->first +
985 "> is not of type <VkFlags64>" );
986 }
987 }
988 else
989 {
990 // every enum not listed in the m_enums, should be an alias of such a thing
991 assert( std::find_if( m_enums.begin(),
992 m_enums.end(),
993 [&type]( std::pair<const std::string, EnumData> const & ed ) { return ed.second.alias == type; } ) != m_enums.end() );
994 }
995 }
996 break;
997 default: break;
998 }
999 }
1000 }
1001 }
1002
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) const1003 bool VulkanHppGenerator::checkEquivalentSingularConstructor( std::vector<std::map<std::string, CommandData>::const_iterator> const & constructorIts,
1004 std::map<std::string, CommandData>::const_iterator constructorIt,
1005 std::vector<ParamData>::const_iterator lenIt ) const
1006 {
1007 // check, if there is no singular constructor with the very same arguments as this array constructor
1008 // (besides the size, of course)
1009 auto isEquivalentSingularConstructor = [constructorIt, lenIt]( std::map<std::string, CommandData>::const_iterator it )
1010 {
1011 if ( it->second.params.size() + 1 != constructorIt->second.params.size() )
1012 {
1013 return false;
1014 }
1015 size_t lenIdx = std::distance( constructorIt->second.params.begin(), lenIt );
1016 for ( size_t i = 0, j = 0; i < it->second.params.size(); ++i, ++j )
1017 {
1018 assert( j < constructorIt->second.params.size() );
1019 if ( j == lenIdx )
1020 {
1021 ++j;
1022 }
1023 if ( it->second.params[i].type.type != constructorIt->second.params[j].type.type )
1024 {
1025 return false;
1026 }
1027 }
1028 return true;
1029 };
1030 return ( std::find_if( constructorIts.begin(), constructorIts.end(), isEquivalentSingularConstructor ) != constructorIts.end() );
1031 }
1032
checkExtensionCorrectness() const1033 void VulkanHppGenerator::checkExtensionCorrectness() const
1034 {
1035 for ( auto const & extension : m_extensions )
1036 {
1037 // check for existence of any deprecation, obsoletion, or promotion
1038 if ( !extension.second.deprecatedBy.empty() )
1039 {
1040 checkForError( ( m_extensions.find( extension.second.deprecatedBy ) != m_extensions.end() ) ||
1041 ( m_features.find( extension.second.deprecatedBy ) != m_features.end() ),
1042 extension.second.xmlLine,
1043 "extension deprecated by unknown extension/version <" + extension.second.promotedTo + ">" );
1044 }
1045 if ( !extension.second.obsoletedBy.empty() )
1046 {
1047 checkForError( ( m_extensions.find( extension.second.obsoletedBy ) != m_extensions.end() ) ||
1048 ( m_features.find( extension.second.obsoletedBy ) != m_features.end() ),
1049 extension.second.xmlLine,
1050 "extension obsoleted by unknown extension/version <" + extension.second.promotedTo + ">" );
1051 }
1052 if ( !extension.second.promotedTo.empty() )
1053 {
1054 checkForError( ( m_extensions.find( extension.second.promotedTo ) != m_extensions.end() ) ||
1055 ( m_features.find( extension.second.promotedTo ) != m_features.end() ),
1056 extension.second.xmlLine,
1057 "extension promoted to unknown extension/version <" + extension.second.promotedTo + ">" );
1058 }
1059
1060 // check for existence of any requirement
1061 for ( auto const & require : extension.second.requireData )
1062 {
1063 if ( !require.depends.empty() )
1064 {
1065 for ( auto const & depends : require.depends )
1066 {
1067 checkForError( ( m_features.find( depends ) != m_features.end() ) || ( m_extensions.find( depends ) != m_extensions.end() ),
1068 require.xmlLine,
1069 "extension <" + extension.first + "> lists an unknown depends <" + depends + ">" );
1070 }
1071 }
1072 }
1073 }
1074 }
1075
checkFuncPointerCorrectness() const1076 void VulkanHppGenerator::checkFuncPointerCorrectness() const
1077 {
1078 for ( auto const & funcPointer : m_funcPointers )
1079 {
1080 if ( !funcPointer.second.requirements.empty() )
1081 {
1082 checkForError( m_types.find( funcPointer.second.requirements ) != m_types.end(),
1083 funcPointer.second.xmlLine,
1084 "funcpointer requires unknown <" + funcPointer.second.requirements + ">" );
1085 }
1086 for ( auto const & argument : funcPointer.second.arguments )
1087 {
1088 checkForError( m_types.find( argument.type ) != m_types.end(), argument.xmlLine, "funcpointer argument of unknown type <" + argument.type + ">" );
1089 }
1090 }
1091 }
1092
checkHandleCorrectness() const1093 void VulkanHppGenerator::checkHandleCorrectness() const
1094 {
1095 // prepare handle checks by getting the VkObjectType enum
1096 auto objectTypeIt = m_enums.find( "VkObjectType" );
1097 assert( objectTypeIt != m_enums.end() );
1098
1099 // handle checks
1100 for ( auto const & handle : m_handles )
1101 {
1102 // check the existence of the parent
1103 checkForError( m_handles.find( handle.second.parent ) != m_handles.end(),
1104 handle.second.xmlLine,
1105 "handle <" + handle.first + "> with unknown parent <" + handle.second.parent + ">" );
1106
1107 // check existence of objTypeEnum used with this handle type
1108 if ( !handle.first.empty() )
1109 {
1110 assert( !handle.second.objTypeEnum.empty() );
1111 checkForError( std::find_if( objectTypeIt->second.values.begin(),
1112 objectTypeIt->second.values.end(),
1113 [&handle]( EnumValueData const & evd )
1114 { return evd.name == handle.second.objTypeEnum; } ) != objectTypeIt->second.values.end(),
1115 handle.second.xmlLine,
1116 "handle <" + handle.first + "> specifies unknown \"objtypeenum\" <" + handle.second.objTypeEnum + ">" );
1117 }
1118 }
1119
1120 // check that all specified objectType values are used with a handle type
1121 for ( auto const & objectTypeValue : objectTypeIt->second.values )
1122 {
1123 if ( objectTypeValue.name != "VK_OBJECT_TYPE_UNKNOWN" )
1124 {
1125 checkForError( std::find_if( m_handles.begin(),
1126 m_handles.end(),
1127 [&objectTypeValue]( std::pair<std::string, HandleData> const & hd )
1128 { return hd.second.objTypeEnum == objectTypeValue.name; } ) != m_handles.end(),
1129 objectTypeValue.xmlLine,
1130 "VkObjectType value <" + objectTypeValue.name + "> not specified as \"objtypeenum\" for any handle" );
1131 }
1132 }
1133 }
1134
checkStructCorrectness() const1135 void VulkanHppGenerator::checkStructCorrectness() const
1136 {
1137 for ( auto const & structAlias : m_structureAliases )
1138 {
1139 auto structIt = m_structures.find( structAlias.second.alias );
1140 checkForError( structIt != m_structures.end(), structAlias.second.xmlLine, "unknown struct alias <" + structAlias.second.alias + ">" );
1141 }
1142
1143 for ( auto const & structAliasInverse : m_structureAliasesInverse )
1144 {
1145 auto structIt = m_structures.find( structAliasInverse.first );
1146 if ( structIt == m_structures.end() )
1147 {
1148 assert( !structAliasInverse.second.empty() );
1149 auto aliasIt = m_structureAliases.find( *structAliasInverse.second.begin() );
1150 assert( aliasIt != m_structureAliases.end() );
1151 checkForError( false, aliasIt->second.xmlLine, "struct <" + aliasIt->first + "> uses unknown alias <" + aliasIt->second.alias + ">" );
1152 }
1153 }
1154
1155 std::set<std::string> sTypeValues;
1156 for ( auto const & structure : m_structures )
1157 {
1158 // check that a struct is referenced somewhere
1159 // I think, it's not forbidden to not reference a struct, but it would probably be not intended?
1160 auto typeIt = m_types.find( structure.first );
1161 assert( typeIt != m_types.end() );
1162 checkForError(
1163 !typeIt->second.referencedIn.empty(), structure.second.xmlLine, "structure <" + structure.first + "> not listed in any feature or extension" );
1164
1165 // check for existence of all structs that are extended by this struct
1166 for ( auto const & extend : structure.second.structExtends )
1167 {
1168 checkForError( ( m_structures.find( extend ) != m_structures.end() ) || ( m_structureAliases.find( extend ) != m_structureAliases.end() ),
1169 structure.second.xmlLine,
1170 "struct <" + structure.first + "> extends unknown <" + extend + ">" );
1171 }
1172
1173 // checks on the members of a struct
1174 checkStructMemberCorrectness( structure.first, structure.second.members, sTypeValues );
1175 }
1176
1177 // enum VkStructureType checks (need to be after structure checks because of sTypeValues gathered there)
1178 auto structureTypeIt = m_enums.find( "VkStructureType" );
1179 assert( structureTypeIt != m_enums.end() );
1180 for ( auto const & enumValue : structureTypeIt->second.values )
1181 {
1182 if ( ( enumValue.name == "VK_STRUCTURE_TYPE_LOADER_INSTANCE_CREATE_INFO" ) || ( enumValue.name == "VK_STRUCTURE_TYPE_LOADER_DEVICE_CREATE_INFO" ) )
1183 {
1184 checkForError(
1185 sTypeValues.find( enumValue.name ) == sTypeValues.end(), enumValue.xmlLine, "Reserved VkStructureType enum value <" + enumValue.name + "> is used" );
1186 }
1187 else
1188 {
1189 checkForError( sTypeValues.erase( enumValue.name ) == 1, enumValue.xmlLine, "VkStructureType enum value <" + enumValue.name + "> never used" );
1190 }
1191 }
1192 assert( sTypeValues.empty() );
1193 }
1194
checkStructMemberCorrectness(std::string const & structureName,std::vector<MemberData> const & members,std::set<std::string> & sTypeValues) const1195 void VulkanHppGenerator::checkStructMemberCorrectness( std::string const & structureName,
1196 std::vector<MemberData> const & members,
1197 std::set<std::string> & sTypeValues ) const
1198 {
1199 for ( auto const & member : members )
1200 {
1201 // check that all member types are required in some feature or extension
1202 if ( member.type.type.starts_with( "Vk" ) )
1203 {
1204 auto typeIt = m_types.find( member.type.type );
1205 assert( typeIt != m_types.end() );
1206 checkForError( !typeIt->second.referencedIn.empty(),
1207 member.xmlLine,
1208 "struct member type <" + member.type.type + "> used in struct <" + structureName + "> is never listed for any feature or extension" );
1209 }
1210
1211 // if a member specifies a selector, that member is a union and the selector is an enum
1212 // check that there's a 1-1 connection between the specified selections and the values of that enum
1213 if ( !member.selector.empty() )
1214 {
1215 auto selectorIt = findStructMemberIt( member.selector, members );
1216 assert( selectorIt != members.end() );
1217 auto selectorEnumIt = m_enums.find( selectorIt->type.type );
1218 assert( selectorEnumIt != m_enums.end() );
1219 auto unionIt = m_structures.find( member.type.type );
1220 assert( ( unionIt != m_structures.end() ) && unionIt->second.isUnion );
1221 for ( auto const & unionMember : unionIt->second.members )
1222 {
1223 // check that each union member has a selection, that is a value of the seleting enum
1224 assert( !unionMember.selection.empty() );
1225 for ( auto const & selection : unionMember.selection )
1226 {
1227 checkForError( std::find_if( selectorEnumIt->second.values.begin(),
1228 selectorEnumIt->second.values.end(),
1229 [&selection]( EnumValueData const & evd ) { return evd.name == selection; } ) != selectorEnumIt->second.values.end(),
1230 unionMember.xmlLine,
1231 "union member <" + unionMember.name + "> uses selection <" + selection + "> that is not part of the selector type <" +
1232 selectorIt->type.type + ">" );
1233 }
1234 }
1235 }
1236
1237 // check that each member type is known
1238 checkForError( m_types.find( member.type.type ) != m_types.end(), member.xmlLine, "struct member uses unknown type <" + member.type.type + ">" );
1239
1240 // check that any used constant is a known constant
1241 if ( !member.usedConstant.empty() )
1242 {
1243 checkForError( m_constants.find( member.usedConstant ) != m_constants.end(),
1244 member.xmlLine,
1245 "struct member array size uses unknown constant <" + member.usedConstant + ">" );
1246 }
1247
1248 // checks if a value is specified
1249 if ( !member.value.empty() )
1250 {
1251 auto enumIt = m_enums.find( member.type.type );
1252 if ( enumIt != m_enums.end() )
1253 {
1254 // check that the value exists in the specified enum
1255 checkForError( std::find_if( enumIt->second.values.begin(),
1256 enumIt->second.values.end(),
1257 [&member]( auto const & evd ) { return member.value == evd.name; } ) != enumIt->second.values.end(),
1258 member.xmlLine,
1259 "value <" + member.value + "> for member <" + member.name + "> in structure <" + structureName + "> of enum type <" + member.type.type +
1260 "> not listed" );
1261 // special handling for sType: no value should appear more than once
1262 if ( member.name == "sType" )
1263 {
1264 checkForError( sTypeValues.insert( member.value ).second, member.xmlLine, "sType value <" + member.value + "> has been used before" );
1265 }
1266 }
1267 else if ( member.type.type == "uint32_t" )
1268 {
1269 // check that a value for a uint32_t is all digits
1270 checkForError( member.value.find_first_not_of( "0123456789" ) == std::string::npos,
1271 member.xmlLine,
1272 "value <" + member.value + "> for member <" + member.name + "> in structure <" + structureName + "> of type <" + member.type.type +
1273 "> is not a number" );
1274 }
1275 else
1276 {
1277 // don't know the type of the value -> error out
1278 checkForError( false,
1279 member.xmlLine,
1280 "member <" + member.name + "> in structure <" + structureName + "> holds value <" + member.value + "> for an unhandled type <" +
1281 member.type.type + ">" );
1282 }
1283 }
1284 }
1285 }
1286
combineDataTypes(std::map<size_t,VectorParamData> const & vectorParams,std::vector<size_t> const & returnParams,bool enumerating,std::vector<std::string> const & dataTypes,CommandFlavourFlags flavourFlags,bool raii) const1287 std::string VulkanHppGenerator::combineDataTypes( std::map<size_t, VectorParamData> const & vectorParams,
1288 std::vector<size_t> const & returnParams,
1289 bool enumerating,
1290 std::vector<std::string> const & dataTypes,
1291 CommandFlavourFlags flavourFlags,
1292 bool raii ) const
1293 {
1294 assert( dataTypes.size() == returnParams.size() );
1295
1296 std::vector<std::string> modifiedDataTypes( dataTypes.size() );
1297 for ( size_t i = 0; i < returnParams.size(); ++i )
1298 {
1299 auto vectorParamIt = vectorParams.find( returnParams[i] );
1300 modifiedDataTypes[i] = ( vectorParamIt == vectorParams.end() || ( flavourFlags & CommandFlavourFlagBits::singular ) )
1301 ? dataTypes[i]
1302 : ( "std::vector<" + dataTypes[i] +
1303 ( raii || ( flavourFlags & CommandFlavourFlagBits::unique )
1304 ? ">"
1305 : ( ", " + startUpperCase( stripPrefix( dataTypes[i], "VULKAN_HPP_NAMESPACE::" ) ) + "Allocator>" ) ) );
1306 }
1307
1308 std::string combinedType;
1309 switch ( modifiedDataTypes.size() )
1310 {
1311 case 0: combinedType = "void"; break;
1312 case 1: combinedType = modifiedDataTypes[0]; break;
1313 case 2:
1314 assert( !enumerating || ( ( vectorParams.find( returnParams[1] ) != vectorParams.end() ) &&
1315 ( vectorParams.find( returnParams[1] )->second.lenParam == returnParams[0] ) ) );
1316 combinedType = enumerating ? modifiedDataTypes[1] : ( "std::pair<" + modifiedDataTypes[0] + ", " + modifiedDataTypes[1] + ">" );
1317 break;
1318 case 3:
1319 assert( enumerating && ( vectorParams.size() == 2 ) && ( vectorParams.begin()->first == returnParams[1] ) &&
1320 ( vectorParams.begin()->second.lenParam == returnParams[0] ) && ( std::next( vectorParams.begin() )->first == returnParams[2] ) &&
1321 ( std::next( vectorParams.begin() )->second.lenParam == returnParams[0] ) );
1322 combinedType = "std::pair<" + modifiedDataTypes[1] + ", " + modifiedDataTypes[2] + ">";
1323 break;
1324 default: assert( false ); break;
1325 }
1326 return combinedType;
1327 }
1328
containsArray(std::string const & type) const1329 bool VulkanHppGenerator::containsArray( std::string const & type ) const
1330 {
1331 // a simple recursive check if a type is or contains an array
1332 auto structureIt = m_structures.find( type );
1333 bool found = false;
1334 if ( structureIt != m_structures.end() )
1335 {
1336 for ( auto memberIt = structureIt->second.members.begin(); memberIt != structureIt->second.members.end() && !found; ++memberIt )
1337 {
1338 found = !memberIt->arraySizes.empty() || containsArray( memberIt->type.type );
1339 }
1340 }
1341 return found;
1342 }
1343
containsFuncPointer(std::string const & type) const1344 bool VulkanHppGenerator::containsFuncPointer( std::string const & type ) const
1345 {
1346 // a simple recursive check if a type contains a funcpointer
1347 auto structureIt = m_structures.find( type );
1348 bool found = false;
1349 if ( structureIt != m_structures.end() )
1350 {
1351 for ( auto memberIt = structureIt->second.members.begin(); memberIt != structureIt->second.members.end() && !found; ++memberIt )
1352 {
1353 found = ( m_funcPointers.find( memberIt->type.type ) != m_funcPointers.end() ) ||
1354 ( ( memberIt->type.type != type ) && containsFuncPointer( memberIt->type.type ) );
1355 }
1356 }
1357 return found;
1358 }
1359
containsFloatingPoints(std::vector<MemberData> const & members) const1360 bool VulkanHppGenerator::containsFloatingPoints( std::vector<MemberData> const & members ) const
1361 {
1362 for ( auto const & m : members )
1363 {
1364 if ( ( ( m.type.type == "float" ) || ( m.type.type == "double" ) ) && m.type.isValue() )
1365 {
1366 return true;
1367 }
1368 }
1369 return false;
1370 }
1371
containsUnion(std::string const & type) const1372 bool VulkanHppGenerator::containsUnion( std::string const & type ) const
1373 {
1374 // a simple recursive check if a type is or contains a union
1375 auto structureIt = m_structures.find( type );
1376 bool found = false;
1377 if ( structureIt != m_structures.end() )
1378 {
1379 found = structureIt->second.isUnion;
1380 for ( auto memberIt = structureIt->second.members.begin(); memberIt != structureIt->second.members.end() && !found; ++memberIt )
1381 {
1382 found = memberIt->type.isValue() && containsUnion( memberIt->type.type );
1383 }
1384 }
1385 return found;
1386 }
1387
determineConstPointerParams(std::vector<ParamData> const & params) const1388 std::vector<size_t> VulkanHppGenerator::determineConstPointerParams( std::vector<ParamData> const & params ) const
1389 {
1390 std::vector<size_t> constPointerParams;
1391
1392 for ( size_t i = 0; i < params.size(); i++ )
1393 {
1394 // very special handling for some types, which come in as non-const pointers, but are meant as const-pointers
1395 if ( params[i].type.isConstPointer() ||
1396 ( params[i].type.isNonConstPointer() && ( specialPointerTypes.find( params[i].type.type ) != specialPointerTypes.end() ) ) )
1397 {
1398 constPointerParams.push_back( i );
1399 }
1400 }
1401 return constPointerParams;
1402 }
1403
determineDataTypes(std::vector<VulkanHppGenerator::ParamData> const & params,std::map<size_t,VectorParamData> const & vectorParams,std::vector<size_t> const & returnParams,std::set<size_t> const & templatedParams) const1404 std::vector<std::string> VulkanHppGenerator::determineDataTypes( std::vector<VulkanHppGenerator::ParamData> const & params,
1405 std::map<size_t, VectorParamData> const & vectorParams,
1406 std::vector<size_t> const & returnParams,
1407 std::set<size_t> const & templatedParams ) const
1408 {
1409 std::vector<std::string> dataTypes;
1410 for ( auto rp : returnParams )
1411 {
1412 if ( templatedParams.find( rp ) != templatedParams.end() )
1413 {
1414 auto vectorParamIt = vectorParams.find( rp );
1415 if ( ( vectorParamIt != vectorParams.end() ) && ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->first ) != returnParams.end() ) &&
1416 ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->second.lenParam ) != returnParams.end() ) )
1417 {
1418 dataTypes.push_back( "uint8_t" );
1419 }
1420 else
1421 {
1422 dataTypes.push_back( ( stripPrefix( params[rp].name, "p" ) + "Type" ) );
1423 }
1424 }
1425 else
1426 {
1427 dataTypes.push_back( trimEnd( stripPostfix( params[rp].type.compose( "VULKAN_HPP_NAMESPACE" ), "*" ) ) );
1428 }
1429 }
1430 return dataTypes;
1431 }
1432
determineDefaultStartIndex(std::vector<ParamData> const & params,std::set<size_t> const & skippedParams) const1433 size_t VulkanHppGenerator::determineDefaultStartIndex( std::vector<ParamData> const & params, std::set<size_t> const & skippedParams ) const
1434 {
1435 // determine the index where the arguments start to have defaults
1436 size_t defaultStartIndex = INVALID_INDEX;
1437 for ( int i = static_cast<int>( params.size() ) - 1; ( 0 <= i ) && ( params[i].optional || ( skippedParams.find( i ) != skippedParams.end() ) ); --i )
1438 {
1439 defaultStartIndex = i;
1440 }
1441 return defaultStartIndex;
1442 }
1443
determineEnumeration(std::map<size_t,VectorParamData> const & vectorParams,std::vector<size_t> const & returnParams) const1444 bool VulkanHppGenerator::determineEnumeration( std::map<size_t, VectorParamData> const & vectorParams, std::vector<size_t> const & returnParams ) const
1445 {
1446 // a command is considered to be enumerating some data, if for at least one vectorParam both, the data and the counter, are returnParams
1447 return std::find_if( vectorParams.begin(),
1448 vectorParams.end(),
1449 [&returnParams]( auto const & vp )
1450 {
1451 return std::find( returnParams.begin(), returnParams.end(), vp.first ) != returnParams.end() &&
1452 std::find( returnParams.begin(), returnParams.end(), vp.second.lenParam ) != returnParams.end();
1453 } ) != vectorParams.end();
1454 }
1455
determineInitialSkipCount(std::string const & command) const1456 size_t VulkanHppGenerator::determineInitialSkipCount( std::string const & command ) const
1457 {
1458 // determine the number of arguments to skip for a function
1459 // -> 0: the command is not bound to an instance or a device (the corresponding handle has no name)
1460 // -> 1: the command bound to an instance or a device (the corresponding handle has a name)
1461 // -> 2: the command has been moved to a second handle
1462 auto commandIt = m_commands.find( command );
1463 assert( commandIt != m_commands.end() );
1464 auto handleIt = m_handles.find( commandIt->second.handle );
1465 assert( handleIt != m_handles.end() );
1466 if ( handleIt->second.commands.find( command ) == handleIt->second.commands.end() )
1467 {
1468 assert( 1 < commandIt->second.params.size() );
1469 assert( m_handles.find( commandIt->second.params[1].type.type ) != m_handles.end() );
1470 return 2;
1471 }
1472 else
1473 {
1474 return handleIt->first.empty() ? 0 : 1;
1475 }
1476 }
1477
determineReturnParams(std::vector<ParamData> const & params) const1478 std::vector<size_t> VulkanHppGenerator::determineReturnParams( std::vector<ParamData> const & params ) const
1479 {
1480 std::vector<size_t> nonConstPointerParamIndices;
1481
1482 for ( size_t i = 0; i < params.size(); i++ )
1483 {
1484 // very special handling of parameters of some types, which always come as a non-const pointer but are not meant
1485 // to be a potential return value!
1486 if ( params[i].type.isNonConstPointer() && ( specialPointerTypes.find( params[i].type.type ) == specialPointerTypes.end() ) )
1487 {
1488 nonConstPointerParamIndices.push_back( i );
1489 }
1490 }
1491 return nonConstPointerParamIndices;
1492 }
1493
1494 std::vector<std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator>
determineRAIIHandleConstructors(std::string const & handleType,std::map<std::string,CommandData>::const_iterator destructorIt) const1495 VulkanHppGenerator::determineRAIIHandleConstructors( std::string const & handleType, std::map<std::string, CommandData>::const_iterator destructorIt ) const
1496 {
1497 std::vector<std::map<std::string, CommandData>::const_iterator> constructorIts;
1498 auto isConstructorCandidate = [&handleType]( std::pair<std::string, CommandData> const & cd )
1499 {
1500 return std::find_if( cd.second.params.begin(),
1501 cd.second.params.end(),
1502 [&handleType]( ParamData const & pd )
1503 { return ( pd.type.type == handleType ) && pd.type.isNonConstPointer(); } ) != cd.second.params.end();
1504 };
1505 for ( auto commandIt = m_commands.begin(); commandIt != m_commands.end(); )
1506 {
1507 // find the commands that get a non-const pointer to the handleType, that is, return a handle type
1508 commandIt = std::find_if( commandIt, m_commands.end(), isConstructorCandidate );
1509 if ( commandIt != m_commands.end() )
1510 {
1511 // only commands that provide all information needed for the destructor can be considered a constructor!
1512 bool valid = true;
1513 if ( destructorIt != m_commands.end() )
1514 {
1515 // get the destructors parameter to the handleType
1516 auto desctructorHandleParamIt = std::find_if( destructorIt->second.params.begin(),
1517 destructorIt->second.params.end(),
1518 [&handleType]( ParamData const & pd ) { return pd.type.type == handleType; } );
1519 assert( desctructorHandleParamIt != destructorIt->second.params.end() );
1520
1521 // lambda to check if a destructor parameter is a parameter of the constructor candidate
1522 // (or it's just the len parameter, which is not needed for the constructor)
1523 auto isConstructorCandidateParam = [&desctructorHandleParamIt, &commandIt, this]( ParamData const & destructorParam )
1524 {
1525 // check if the destructor param type equals this param type, or, if this param type is a struct, is part of
1526 // that struct
1527 auto isDestructorParamType = [&destructorParam, this]( ParamData const & pd )
1528 {
1529 if ( pd.type.type != destructorParam.type.type )
1530 {
1531 // check if the destructor param type equals a structure member type
1532 auto structureIt = m_structures.find( pd.type.type );
1533 return ( structureIt != m_structures.end() ) &&
1534 ( findStructMemberItByType( destructorParam.type.type, structureIt->second.members ) != structureIt->second.members.end() );
1535 }
1536 return true;
1537 };
1538
1539 return ( destructorParam.name == desctructorHandleParamIt->len ) ||
1540 ( std::find_if( commandIt->second.params.begin(), commandIt->second.params.end(), isDestructorParamType ) != commandIt->second.params.end() );
1541 };
1542
1543 // the constructor candidate is valid, if none of the (relevant) destructor parameters is missing in the
1544 // constructor candidate params
1545 valid = ( std::find_if_not( destructorIt->second.params.begin(), destructorIt->second.params.end(), isConstructorCandidateParam ) ==
1546 destructorIt->second.params.end() );
1547 }
1548 if ( valid )
1549 {
1550 // filter out alias functions
1551 if ( commandIt->second.alias.empty() )
1552 {
1553 constructorIts.push_back( commandIt );
1554 }
1555 }
1556 ++commandIt;
1557 }
1558 }
1559 assert( !constructorIts.empty() );
1560 return constructorIts;
1561 }
1562
determineRAIIHandleDestructor(std::string const & handleType) const1563 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator VulkanHppGenerator::determineRAIIHandleDestructor( std::string const & handleType ) const
1564 {
1565 std::string type = stripPrefix( handleType, "Vk" );
1566 auto destructorIt = m_commands.find( "vkDestroy" + type );
1567 if ( destructorIt == m_commands.end() )
1568 {
1569 destructorIt = m_commands.find( "vkFree" + type + "s" );
1570 if ( destructorIt == m_commands.end() )
1571 {
1572 destructorIt = m_commands.find( "vkRelease" + type );
1573 if ( destructorIt == m_commands.end() )
1574 {
1575 if ( handleType == "VkDeviceMemory" )
1576 {
1577 // special handling for vkDeviceMemory
1578 destructorIt = m_commands.find( "vkFreeMemory" );
1579 assert( destructorIt != m_commands.end() );
1580 }
1581 else if ( handleType == "VkDisplayKHR" )
1582 {
1583 // special handling for VkDisplayKHR
1584 destructorIt = m_commands.find( "vkReleaseDisplayEXT" );
1585 assert( destructorIt != m_commands.end() );
1586 }
1587 else
1588 {
1589 assert( ( handleType == "VkDisplayModeKHR" ) || ( handleType == "VkPhysicalDevice" ) || ( handleType == "VkQueue" ) );
1590 }
1591 }
1592 }
1593 }
1594 return destructorIt;
1595 }
1596
determineSingularParams(size_t returnParam,std::map<size_t,VectorParamData> const & vectorParams) const1597 std::set<size_t> VulkanHppGenerator::determineSingularParams( size_t returnParam, std::map<size_t, VectorParamData> const & vectorParams ) const
1598 {
1599 auto returnVectorIt = vectorParams.find( returnParam );
1600 assert( returnVectorIt != vectorParams.end() );
1601 std::set<size_t> singularParams;
1602 singularParams.insert( returnVectorIt->second.lenParam );
1603 for ( auto const & vpi : vectorParams )
1604 {
1605 if ( vpi.second.lenParam == returnVectorIt->second.lenParam )
1606 {
1607 singularParams.insert( vpi.first );
1608 }
1609 }
1610 return singularParams;
1611 }
1612
determineSkippedParams(std::vector<ParamData> const & params,size_t initialSkipCount,std::map<size_t,VectorParamData> const & vectorParams,std::vector<size_t> const & returnParams,bool singular) const1613 std::set<size_t> VulkanHppGenerator::determineSkippedParams( std::vector<ParamData> const & params,
1614 size_t initialSkipCount,
1615 std::map<size_t, VectorParamData> const & vectorParams,
1616 std::vector<size_t> const & returnParams,
1617 bool singular ) const
1618 {
1619 // skip the initial skips (get fed by the object)
1620 assert( initialSkipCount <= params.size() );
1621 std::set<size_t> skippedParams;
1622 for ( size_t i = 0; i < initialSkipCount; ++i )
1623 {
1624 skippedParams.insert( i );
1625 }
1626
1627 // skip the size parameters (get derived from an array), and a stride parameter
1628 for ( auto const & vpi : vectorParams )
1629 {
1630 assert( !params[vpi.first].len.empty() );
1631 if ( ( ( std::find_if( returnParams.begin(), returnParams.end(), [&vpi]( size_t rpi ) { return vpi.first == rpi; } ) == returnParams.end() ) &&
1632 isParam( params[vpi.first].len, params ) ) ||
1633 ( singular && params[vpi.second.lenParam].type.isValue() ) )
1634 {
1635 skippedParams.insert( vpi.second.lenParam );
1636 }
1637 if ( vpi.second.strideParam != INVALID_INDEX )
1638 {
1639 skippedParams.insert( vpi.second.strideParam );
1640 }
1641 }
1642
1643 // skip the return parameters (get resolved by local variables to be returned)
1644 skippedParams.insert( returnParams.begin(), returnParams.end() );
1645
1646 return skippedParams;
1647 }
1648
determineSubStruct(std::pair<std::string,StructureData> const & structure) const1649 std::string VulkanHppGenerator::determineSubStruct( std::pair<std::string, StructureData> const & structure ) const
1650 {
1651 if ( structure.second.members.front().name != "sType" )
1652 {
1653 // check if sd is a substruct of structure
1654 auto isSubStruct = [&structure]( std::pair<std::string, StructureData> const & sd )
1655 {
1656 // member-by-member comparison of type and name
1657 auto memberIt = structure.second.members.begin();
1658 auto isMember = [&memberIt]( MemberData const & md )
1659 {
1660 if ( ( md.type == memberIt->type ) && ( md.name == memberIt->name ) )
1661 {
1662 ++memberIt;
1663 return true;
1664 }
1665 return false;
1666 };
1667
1668 return ( sd.second.members.size() < structure.second.members.size() ) &&
1669 ( std::find_if_not( sd.second.members.begin(), sd.second.members.end(), isMember ) == sd.second.members.end() );
1670 };
1671
1672 // look for a struct in m_structures that starts identically to structure
1673 auto structIt = std::find_if( m_structures.begin(), m_structures.end(), isSubStruct );
1674 return ( structIt == m_structures.end() ) ? "" : structIt->first;
1675 }
1676 return "";
1677 }
1678
determineVectorParams(std::vector<ParamData> const & params) const1679 std::map<size_t, VulkanHppGenerator::VectorParamData> VulkanHppGenerator::determineVectorParams( std::vector<ParamData> const & params ) const
1680 {
1681 std::map<size_t, VectorParamData> vectorParams;
1682
1683 // look for the parameters whose len equals the name of an other parameter
1684 for ( size_t i = 0; i < params.size(); i++ )
1685 {
1686 if ( !params[i].len.empty() && ( params[i].len != "null-terminated" ) )
1687 {
1688 VectorParamData & vpd = vectorParams[i];
1689
1690 std::string len;
1691 if ( altLens.find( params[i].len ) != altLens.end() )
1692 {
1693 checkForError( params[i].len == "(samples + 31) / 32", params[i].xmlLine, "unknown command parameter len <" + params[i].len + ">" );
1694 len = "samples";
1695 }
1696 else
1697 {
1698 len = params[i].len;
1699 }
1700 auto lenIt =
1701 std::find_if( params.begin(), params.end(), [&len, this]( auto const & pd ) { return ( len == pd.name ) || isLenByStructMember( len, pd ); } );
1702 assert( lenIt != params.end() );
1703 vpd.lenParam = std::distance( params.begin(), lenIt );
1704 if ( !params[i].stride.empty() )
1705 {
1706 std::string const & stride = params[i].stride;
1707 auto strideIt = std::find_if( params.begin(), params.end(), [&stride]( auto const & pd ) { return stride == pd.name; } );
1708 assert( strideIt != params.end() );
1709 vpd.strideParam = std::distance( params.begin(), strideIt );
1710 }
1711 }
1712 }
1713 return vectorParams;
1714 }
1715
determineVoidPointerParams(std::vector<ParamData> const & params) const1716 std::set<size_t> VulkanHppGenerator::determineVoidPointerParams( std::vector<ParamData> const & params ) const
1717 {
1718 std::set<size_t> voidPointerParams;
1719
1720 for ( size_t i = 0; i < params.size(); i++ )
1721 {
1722 if ( !params[i].type.isValue() && ( params[i].type.type == "void" ) && ( params[i].type.postfix != "**" ) )
1723 {
1724 voidPointerParams.insert( i );
1725 }
1726 }
1727 return voidPointerParams;
1728 }
1729
distributeSecondLevelCommands(std::set<std::string> const & specialFunctions)1730 void VulkanHppGenerator::distributeSecondLevelCommands( std::set<std::string> const & specialFunctions )
1731 {
1732 // distribute commands from instance/device to second-level handles, like Queue, Event,... for RAII handles
1733 for ( auto & handle : m_handles )
1734 {
1735 if ( !handle.first.empty() )
1736 {
1737 for ( auto command = handle.second.commands.begin(); command != handle.second.commands.end(); )
1738 {
1739 bool foundCommand = false;
1740 if ( specialFunctions.find( *command ) == specialFunctions.end() )
1741 {
1742 auto commandIt = m_commands.find( *command );
1743 assert( commandIt != m_commands.end() );
1744 assert( commandIt->second.params.front().type.type == handle.first );
1745 if ( ( 1 < commandIt->second.params.size() ) && ( isHandleType( commandIt->second.params[1].type.type ) ) && !commandIt->second.params[1].optional )
1746 {
1747 auto handleIt = m_handles.find( commandIt->second.params[1].type.type );
1748 assert( handleIt != m_handles.end() );
1749 // filter out functions seem to fit due to taking handles as first and second argument, but the first argument is not the
1750 // type to create the second one, and so it's unknown to the raii handle!
1751 assert( !handleIt->second.constructorIts.empty() );
1752 if ( ( *handleIt->second.constructorIts.begin() )->second.handle == handle.first )
1753 {
1754 assert( std::find_if( handleIt->second.constructorIts.begin(),
1755 handleIt->second.constructorIts.end(),
1756 [&handle]( auto const & constructorIt )
1757 { return constructorIt->second.handle != handle.first; } ) == handleIt->second.constructorIts.end() );
1758 handleIt->second.secondLevelCommands.insert( *command );
1759 command = handle.second.commands.erase( command );
1760 foundCommand = true;
1761 }
1762 }
1763 }
1764 if ( !foundCommand )
1765 {
1766 ++command;
1767 }
1768 }
1769 }
1770 }
1771 }
1772
findBaseName(std::string aliasName,std::map<std::string,EnumAliasData> const & aliases) const1773 std::string VulkanHppGenerator::findBaseName( std::string aliasName, std::map<std::string, EnumAliasData> const & aliases ) const
1774 {
1775 std::string baseName = aliasName;
1776 auto aliasIt = aliases.find( baseName );
1777 while ( aliasIt != aliases.end() )
1778 {
1779 baseName = aliasIt->second.name;
1780 aliasIt = aliases.find( baseName );
1781 }
1782 return baseName;
1783 }
1784
findStructMemberIt(std::string const & name,std::vector<MemberData> const & memberData) const1785 std::vector<VulkanHppGenerator::MemberData>::const_iterator VulkanHppGenerator::findStructMemberIt( std::string const & name,
1786 std::vector<MemberData> const & memberData ) const
1787 {
1788 return std::find_if( memberData.begin(), memberData.end(), [&name]( MemberData const & md ) { return md.name == name; } );
1789 }
1790
findStructMemberItByType(std::string const & type,std::vector<MemberData> const & memberData) const1791 std::vector<VulkanHppGenerator::MemberData>::const_iterator VulkanHppGenerator::findStructMemberItByType( std::string const & type,
1792 std::vector<MemberData> const & memberData ) const
1793 {
1794 return std::find_if( memberData.begin(), memberData.end(), [&type]( MemberData const & md ) { return md.type.type == type; } );
1795 }
1796
generateAllocatorTemplates(std::vector<size_t> const & returnParams,std::vector<std::string> const & returnDataTypes,std::map<size_t,VectorParamData> const & vectorParams,CommandFlavourFlags flavourFlags,bool definition) const1797 std::pair<std::string, std::string> VulkanHppGenerator::generateAllocatorTemplates( std::vector<size_t> const & returnParams,
1798 std::vector<std::string> const & returnDataTypes,
1799 std::map<size_t, VectorParamData> const & vectorParams,
1800 CommandFlavourFlags flavourFlags,
1801 bool definition ) const
1802 {
1803 bool chained = flavourFlags & CommandFlavourFlagBits::chained;
1804 bool singular = flavourFlags & CommandFlavourFlagBits::singular;
1805 bool unique = flavourFlags & CommandFlavourFlagBits::unique;
1806
1807 assert( returnParams.size() == returnDataTypes.size() );
1808 std::string allocatorTemplates;
1809 if ( !singular )
1810 {
1811 for ( size_t i = 0; i < returnParams.size(); i++ )
1812 {
1813 if ( vectorParams.find( returnParams[i] ) != vectorParams.end() )
1814 {
1815 if ( chained )
1816 {
1817 allocatorTemplates += "typename StructureChainAllocator";
1818 if ( !definition )
1819 {
1820 allocatorTemplates += " = std::allocator<StructureChain>";
1821 }
1822 }
1823 else
1824 {
1825 allocatorTemplates += "typename " + startUpperCase( stripPrefix( returnDataTypes[i], "VULKAN_HPP_NAMESPACE::" ) ) + "Allocator";
1826 if ( !definition )
1827 {
1828 allocatorTemplates += " = std::allocator<" + ( unique ? ( "UniqueHandle<" + returnDataTypes[i] + ", Dispatch>" ) : returnDataTypes[i] ) + ">";
1829 }
1830 }
1831 allocatorTemplates += ", ";
1832 }
1833 }
1834 }
1835 std::string uniqueHandleAllocatorTemplates;
1836 if ( unique && !allocatorTemplates.empty() )
1837 {
1838 uniqueHandleAllocatorTemplates = ", " + stripPostfix( allocatorTemplates, ", " );
1839 allocatorTemplates.clear();
1840 }
1841 return std::make_pair( allocatorTemplates, uniqueHandleAllocatorTemplates );
1842 }
1843
generateArgumentListEnhanced(std::vector<ParamData> const & params,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,std::set<size_t> const & skippedParams,std::set<size_t> const & singularParams,std::set<size_t> const & templatedParams,bool definition,CommandFlavourFlags flavourFlags,bool withDispatcher) const1844 std::string VulkanHppGenerator::generateArgumentListEnhanced( std::vector<ParamData> const & params,
1845 std::vector<size_t> const & returnParams,
1846 std::map<size_t, VectorParamData> const & vectorParams,
1847 std::set<size_t> const & skippedParams,
1848 std::set<size_t> const & singularParams,
1849 std::set<size_t> const & templatedParams,
1850 bool definition,
1851 CommandFlavourFlags flavourFlags,
1852 bool withDispatcher ) const
1853 {
1854 bool withAllocators = flavourFlags & CommandFlavourFlagBits::withAllocator;
1855
1856 size_t defaultStartIndex = withAllocators ? ~0 : determineDefaultStartIndex( params, skippedParams );
1857
1858 std::string argumentList;
1859 bool encounteredArgument = false;
1860 for ( size_t i = 0; i < params.size(); ++i )
1861 {
1862 if ( skippedParams.find( i ) == skippedParams.end() )
1863 {
1864 if ( encounteredArgument )
1865 {
1866 argumentList += ", ";
1867 }
1868 bool hasDefaultAssignment = false;
1869
1870 std::string composedType = params[i].type.compose( "VULKAN_HPP_NAMESPACE" );
1871
1872 if ( singularParams.find( i ) != singularParams.end() )
1873 {
1874 assert( !params[i].optional );
1875 assert( params[i].type.isConstPointer() && !params[i].len.empty() && !isLenByStructMember( params[i].len, params ) &&
1876 params[i].type.type.starts_with( "Vk" ) );
1877 assert( !isHandleType( params[i].type.type ) );
1878 assert( composedType.ends_with( " *" ) );
1879 argumentList += stripPostfix( composedType, " *" ) + " & " + stripPluralS( startLowerCase( stripPrefix( params[i].name, "p" ) ), m_tags );
1880 }
1881 else if ( params[i].type.isConstPointer() )
1882 {
1883 assert( composedType.ends_with( " *" ) );
1884 std::string name = startLowerCase( stripPrefix( params[i].name, "p" ) );
1885 if ( params[i].len.empty() )
1886 {
1887 assert( withDispatcher || !isHandleType( params[i].type.type ) );
1888 assert( !params[i].type.prefix.empty() && ( params[i].type.postfix == "*" ) );
1889 assert( params[i].arraySizes.empty() );
1890 if ( params[i].type.type == "void" )
1891 {
1892 argumentList += ( templatedParams.find( i ) == templatedParams.end() ) ? ( composedType + " " + params[i].name )
1893 : ( stripPrefix( params[i].name, "p" ) + "Type const & " + name );
1894 }
1895 else if ( params[i].optional )
1896 {
1897 argumentList += "Optional<" + stripPostfix( composedType, " *" ) + "> " + name +
1898 ( ( definition || withAllocators ) ? "" : " VULKAN_HPP_DEFAULT_ARGUMENT_NULLPTR_ASSIGNMENT" );
1899 hasDefaultAssignment = true;
1900 }
1901 else
1902 {
1903 argumentList += stripPostfix( composedType, " *" ) + " & " + name;
1904 }
1905 }
1906 else
1907 {
1908 // a const-pointer with a non-empty len is either null-terminated (aka a string) or represented by an
1909 // ArrayProxy
1910 assert( params[i].arraySizes.empty() );
1911 if ( params[i].len == "null-terminated" )
1912 {
1913 assert( params[i].type.type == "char" );
1914 if ( params[i].optional )
1915 {
1916 argumentList +=
1917 "Optional<const std::string> " + name + ( ( definition || withAllocators ) ? "" : " VULKAN_HPP_DEFAULT_ARGUMENT_NULLPTR_ASSIGNMENT" );
1918 hasDefaultAssignment = true;
1919 }
1920 else
1921 {
1922 argumentList += "const std::string & " + name;
1923 }
1924 }
1925 else
1926 {
1927 // an ArrayProxy also covers no data, so any optional flag can be ignored here
1928 std::string type = stripPostfix( composedType, " *" );
1929 size_t pos = type.find( "void" );
1930 if ( pos != std::string::npos )
1931 {
1932 type.replace( pos, 4, stripPrefix( params[i].name, "p" ) + "Type" );
1933 }
1934 argumentList +=
1935 std::string( "VULKAN_HPP_NAMESPACE::" ) + ( params[i].stride.empty() ? "" : "Strided" ) + "ArrayProxy<" + type + "> const & " + name;
1936 if ( params[i].optional && !definition )
1937 {
1938 assert( params[i].stride.empty() );
1939 argumentList += " VULKAN_HPP_DEFAULT_ARGUMENT_NULLPTR_ASSIGNMENT";
1940 hasDefaultAssignment = true;
1941 }
1942 }
1943 }
1944 }
1945 else if ( params[i].type.isNonConstPointer() )
1946 {
1947 assert( withDispatcher || !isHandleType( params[i].type.type ) );
1948 assert( params[i].len.empty() && !params[i].optional );
1949 assert( composedType.ends_with( " *" ) );
1950 argumentList += stripPostfix( composedType, " *" ) + " & " + params[i].name;
1951 }
1952 else
1953 {
1954 assert( params[i].type.isValue() );
1955 argumentList += composedType + " " + params[i].name + generateCArraySizes( params[i].arraySizes );
1956 }
1957 argumentList += std::string( !definition && ( defaultStartIndex <= i ) && !hasDefaultAssignment ? " VULKAN_HPP_DEFAULT_ARGUMENT_ASSIGNMENT" : "" );
1958 encounteredArgument = true;
1959 }
1960 }
1961 if ( withAllocators )
1962 {
1963 if ( flavourFlags & CommandFlavourFlagBits::chained )
1964 {
1965 if ( encounteredArgument )
1966 {
1967 argumentList += ", ";
1968 }
1969 argumentList += "StructureChainAllocator & structureChainAllocator";
1970 encounteredArgument = true;
1971 }
1972 else
1973 {
1974 for ( auto sp : skippedParams )
1975 {
1976 if ( !params[sp].len.empty() )
1977 {
1978 if ( encounteredArgument )
1979 {
1980 argumentList += ", ";
1981 }
1982 std::string type;
1983 if ( templatedParams.find( sp ) != templatedParams.end() )
1984 {
1985 auto vectorParamIt = vectorParams.find( sp );
1986 if ( ( vectorParamIt != vectorParams.end() ) &&
1987 ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->first ) != returnParams.end() ) &&
1988 ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->second.lenParam ) != returnParams.end() ) )
1989 {
1990 type = "Uint8_t";
1991 }
1992 else
1993 {
1994 type = stripPrefix( params[sp].name, "p" ) + "Type";
1995 }
1996 }
1997 else
1998 {
1999 type = ( params[sp].type.type == "void" ) ? "Uint8_t" : startUpperCase( stripPrefix( params[sp].type.type, "Vk" ) );
2000 }
2001 argumentList += type + "Allocator & " + startLowerCase( type ) + "Allocator";
2002 encounteredArgument = true;
2003 }
2004 }
2005 }
2006 }
2007 if ( withDispatcher )
2008 {
2009 if ( encounteredArgument )
2010 {
2011 argumentList += ", ";
2012 }
2013 argumentList += std::string( "Dispatch const & d" ) + ( definition ? "" : " VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT" );
2014 }
2015 return argumentList;
2016 }
2017
generateArgumentListStandard(std::vector<ParamData> const & params,std::set<size_t> const & skippedParams) const2018 std::string VulkanHppGenerator::generateArgumentListStandard( std::vector<ParamData> const & params, std::set<size_t> const & skippedParams ) const
2019 {
2020 std::string argumentList;
2021 for ( size_t i = 0; i < params.size(); ++i )
2022 {
2023 if ( skippedParams.find( i ) == skippedParams.end() )
2024 {
2025 argumentList += params[i].type.compose( "VULKAN_HPP_NAMESPACE" ) + " " + params[i].name + generateCArraySizes( params[i].arraySizes ) + ", ";
2026 }
2027 }
2028 argumentList += "Dispatch const & d ";
2029 return argumentList;
2030 }
2031
generateArgumentTemplates(std::vector<ParamData> const & params,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,std::set<size_t> const & templatedParams,CommandFlavourFlags flavourFlags,bool raii) const2032 std::string VulkanHppGenerator::generateArgumentTemplates( std::vector<ParamData> const & params,
2033 std::vector<size_t> const & returnParams,
2034 std::map<size_t, VectorParamData> const & vectorParams,
2035 std::set<size_t> const & templatedParams,
2036 CommandFlavourFlags flavourFlags,
2037 bool raii ) const
2038 {
2039 std::string argumentTemplates;
2040 if ( !templatedParams.empty() )
2041 {
2042 assert( !( flavourFlags & CommandFlavourFlagBits::chained ) );
2043 for ( auto t : templatedParams )
2044 {
2045 assert( params[t].name.starts_with( "p" ) );
2046 auto vectorParamIt = vectorParams.find( t );
2047 if ( ( vectorParamIt == vectorParams.end() ) || ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->first ) == returnParams.end() ) ||
2048 ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->second.lenParam ) == returnParams.end() ) )
2049 {
2050 // only templated parameters that are not part of an enumeration are really templated
2051 argumentTemplates += "typename " + stripPrefix( params[t].name, "p" ) + "Type, ";
2052 }
2053 }
2054 }
2055 else if ( flavourFlags & CommandFlavourFlagBits::chained )
2056 {
2057 argumentTemplates = ( returnParams.size() == 1 ) ? "typename X, typename Y, typename... Z, " : "typename StructureChain, ";
2058 }
2059 if ( !argumentTemplates.empty() && raii )
2060 {
2061 argumentTemplates = "template <" + stripPostfix( argumentTemplates, ", " ) + ">";
2062 }
2063 return argumentTemplates;
2064 }
2065
generateBaseTypes() const2066 std::string VulkanHppGenerator::generateBaseTypes() const
2067 {
2068 assert( !m_baseTypes.empty() );
2069 const std::string basetypesTemplate = R"(
2070 //==================
2071 //=== BASE TYPEs ===
2072 //==================
2073
2074 ${basetypes}
2075 )";
2076
2077 std::string basetypes;
2078 for ( auto const & baseType : m_baseTypes )
2079 {
2080 // filter out VkFlags and VkFlags64, as they are mapped to our own Flags class
2081 if ( ( baseType.first != "VkFlags" ) && ( baseType.first != "VkFlags64" ) )
2082 {
2083 basetypes += " using " + stripPrefix( baseType.first, "Vk" ) + " = " + baseType.second.typeInfo.compose( "VULKAN_HPP_NAMESPACE" ) + ";\n";
2084 }
2085 }
2086
2087 return replaceWithMap( basetypesTemplate, { { "basetypes", basetypes } } );
2088 }
2089
generateBitmask(std::map<std::string,BitmaskData>::const_iterator bitmaskIt,std::string const & surroundingProtect) const2090 std::string VulkanHppGenerator::generateBitmask( std::map<std::string, BitmaskData>::const_iterator bitmaskIt, std::string const & surroundingProtect ) const
2091 {
2092 auto bitmaskBitsIt = m_enums.find( bitmaskIt->second.requirements );
2093 assert( bitmaskBitsIt != m_enums.end() );
2094
2095 std::string bitmaskName = stripPrefix( bitmaskIt->first, "Vk" );
2096 std::string enumName = stripPrefix( bitmaskBitsIt->first, "Vk" );
2097 std::string alias = bitmaskIt->second.alias.empty() ? "" : ( " using " + stripPrefix( bitmaskIt->second.alias, "Vk" ) + " = " + bitmaskName + ";\n" );
2098
2099 std::string allFlags;
2100 if ( bitmaskBitsIt->second.values.empty() )
2101 {
2102 allFlags = " {};";
2103 }
2104 else
2105 {
2106 bool encounteredFlag = false;
2107 std::string previousEnter, previousLeave;
2108 for ( auto const & value : bitmaskBitsIt->second.values )
2109 {
2110 // determine the values protect, if any
2111 std::string valueProtect = getProtect( value );
2112
2113 // if the value's protect differs from the surrounding protect, generate protection code
2114 std::string enter, leave;
2115 if ( !valueProtect.empty() && ( valueProtect != surroundingProtect ) )
2116 {
2117 tie( enter, leave ) = generateProtection( valueProtect );
2118 }
2119 std::string valueName = generateEnumValueName( bitmaskBitsIt->first, value.name, true, m_tags );
2120 allFlags +=
2121 ( ( previousEnter != enter ) ? ( "\n" + previousLeave + enter ) : "\n" ) + " " + ( encounteredFlag ? "| " : " " ) + enumName + "::" + valueName;
2122 encounteredFlag = true;
2123 previousEnter = enter;
2124 previousLeave = leave;
2125 }
2126 if ( !previousLeave.empty() )
2127 {
2128 allFlags += "\n" + previousLeave;
2129 }
2130 allFlags += ";";
2131 }
2132
2133 static const std::string bitmaskTemplate = R"(
2134 using ${bitmaskName} = Flags<${enumName}>;
2135 ${alias}
2136
2137 template <> struct FlagTraits<${enumName}>
2138 {
2139 static VULKAN_HPP_CONST_OR_CONSTEXPR bool isBitmask = true;
2140 static VULKAN_HPP_CONST_OR_CONSTEXPR ${bitmaskName} allFlags = ${allFlags}
2141 };
2142 )";
2143
2144 return replaceWithMap( bitmaskTemplate, { { "alias", alias }, { "allFlags", allFlags }, { "bitmaskName", bitmaskName }, { "enumName", enumName } } );
2145 }
2146
generateBitmasksToString() const2147 std::string VulkanHppGenerator::generateBitmasksToString() const
2148 {
2149 const std::string bitmasksToStringTemplate = R"(
2150 //==========================
2151 //=== BITMASKs to_string ===
2152 //==========================
2153
2154 ${bitmasksToString}
2155 )";
2156
2157 std::string bitmasksToString;
2158 std::set<std::string> listedBitmasks;
2159 for ( auto const & feature : m_features )
2160 {
2161 bitmasksToString += generateBitmasksToString( feature.second.requireData, listedBitmasks, feature.first );
2162 }
2163 for ( auto const & extIt : m_extensionsByNumber )
2164 {
2165 bitmasksToString += generateBitmasksToString( extIt.second->second.requireData, listedBitmasks, extIt.second->first );
2166 }
2167
2168 return replaceWithMap( bitmasksToStringTemplate, { { "bitmasksToString", bitmasksToString } } );
2169 }
2170
generateBitmasksToString(std::vector<RequireData> const & requireData,std::set<std::string> & listedBitmasks,std::string const & title) const2171 std::string VulkanHppGenerator::generateBitmasksToString( std::vector<RequireData> const & requireData,
2172 std::set<std::string> & listedBitmasks,
2173 std::string const & title ) const
2174 {
2175 std::string str;
2176 for ( auto const & require : requireData )
2177 {
2178 for ( auto const & type : require.types )
2179 {
2180 auto bitmaskIt = m_bitmasks.find( type );
2181 if ( ( bitmaskIt != m_bitmasks.end() ) && ( listedBitmasks.find( type ) == listedBitmasks.end() ) )
2182 {
2183 listedBitmasks.insert( type );
2184 str += generateBitmaskToString( bitmaskIt );
2185 }
2186 }
2187 }
2188 return addTitleAndProtection( title, str );
2189 }
2190
generateBitmaskToString(std::map<std::string,BitmaskData>::const_iterator bitmaskIt) const2191 std::string VulkanHppGenerator::generateBitmaskToString( std::map<std::string, BitmaskData>::const_iterator bitmaskIt ) const
2192 {
2193 auto bitmaskBitsIt = m_enums.find( bitmaskIt->second.requirements );
2194 assert( bitmaskBitsIt != m_enums.end() );
2195
2196 std::string bitmaskName = stripPrefix( bitmaskIt->first, "Vk" );
2197 std::string enumName = stripPrefix( bitmaskBitsIt->first, "Vk" );
2198
2199 std::string str;
2200 if ( bitmaskBitsIt->second.values.empty() )
2201 {
2202 static std::string bitmaskToStringTemplate = R"(
2203 VULKAN_HPP_INLINE std::string to_string( ${bitmaskName} )
2204 {
2205 return "{}";
2206 }
2207 )";
2208 str += replaceWithMap( bitmaskToStringTemplate, { { "bitmaskName", bitmaskName } } );
2209 }
2210 else
2211 {
2212 static const std::string bitmaskToStringTemplate = R"(
2213 VULKAN_HPP_INLINE std::string to_string( ${bitmaskName} value )
2214 {
2215 if ( !value )
2216 return "{}";
2217
2218 std::string result;
2219 ${toStringChecks}
2220 return "{ " + result.substr( 0, result.size() - 3 ) + " }";
2221 }
2222 )";
2223
2224 std::string toStringChecks;
2225 std::string previousEnter, previousLeave;
2226 for ( auto const & value : bitmaskBitsIt->second.values )
2227 {
2228 auto [enter, leave] = generateProtection( getProtect( value ) );
2229 std::string valueName = generateEnumValueName( bitmaskBitsIt->first, value.name, true, m_tags );
2230 if ( value.singleBit )
2231 {
2232 toStringChecks += ( ( previousEnter != enter ) ? ( previousLeave + enter ) : "" ) + " if ( value & " + enumName + "::" + valueName +
2233 " ) result += \"" + valueName.substr( 1 ) + " | \";\n";
2234 }
2235 previousEnter = enter;
2236 previousLeave = leave;
2237 }
2238 if ( !previousLeave.empty() )
2239 {
2240 assert( previousLeave.ends_with( "\n" ) );
2241 toStringChecks += previousLeave;
2242 previousLeave.resize( previousLeave.size() - strlen( "\n" ) );
2243 }
2244
2245 str += replaceWithMap( bitmaskToStringTemplate, { { "bitmaskName", bitmaskName }, { "toStringChecks", toStringChecks } } );
2246 }
2247
2248 return str;
2249 }
2250
generateCallArgumentsEnhanced(CommandData const & commandData,size_t initialSkipCount,bool nonConstPointerAsNullptr,std::set<size_t> const & singularParams,std::set<size_t> const & templatedParams,bool raiiHandleMemberFunction) const2251 std::string VulkanHppGenerator::generateCallArgumentsEnhanced( CommandData const & commandData,
2252 size_t initialSkipCount,
2253 bool nonConstPointerAsNullptr,
2254 std::set<size_t> const & singularParams,
2255 std::set<size_t> const & templatedParams,
2256 bool raiiHandleMemberFunction ) const
2257 {
2258 assert( initialSkipCount <= commandData.params.size() );
2259 std::string arguments;
2260 bool encounteredArgument = false;
2261 if ( raiiHandleMemberFunction )
2262 {
2263 switch ( initialSkipCount )
2264 {
2265 case 1:
2266 assert( isHandleType( commandData.params[0].type.type ) && commandData.params[0].type.isValue() );
2267 assert( commandData.params[0].arraySizes.empty() && commandData.params[0].len.empty() );
2268 assert( commandData.params[0].type.type == commandData.handle );
2269 arguments = "static_cast<" + commandData.handle + ">( m_" + startLowerCase( stripPrefix( commandData.handle, "Vk" ) ) + " )";
2270 encounteredArgument = true;
2271 break;
2272 case 2:
2273 {
2274 assert( isHandleType( commandData.params[0].type.type ) && commandData.params[0].type.isValue() );
2275 assert( commandData.params[0].arraySizes.empty() && commandData.params[0].len.empty() );
2276 assert( commandData.params[0].type.type == commandData.handle );
2277 auto handleIt = m_handles.find( commandData.params[1].type.type );
2278 assert( handleIt != m_handles.end() );
2279 arguments = "static_cast<" + commandData.handle + ">( m_" + startLowerCase( stripPrefix( commandData.handle, "Vk" ) ) + " )";
2280
2281 assert( commandData.params[1].type.isValue() && commandData.params[1].arraySizes.empty() && commandData.params[1].len.empty() );
2282 arguments += ", static_cast<" + commandData.params[1].type.type + ">( m_" +
2283 generateRAIIHandleConstructorParamName( handleIt->first, handleIt->second.destructorIt ) + " )";
2284 encounteredArgument = true;
2285 }
2286 break;
2287 }
2288 }
2289 else
2290 {
2291 for ( size_t i = 0; i < initialSkipCount; ++i )
2292 {
2293 if ( encounteredArgument )
2294 {
2295 arguments += ", ";
2296 }
2297 assert( isHandleType( commandData.params[i].type.type ) && commandData.params[i].type.isValue() );
2298 assert( commandData.params[i].arraySizes.empty() && commandData.params[i].len.empty() );
2299 arguments += "m_" + startLowerCase( stripPrefix( commandData.params[i].type.type, "Vk" ) );
2300 encounteredArgument = true;
2301 }
2302 }
2303 for ( size_t i = initialSkipCount; i < commandData.params.size(); ++i )
2304 {
2305 if ( encounteredArgument )
2306 {
2307 arguments += ", ";
2308 }
2309 arguments += generateCallArgumentEnhanced( commandData.params, i, nonConstPointerAsNullptr, singularParams, templatedParams );
2310 encounteredArgument = true;
2311 }
2312 return arguments;
2313 }
2314
generateCallArgumentsRAIIFactory(std::vector<ParamData> const & params,size_t initialSkipCount,std::set<size_t> const & skippedParams,std::set<size_t> const & singularParams) const2315 std::string VulkanHppGenerator::generateCallArgumentsRAIIFactory( std::vector<ParamData> const & params,
2316 size_t initialSkipCount,
2317 std::set<size_t> const & skippedParams,
2318 std::set<size_t> const & singularParams ) const
2319 {
2320 assert( initialSkipCount <= params.size() );
2321 std::string arguments = "*this";
2322 // skip the last parameter!
2323 for ( size_t i = initialSkipCount; i < params.size() - 1; ++i )
2324 {
2325 if ( skippedParams.find( i ) == skippedParams.end() )
2326 {
2327 std::string argument = params[i].name;
2328 if ( !params[i].type.isValue() )
2329 {
2330 argument = startLowerCase( stripPrefix( argument, "p" ) );
2331 if ( singularParams.find( i ) != singularParams.end() )
2332 {
2333 argument = stripPluralS( argument, m_tags );
2334 }
2335 }
2336 else
2337 {
2338 assert( singularParams.find( i ) == singularParams.end() );
2339 }
2340 arguments += ", " + argument;
2341 }
2342 }
2343 return arguments;
2344 }
2345
generateCallArgumentsStandard(std::string const & handle,std::vector<ParamData> const & params) const2346 std::string VulkanHppGenerator::generateCallArgumentsStandard( std::string const & handle, std::vector<ParamData> const & params ) const
2347 {
2348 std::string arguments;
2349 bool encounteredArgument = false;
2350 for ( auto const & param : params )
2351 {
2352 if ( encounteredArgument )
2353 {
2354 arguments += ", ";
2355 }
2356 if ( ( param.type.type == handle ) && param.type.isValue() )
2357 {
2358 assert( param.arraySizes.empty() && param.len.empty() );
2359 arguments += "m_" + startLowerCase( stripPrefix( param.type.type, "Vk" ) );
2360 }
2361 else
2362 {
2363 std::string argument = param.name;
2364 if ( param.type.type.starts_with( "Vk" ) )
2365 {
2366 if ( !param.arraySizes.empty() )
2367 {
2368 assert( param.arraySizes.size() == 1 );
2369 assert( param.type.isValue() );
2370 assert( param.type.postfix.empty() );
2371 argument = "reinterpret_cast<" + param.type.compose( "" ) + " *>( " + argument + " )";
2372 }
2373 else if ( param.type.isValue() )
2374 {
2375 argument = "static_cast<" + param.type.type + ">( " + argument + " )";
2376 }
2377 else
2378 {
2379 assert( !param.type.postfix.empty() );
2380 argument = "reinterpret_cast<" + param.type.compose( "" ) + ">( " + argument + " )";
2381 }
2382 }
2383 arguments += argument;
2384 }
2385 encounteredArgument = true;
2386 }
2387 return arguments;
2388 }
2389
generateCallArgumentEnhanced(std::vector<ParamData> const & params,size_t paramIndex,bool nonConstPointerAsNullptr,std::set<size_t> const & singularParams,std::set<size_t> const & templatedParams) const2390 std::string VulkanHppGenerator::generateCallArgumentEnhanced( std::vector<ParamData> const & params,
2391 size_t paramIndex,
2392 bool nonConstPointerAsNullptr,
2393 std::set<size_t> const & singularParams,
2394 std::set<size_t> const & templatedParams ) const
2395 {
2396 std::string argument;
2397 ParamData const & param = params[paramIndex];
2398 if ( param.type.isConstPointer() || ( specialPointerTypes.find( param.type.type ) != specialPointerTypes.end() ) )
2399 {
2400 // parameter is a const-pointer or one of the special pointer types that are considered to be const-pointers
2401 argument = generateCallArgumentEnhancedConstPointer( param, paramIndex, singularParams, templatedParams );
2402 }
2403 else if ( param.type.isNonConstPointer() && ( specialPointerTypes.find( param.type.type ) == specialPointerTypes.end() ) )
2404 {
2405 // parameter is a non-const pointer and none of the special pointer types, that are considered const-pointers
2406 argument = generateCallArgumentEnhancedNonConstPointer( param, paramIndex, nonConstPointerAsNullptr, singularParams );
2407 }
2408 else
2409 {
2410 argument = generateCallArgumentEnhancedValue( params, paramIndex, singularParams );
2411 }
2412 assert( !argument.empty() );
2413 return argument;
2414 }
2415
generateCallArgumentEnhancedConstPointer(ParamData const & param,size_t paramIndex,std::set<size_t> const & singularParams,std::set<size_t> const & templatedParams) const2416 std::string VulkanHppGenerator::generateCallArgumentEnhancedConstPointer( ParamData const & param,
2417 size_t paramIndex,
2418 std::set<size_t> const & singularParams,
2419 std::set<size_t> const & templatedParams ) const
2420 {
2421 std::string argument;
2422 std::string name = startLowerCase( stripPrefix( param.name, "p" ) );
2423 if ( isHandleType( param.type.type ) && param.type.isValue() )
2424 {
2425 assert( !param.optional );
2426 // if at all, this is the first argument, and it's the implicitly provided member handle
2427 assert( paramIndex == 0 );
2428 assert( param.arraySizes.empty() && param.len.empty() );
2429 argument = "m_" + startLowerCase( stripPrefix( param.type.type, "Vk" ) );
2430 }
2431 else if ( param.len.empty() )
2432 {
2433 // this const-pointer parameter has no length, that is it's a const-pointer to a single value
2434 if ( param.type.type == "void" )
2435 {
2436 argument = ( templatedParams.find( paramIndex ) == templatedParams.end() )
2437 ? param.name
2438 : "reinterpret_cast<" + param.type.compose( "VULKAN_HPP_NAMESPACE" ) + ">( &" + name + " )";
2439 }
2440 else if ( param.optional )
2441 {
2442 argument = "static_cast<" + param.type.compose( "VULKAN_HPP_NAMESPACE" ) + ">( " + name + " )";
2443 }
2444 else
2445 {
2446 argument = "&" + name;
2447 }
2448 if ( param.type.type.starts_with( "Vk" ) )
2449 {
2450 argument = "reinterpret_cast<" + param.type.compose( "" ) + ">( " + argument + " )";
2451 }
2452 }
2453 else if ( param.len == "null-terminated" )
2454 {
2455 // this const-pointer parameter is "null-terminated", that is it's a string
2456 assert( ( param.type.type == "char" ) && param.arraySizes.empty() );
2457 if ( param.optional )
2458 {
2459 argument = name + " ? " + name + "->c_str() : nullptr";
2460 }
2461 else
2462 {
2463 argument = name + ".c_str()";
2464 }
2465 }
2466 else
2467 {
2468 // this const-pointer parameter has some explicit length
2469 if ( singularParams.find( paramIndex ) != singularParams.end() )
2470 {
2471 assert( !param.optional );
2472 argument = "&" + stripPluralS( name, m_tags );
2473 }
2474 else
2475 {
2476 // this const-parameter is represented by some array, where data() also works with no data (optional)
2477 argument = name + ".data()";
2478 }
2479 if ( param.type.type.starts_with( "Vk" ) || ( param.type.type == "void" ) )
2480 {
2481 argument = "reinterpret_cast<" + param.type.compose( "" ) + ">( " + argument + " )";
2482 }
2483 }
2484 return argument;
2485 }
2486
generateCallArgumentEnhancedNonConstPointer(ParamData const & param,size_t paramIndex,bool nonConstPointerAsNullptr,std::set<size_t> const & singularParams) const2487 std::string VulkanHppGenerator::generateCallArgumentEnhancedNonConstPointer( ParamData const & param,
2488 size_t paramIndex,
2489 bool nonConstPointerAsNullptr,
2490 std::set<size_t> const & singularParams ) const
2491 {
2492 std::string argument;
2493 std::string name = startLowerCase( stripPrefix( param.name, "p" ) );
2494 if ( param.len.empty() )
2495 {
2496 assert( param.arraySizes.empty() );
2497 if ( param.type.type.starts_with( "Vk" ) )
2498 {
2499 argument = "reinterpret_cast<" + param.type.compose( "" ) + ">( &" + name + " )";
2500 }
2501 else
2502 {
2503 assert( !param.optional );
2504 argument = "&" + name;
2505 }
2506 }
2507 else
2508 {
2509 // the non-const pointer has a len -> it will be represented by some array
2510 assert( param.arraySizes.empty() );
2511 if ( nonConstPointerAsNullptr )
2512 {
2513 argument = "nullptr";
2514 }
2515 else
2516 {
2517 if ( singularParams.find( paramIndex ) != singularParams.end() )
2518 {
2519 argument = "&" + stripPluralS( name, m_tags );
2520 }
2521 else
2522 {
2523 // get the data of the array, which also covers no data -> no need to look at param.optional
2524 argument = name + ".data()";
2525 }
2526 if ( param.type.type.starts_with( "Vk" ) || ( param.type.type == "void" ) )
2527 {
2528 argument = "reinterpret_cast<" + param.type.compose( "" ) + ">( " + argument + " )";
2529 }
2530 }
2531 }
2532 return argument;
2533 }
2534
generateCallArgumentEnhancedValue(std::vector<ParamData> const & params,size_t paramIndex,std::set<size_t> const & singularParams) const2535 std::string VulkanHppGenerator::generateCallArgumentEnhancedValue( std::vector<ParamData> const & params,
2536 size_t paramIndex,
2537 std::set<size_t> const & singularParams ) const
2538 {
2539 std::string argument;
2540 ParamData const & param = params[paramIndex];
2541 assert( param.len.empty() );
2542 if ( param.type.type.starts_with( "Vk" ) )
2543 {
2544 if ( param.arraySizes.empty() )
2545 {
2546 auto pointerIt = std::find_if( params.begin(), params.end(), [¶m]( ParamData const & pd ) { return pd.len == param.name; } );
2547 if ( pointerIt != params.end() )
2548 {
2549 assert( !param.optional );
2550 argument = startLowerCase( stripPrefix( pointerIt->name, "p" ) ) + ".size()";
2551 if ( pointerIt->type.type == "void" )
2552 {
2553 argument += " * sizeof( " + stripPrefix( pointerIt->name, "p" ) + "Type )";
2554 }
2555 }
2556 else
2557 {
2558 argument = "static_cast<" + param.type.compose( "" ) + ">( " + param.name + " )";
2559 }
2560 assert( std::find_if( params.begin(), params.end(), [¶m]( ParamData const & pd ) { return pd.stride == param.name; } ) == params.end() );
2561 }
2562 else
2563 {
2564 assert( !param.optional );
2565 assert( param.arraySizes.size() == 1 );
2566 assert( param.type.prefix == "const" );
2567 argument = "reinterpret_cast<" + param.type.compose( "" ) + " *>( " + param.name + " )";
2568 }
2569 }
2570 else
2571 {
2572 auto pointerIt = std::find_if( params.begin(), params.end(), [¶m]( ParamData const & pd ) { return pd.len == param.name; } );
2573 if ( pointerIt != params.end() )
2574 {
2575 // this parameter is the len of some other -> replace it with that parameter's size
2576 assert( param.arraySizes.empty() );
2577 assert( ( param.type.type == "size_t" ) || ( param.type.type == "uint32_t" ) );
2578 if ( singularParams.find( paramIndex ) == singularParams.end() )
2579 {
2580 argument = startLowerCase( stripPrefix( pointerIt->name, "p" ) ) + ".size()";
2581 if ( pointerIt->type.type == "void" )
2582 {
2583 argument += " * sizeof( " + stripPrefix( pointerIt->name, "p" ) + "Type )";
2584 }
2585 }
2586 else
2587 {
2588 if ( pointerIt->type.type == "void" )
2589 {
2590 argument = "sizeof( " + stripPrefix( pointerIt->name, "p" ) + "Type )";
2591 }
2592 else
2593 {
2594 argument = "1";
2595 }
2596 }
2597 }
2598 else
2599 {
2600 assert( !param.optional );
2601 assert( param.arraySizes.size() <= 1 );
2602 pointerIt = std::find_if( params.begin(), params.end(), [¶m]( ParamData const & pd ) { return pd.stride == param.name; } );
2603 if ( pointerIt != params.end() )
2604 {
2605 // this parameter is the stride of some other -> replace it with that parameter's stride
2606 assert( param.arraySizes.empty() );
2607 assert( param.type.type == "uint32_t" );
2608 argument = startLowerCase( stripPrefix( pointerIt->name, "p" ) ) + ".stride()";
2609 }
2610 else
2611 {
2612 argument = param.name;
2613 }
2614 }
2615 }
2616 return argument;
2617 }
2618
generateCallSequence(std::string const & name,CommandData const & commandData,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,size_t initialSkipCount,std::set<size_t> const & singularParams,std::set<size_t> const & templatedParams,CommandFlavourFlags flavourFlags,bool raii) const2619 std::string VulkanHppGenerator::generateCallSequence( std::string const & name,
2620 CommandData const & commandData,
2621 std::vector<size_t> const & returnParams,
2622 std::map<size_t, VectorParamData> const & vectorParams,
2623 size_t initialSkipCount,
2624 std::set<size_t> const & singularParams,
2625 std::set<size_t> const & templatedParams,
2626 CommandFlavourFlags flavourFlags,
2627 bool raii ) const
2628 {
2629 std::string dispatcher = raii ? "getDispatcher()->" : "d.";
2630 // if at least one returnParam is a size value of a vector param (and no singular params), we need two calls
2631 if ( singularParams.empty() &&
2632 ( std::find_if( returnParams.begin(),
2633 returnParams.end(),
2634 [&vectorParams]( size_t rp )
2635 {
2636 return ( std::find_if( vectorParams.begin(), vectorParams.end(), [rp]( auto const & vp ) { return vp.second.lenParam == rp; } ) !=
2637 vectorParams.end() );
2638 } ) != returnParams.end() ) )
2639 {
2640 auto vectorParamIt = vectorParams.find( returnParams[1] );
2641 assert( ( vectorParamIt != vectorParams.end() ) && ( vectorParamIt->second.lenParam == returnParams[0] ) );
2642
2643 std::string firstCallArguments = generateCallArgumentsEnhanced( commandData, initialSkipCount, true, {}, templatedParams, raii );
2644 std::string secondCallArguments = generateCallArgumentsEnhanced( commandData, initialSkipCount, false, {}, templatedParams, raii );
2645 std::string vectorName = startLowerCase( stripPrefix( commandData.params[vectorParamIt->first].name, "p" ) );
2646 std::string vectorSize = startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) );
2647
2648 if ( flavourFlags & CommandFlavourFlagBits::chained )
2649 {
2650 assert( vectorParams.size() == 1 );
2651 // chained data needs some more handling!!
2652 std::string vectorElementType = stripPostfix( commandData.params[vectorParamIt->first].type.compose( "VULKAN_HPP_NAMESPACE" ), " *" );
2653
2654 if ( commandData.returnType == "VkResult" )
2655 {
2656 const std::string callSequenceTemplate = R"(VkResult result;
2657 do
2658 {
2659 result = ${dispatcher}${vkCommand}( ${firstCallArguments} );
2660 if ( ( result == VK_SUCCESS ) && ${counterName} )
2661 {
2662 structureChains.resize( ${counterName} );
2663 ${vectorName}.resize( ${counterName} );
2664 for ( ${counterType} i = 0; i < ${counterName}; i++ )
2665 {
2666 ${vectorName}[i].pNext = structureChains[i].template get<${vectorElementType}>().pNext;
2667 }
2668 result = ${dispatcher}${vkCommand}( ${secondCallArguments} );
2669 }
2670 } while ( result == VK_INCOMPLETE );)";
2671
2672 return replaceWithMap( callSequenceTemplate,
2673 { { "counterName", startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) ) },
2674 { "counterType", commandData.params[vectorParamIt->second.lenParam].type.type },
2675 { "dispatcher", dispatcher },
2676 { "firstCallArguments", firstCallArguments },
2677 { "secondCallArguments", secondCallArguments },
2678 { "vectorElementType", vectorElementType },
2679 { "vectorName", vectorName },
2680 { "vkCommand", name } } );
2681 }
2682 else
2683 {
2684 const std::string callSequenceTemplate =
2685 R"(${dispatcher}${vkCommand}( ${firstCallArguments} );
2686 structureChains.resize( ${counterName} );
2687 ${vectorName}.resize( ${counterName} );
2688 for ( ${counterType} i = 0; i < ${counterName}; i++ )
2689 {
2690 ${vectorName}[i].pNext = structureChains[i].template get<${vectorElementType}>().pNext;
2691 }
2692 ${dispatcher}${vkCommand}( ${secondCallArguments} );)";
2693
2694 return replaceWithMap( callSequenceTemplate,
2695 { { "counterName", startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) ) },
2696 { "counterType", commandData.params[vectorParamIt->second.lenParam].type.type },
2697 { "dispatcher", dispatcher },
2698 { "firstCallArguments", firstCallArguments },
2699 { "secondCallArguments", secondCallArguments },
2700 { "vectorElementType", vectorElementType },
2701 { "vectorName", vectorName },
2702 { "vkCommand", name } } );
2703 }
2704 }
2705 else if ( commandData.returnType == "VkResult" )
2706 {
2707 assert( ( commandData.successCodes.size() == 2 ) && ( commandData.successCodes[0] == "VK_SUCCESS" ) &&
2708 ( commandData.successCodes[1] == "VK_INCOMPLETE" ) );
2709
2710 std::string resizes;
2711 for ( auto const & vp : vectorParams )
2712 {
2713 assert( ( std::find( returnParams.begin(), returnParams.end(), vp.first ) != returnParams.end() ) &&
2714 ( std::find( returnParams.begin(), returnParams.end(), vp.second.lenParam ) != returnParams.end() ) );
2715 resizes += startLowerCase( stripPrefix( commandData.params[vp.first].name, "p" ) ) + ".resize( " +
2716 startLowerCase( stripPrefix( commandData.params[vp.second.lenParam].name, "p" ) ) + " );\n";
2717 }
2718 resizes.pop_back();
2719
2720 std::string const callSequenceTemplate = R"(VkResult result;
2721 do
2722 {
2723 result = ${dispatcher}${vkCommand}( ${firstCallArguments} );
2724 if ( ( result == VK_SUCCESS ) && ${counterName} )
2725 {
2726 ${resizes}
2727 result = ${dispatcher}${vkCommand}( ${secondCallArguments} );
2728 }
2729 } while ( result == VK_INCOMPLETE );)";
2730
2731 return replaceWithMap( callSequenceTemplate,
2732 { { "counterName", startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) ) },
2733 { "dispatcher", dispatcher },
2734 { "firstCallArguments", firstCallArguments },
2735 { "secondCallArguments", secondCallArguments },
2736 { "resizes", resizes },
2737 { "vkCommand", name } } );
2738 }
2739 else
2740 {
2741 // no need to enumerate here, just two calls
2742 assert( commandData.returnType == "void" );
2743 std::string const callSequenceTemplate = R"(${dispatcher}${vkCommand}( ${firstCallArguments} );
2744 ${vectorName}.resize( ${vectorSize} );
2745 ${dispatcher}${vkCommand}( ${secondCallArguments} );)";
2746
2747 return replaceWithMap( callSequenceTemplate,
2748 { { "dispatcher", dispatcher },
2749 { "firstCallArguments", firstCallArguments },
2750 { "secondCallArguments", secondCallArguments },
2751 { "vectorName", vectorName },
2752 { "vectorSize", vectorSize },
2753 { "vkCommand", name } } );
2754 }
2755 }
2756 else
2757 {
2758 std::string const callSequenceTemplate = R"(${resultAssignment}${dispatcher}${vkCommand}( ${callArguments} );)";
2759
2760 std::string callArguments = generateCallArgumentsEnhanced( commandData, initialSkipCount, false, singularParams, templatedParams, raii );
2761 std::string resultAssignment = generateResultAssignment( commandData );
2762
2763 return replaceWithMap(
2764 callSequenceTemplate,
2765 { { "callArguments", callArguments }, { "dispatcher", dispatcher }, { "resultAssignment", resultAssignment }, { "vkCommand", name } } );
2766 }
2767 }
2768
generateCommand(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const2769 std::string VulkanHppGenerator::generateCommand( std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition ) const
2770 {
2771 if ( commandData.returnType == "VkResult" )
2772 {
2773 assert( !commandData.successCodes.empty() );
2774 if ( commandData.successCodes.size() == 1 )
2775 {
2776 if ( commandData.errorCodes.empty() )
2777 {
2778 return generateCommandResultSingleSuccessNoErrors( name, commandData, initialSkipCount, definition );
2779 }
2780 else
2781 {
2782 return generateCommandResultSingleSuccessWithErrors( name, commandData, initialSkipCount, definition );
2783 }
2784 }
2785 else
2786 {
2787 if ( commandData.errorCodes.empty() )
2788 {
2789 return generateCommandResultMultiSuccessNoErrors( name, commandData, initialSkipCount, definition );
2790 }
2791 else
2792 {
2793 return generateCommandResultMultiSuccessWithErrors( name, commandData, initialSkipCount, definition );
2794 }
2795 }
2796 }
2797 else if ( commandData.returnType == "void" )
2798 {
2799 std::vector<size_t> returnParams = determineReturnParams( commandData.params );
2800 switch ( returnParams.size() )
2801 {
2802 case 0: return generateCommandVoid0Return( name, commandData, initialSkipCount, definition );
2803 case 1: return generateCommandVoid1Return( name, commandData, initialSkipCount, definition, returnParams[0] );
2804 case 2: return generateCommandVoid2Return( name, commandData, initialSkipCount, definition, returnParams );
2805 }
2806 }
2807 else
2808 {
2809 return generateCommandValue( name, commandData, initialSkipCount, definition );
2810 }
2811
2812 throw std::runtime_error( "Never encountered a function like <" + name + "> !" );
2813 }
2814
generateCommandDefinitions() const2815 std::string VulkanHppGenerator::generateCommandDefinitions() const
2816 {
2817 const std::string commandDefinitionsTemplate = R"(
2818 //===========================
2819 //=== COMMAND Definitions ===
2820 //===========================
2821
2822 ${commandDefinitions}
2823 )";
2824
2825 std::string commandDefinitions;
2826 std::set<std::string> listedCommands; // some commands are listed with more than one extension!
2827 for ( auto const & feature : m_features )
2828 {
2829 commandDefinitions += generateCommandDefinitions( feature.second.requireData, listedCommands, feature.first );
2830 }
2831 for ( auto const & extIt : m_extensionsByNumber )
2832 {
2833 commandDefinitions += generateCommandDefinitions( extIt.second->second.requireData, listedCommands, extIt.second->first );
2834 }
2835
2836 return replaceWithMap( commandDefinitionsTemplate, { { "commandDefinitions", commandDefinitions } } );
2837 }
2838
generateCommandDefinitions(std::vector<RequireData> const & requireData,std::set<std::string> & listedCommands,std::string const & title) const2839 std::string VulkanHppGenerator::generateCommandDefinitions( std::vector<RequireData> const & requireData,
2840 std::set<std::string> & listedCommands,
2841 std::string const & title ) const
2842 {
2843 std::string str;
2844 for ( auto const & require : requireData )
2845 {
2846 for ( auto const & command : require.commands )
2847 {
2848 if ( listedCommands.insert( command ).second )
2849 {
2850 auto commandIt = m_commands.find( command );
2851 assert( commandIt != m_commands.end() );
2852 str += generateCommandDefinitions( command, commandIt->second.handle );
2853 }
2854 }
2855 }
2856 return addTitleAndProtection( title, str );
2857 }
2858
generateCommandDefinitions(std::string const & command,std::string const & handle) const2859 std::string VulkanHppGenerator::generateCommandDefinitions( std::string const & command, std::string const & handle ) const
2860 {
2861 auto commandIt = m_commands.find( command );
2862 assert( commandIt != m_commands.end() );
2863
2864 std::string str = "\n" + generateCommand( commandIt->first, commandIt->second, handle.empty() ? 0 : 1, true );
2865
2866 // special handling for destroy functions, filter out alias functions
2867 std::string commandName = generateCommandName( commandIt->first, commandIt->second.params, 1, m_tags );
2868 if ( commandIt->second.alias.empty() &&
2869 ( ( ( commandIt->first.substr( 2, 7 ) == "Destroy" ) && ( commandName != "destroy" ) ) || ( commandIt->first.substr( 2, 4 ) == "Free" ) ||
2870 ( commandIt->first == "vkReleasePerformanceConfigurationINTEL" ) ) )
2871 {
2872 CommandData commandData = commandIt->second;
2873 assert( ( 1 < commandData.params.size() ) && ( commandData.params[0].type.type == handle ) );
2874 commandData.params[1].optional = false; // make sure, the object to destroy/free/release is not optional in the shortened version!
2875
2876 std::string destroyCommandString = generateCommand( commandIt->first, commandData, handle.empty() ? 0 : 1, true );
2877 std::string shortenedName;
2878 if ( commandIt->first.substr( 2, 7 ) == "Destroy" )
2879 {
2880 shortenedName = "destroy";
2881 }
2882 else if ( commandIt->first.substr( 2, 4 ) == "Free" )
2883 {
2884 shortenedName = "free";
2885 }
2886 else
2887 {
2888 assert( commandIt->first == "vkReleasePerformanceConfigurationINTEL" );
2889 shortenedName = "release";
2890 }
2891 size_t pos = destroyCommandString.find( commandName );
2892 while ( pos != std::string::npos )
2893 {
2894 destroyCommandString.replace( pos, commandName.length(), shortenedName );
2895 pos = destroyCommandString.find( commandName, pos );
2896 }
2897
2898 // special handling for "free", to prevent interfering with MSVC debug free!
2899 if ( shortenedName == "free" )
2900 {
2901 std::string toEncloseString = stripPrefix( handle, "Vk" ) + "::free";
2902 std::string enclosedString = "( " + toEncloseString + " )";
2903 pos = destroyCommandString.find( toEncloseString );
2904 while ( pos != std::string::npos )
2905 {
2906 destroyCommandString.replace( pos, toEncloseString.length(), enclosedString );
2907 pos = destroyCommandString.find( toEncloseString, pos + enclosedString.length() );
2908 }
2909 }
2910
2911 // we need to remove the default argument for the first argument, to prevent ambiguities!
2912 assert( 1 < commandIt->second.params.size() );
2913 pos = destroyCommandString.find( commandIt->second.params[1].name ); // skip the standard version of the function
2914 assert( pos != std::string::npos );
2915 pos = destroyCommandString.find( commandIt->second.params[1].name,
2916 pos + 1 ); // get the argument to destroy in the advanced version
2917 assert( pos != std::string::npos );
2918 pos = destroyCommandString.find( " VULKAN_HPP_DEFAULT_ARGUMENT_ASSIGNMENT", pos );
2919 if ( pos != std::string::npos )
2920 {
2921 destroyCommandString.erase( pos, strlen( " VULKAN_HPP_DEFAULT_ARGUMENT_ASSIGNMENT" ) );
2922 }
2923 str += "\n" + destroyCommandString;
2924 }
2925 return str;
2926 }
2927
generateCommandEnhanced(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,std::map<size_t,VectorParamData> const & vectorParams,std::vector<size_t> const & returnParams,CommandFlavourFlags flavourFlags) const2928 std::string VulkanHppGenerator::generateCommandEnhanced( std::string const & name,
2929 CommandData const & commandData,
2930 size_t initialSkipCount,
2931 bool definition,
2932 std::map<size_t, VectorParamData> const & vectorParams,
2933 std::vector<size_t> const & returnParams,
2934 CommandFlavourFlags flavourFlags ) const
2935 {
2936 bool singular = flavourFlags & CommandFlavourFlagBits::singular;
2937
2938 assert( vectorParams.empty() || ( vectorParams.begin()->second.lenParam != INVALID_INDEX ) );
2939 assert( !singular || !returnParams.empty() ); // if singular is true, then there is at least one returnParam !
2940
2941 std::set<size_t> skippedParams = determineSkippedParams( commandData.params, initialSkipCount, vectorParams, returnParams, singular );
2942 // special handling for vkGetMemoryHostPointerPropertiesEXT: here, we really need to stick with the const void * parameter !
2943 std::set<size_t> templatedParams = ( name == "vkGetMemoryHostPointerPropertiesEXT" ) ? std::set<size_t>() : determineVoidPointerParams( commandData.params );
2944 std::set<size_t> singularParams = singular ? determineSingularParams( returnParams[0], vectorParams ) : std::set<size_t>();
2945 std::pair<bool, std::map<size_t, std::vector<size_t>>> vectorSizeCheck =
2946 needsVectorSizeCheck( commandData.params, vectorParams, returnParams, singularParams );
2947 bool enumerating = determineEnumeration( vectorParams, returnParams );
2948
2949 std::vector<std::string> dataTypes = determineDataTypes( commandData.params, vectorParams, returnParams, templatedParams );
2950 std::string dataType = combineDataTypes( vectorParams, returnParams, enumerating, dataTypes, flavourFlags, false );
2951
2952 std::string argumentTemplates = generateArgumentTemplates( commandData.params, returnParams, vectorParams, templatedParams, flavourFlags, false );
2953 auto [allocatorTemplates, uniqueHandleAllocatorTemplates] = generateAllocatorTemplates( returnParams, dataTypes, vectorParams, flavourFlags, definition );
2954 std::string typenameCheck = generateTypenameCheck( returnParams, vectorParams, definition, dataTypes, flavourFlags );
2955 std::string nodiscard = generateNoDiscard( !returnParams.empty(), 1 < commandData.successCodes.size(), 1 < commandData.errorCodes.size() );
2956 std::string returnType = generateReturnType( commandData, returnParams, vectorParams, flavourFlags, false, dataType );
2957 std::string className = initialSkipCount ? stripPrefix( commandData.params[initialSkipCount - 1].type.type, "Vk" ) : "";
2958 std::string classSeparator = commandData.handle.empty() ? "" : "::";
2959 std::string commandName = generateCommandName( name, commandData.params, initialSkipCount, m_tags, flavourFlags );
2960 std::string argumentList = generateArgumentListEnhanced(
2961 commandData.params, returnParams, vectorParams, skippedParams, singularParams, templatedParams, definition, flavourFlags, true );
2962 std::string constString = commandData.handle.empty() ? "" : " const";
2963 std::string noexceptString = generateNoExcept( commandData.errorCodes, returnParams, vectorParams, flavourFlags, vectorSizeCheck.first, false );
2964
2965 if ( definition )
2966 {
2967 std::string vectorSizeCheckString =
2968 vectorSizeCheck.first ? generateVectorSizeCheck( name, commandData, initialSkipCount, vectorSizeCheck.second, skippedParams, false ) : "";
2969 std::string returnVariable = generateReturnVariable( commandData, returnParams, vectorParams, flavourFlags );
2970 std::string dataDeclarations = generateDataDeclarations(
2971 commandData, returnParams, vectorParams, templatedParams, flavourFlags, false, dataTypes, dataType, returnType, returnVariable );
2972 std::string dataPreparation =
2973 generateDataPreparation( commandData, initialSkipCount, returnParams, vectorParams, templatedParams, flavourFlags, enumerating );
2974 std::string dataSizeChecks = generateDataSizeChecks( commandData, returnParams, dataTypes, vectorParams, templatedParams, singular );
2975 std::string callSequence =
2976 generateCallSequence( name, commandData, returnParams, vectorParams, initialSkipCount, singularParams, templatedParams, flavourFlags, false );
2977 std::string resultCheck = generateResultCheck( commandData, className, classSeparator, commandName, enumerating );
2978 std::string returnStatement = generateReturnStatement( name,
2979 commandData,
2980 returnVariable,
2981 returnType,
2982 dataType,
2983 initialSkipCount,
2984 returnParams.empty() ? INVALID_INDEX : returnParams[0],
2985 flavourFlags,
2986 enumerating,
2987 false );
2988
2989 std::string const functionTemplate =
2990 R"( template <${argumentTemplates}${allocatorTemplates}typename Dispatch${uniqueHandleAllocatorTemplates}${typenameCheck}>
2991 ${nodiscard}VULKAN_HPP_INLINE ${returnType} ${className}${classSeparator}${commandName}( ${argumentList} )${const}${noexcept}
2992 {
2993 VULKAN_HPP_ASSERT( d.getVkHeaderVersion() == VK_HEADER_VERSION );
2994 ${vectorSizeCheck}
2995 ${dataSizeChecks}
2996 ${dataDeclarations}
2997 ${callSequence}
2998 ${resultCheck}
2999 ${dataPreparation}
3000 ${returnStatement}
3001 })";
3002
3003 return replaceWithMap( functionTemplate,
3004 { { "allocatorTemplates", allocatorTemplates },
3005 { "argumentList", argumentList },
3006 { "argumentTemplates", argumentTemplates },
3007 { "callSequence", callSequence },
3008 { "className", className },
3009 { "classSeparator", classSeparator },
3010 { "commandName", commandName },
3011 { "const", constString },
3012 { "dataDeclarations", dataDeclarations },
3013 { "dataPreparation", dataPreparation },
3014 { "dataSizeChecks", dataSizeChecks },
3015 { "nodiscard", nodiscard },
3016 { "noexcept", noexceptString },
3017 { "resultCheck", resultCheck },
3018 { "returnStatement", returnStatement },
3019 { "returnType", returnType },
3020 { "typenameCheck", typenameCheck },
3021 { "uniqueHandleAllocatorTemplates", uniqueHandleAllocatorTemplates },
3022 { "vectorSizeCheck", vectorSizeCheckString } } );
3023 }
3024 else
3025 {
3026 std::string const functionTemplate =
3027 R"( template <${argumentTemplates}${allocatorTemplates}typename Dispatch = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE${uniqueHandleAllocatorTemplates}${typenameCheck}>
3028 ${nodiscard}${returnType} ${commandName}( ${argumentList} )${const}${noexcept};)";
3029
3030 return replaceWithMap( functionTemplate,
3031 { { "allocatorTemplates", allocatorTemplates },
3032 { "argumentList", argumentList },
3033 { "argumentTemplates", argumentTemplates },
3034 { "commandName", commandName },
3035 { "const", commandData.handle.empty() ? "" : " const" },
3036 { "nodiscard", nodiscard },
3037 { "noexcept", noexceptString },
3038 { "returnType", returnType },
3039 { "typenameCheck", typenameCheck },
3040 { "uniqueHandleAllocatorTemplates", uniqueHandleAllocatorTemplates } } );
3041 }
3042 }
3043
generateCommandName(std::string const & vulkanCommandName,std::vector<ParamData> const & params,size_t initialSkipCount,std::set<std::string> const & tags,CommandFlavourFlags flavourFlags) const3044 std::string VulkanHppGenerator::generateCommandName( std::string const & vulkanCommandName,
3045 std::vector<ParamData> const & params,
3046 size_t initialSkipCount,
3047 std::set<std::string> const & tags,
3048 CommandFlavourFlags flavourFlags ) const
3049 {
3050 std::string commandName( startLowerCase( stripPrefix( vulkanCommandName, "vk" ) ) );
3051 for ( size_t i = initialSkipCount - 1; i < initialSkipCount; --i ) // count down to zero, then wrap around and stop
3052 {
3053 std::string const & argumentType = params[i].type.type;
3054 std::string searchName = stripPrefix( argumentType, "Vk" );
3055 std::string argumentTag = findTag( tags, argumentType );
3056 if ( !argumentTag.empty() )
3057 {
3058 searchName = stripPostfix( searchName, argumentTag );
3059 }
3060 size_t pos = commandName.find( searchName );
3061 if ( pos == std::string::npos )
3062 {
3063 searchName = startLowerCase( searchName );
3064 pos = commandName.find( searchName );
3065 }
3066 if ( pos != std::string::npos )
3067 {
3068 size_t len = searchName.length();
3069 if ( commandName.find( searchName + "s" ) == pos )
3070 {
3071 // filter out any plural of the searchName as well!
3072 ++len;
3073 }
3074 commandName.erase( pos, len );
3075 }
3076 else if ( ( searchName == "commandBuffer" ) && commandName.starts_with( "cmd" ) )
3077 {
3078 commandName.erase( 0, 3 );
3079 pos = 0;
3080 }
3081 if ( pos == 0 )
3082 {
3083 commandName = startLowerCase( commandName );
3084 }
3085 std::string commandTag = findTag( tags, commandName );
3086 if ( !argumentTag.empty() && ( argumentTag == commandTag ) )
3087 {
3088 commandName = stripPostfix( commandName, argumentTag );
3089 }
3090 }
3091 if ( flavourFlags & CommandFlavourFlagBits::singular )
3092 {
3093 commandName = stripPluralS( commandName, m_tags );
3094 }
3095 if ( flavourFlags & CommandFlavourFlagBits::unique )
3096 {
3097 commandName += "Unique";
3098 }
3099 return commandName;
3100 }
3101
generateCommandResultMultiSuccessNoErrors(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3102 std::string VulkanHppGenerator::generateCommandResultMultiSuccessNoErrors( std::string const & name,
3103 CommandData const & commandData,
3104 size_t initialSkipCount,
3105 bool definition ) const
3106 {
3107 std::vector<size_t> returnParams = determineReturnParams( commandData.params );
3108 switch ( returnParams.size() )
3109 {
3110 case 0: return generateCommandResultMultiSuccessNoErrors0Return( name, commandData, initialSkipCount, definition ); break;
3111 case 2: return generateCommandResultMultiSuccessNoErrors2Return( name, commandData, initialSkipCount, definition, returnParams ); break;
3112 }
3113 return "";
3114 }
3115
generateCommandResultMultiSuccessNoErrors0Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3116 std::string VulkanHppGenerator::generateCommandResultMultiSuccessNoErrors0Return( std::string const & name,
3117 CommandData const & commandData,
3118 size_t initialSkipCount,
3119 bool definition ) const
3120 {
3121 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3122 if ( vectorParams.empty() )
3123 {
3124 std::vector<size_t> constPointerParams = determineConstPointerParams( commandData.params );
3125 if ( constPointerParams.empty() )
3126 {
3127 return generateCommandSet( generateCommandStandard( name, commandData, initialSkipCount, definition ),
3128 generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, {} ) );
3129 }
3130 }
3131 return "";
3132 }
3133
generateCommandResultMultiSuccessNoErrors2Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const3134 std::string VulkanHppGenerator::generateCommandResultMultiSuccessNoErrors2Return(
3135 std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, std::vector<size_t> const & returnParams ) const
3136 {
3137 if ( ( commandData.successCodes.size() == 2 ) && ( commandData.successCodes[0] == "VK_SUCCESS" ) && ( commandData.successCodes[1] == "VK_INCOMPLETE" ) )
3138 {
3139 if ( ( commandData.params[returnParams[0]].type.type == "size_t" ) || ( commandData.params[returnParams[0]].type.type == "uint32_t" ) )
3140 {
3141 if ( ( commandData.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[1]].type.type ) &&
3142 !isStructureChainAnchor( commandData.params[returnParams[1]].type.type ) )
3143 {
3144 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3145 if ( vectorParams.size() == 1 )
3146 {
3147 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
3148 {
3149 if ( returnParams[1] == vectorParams.begin()->first )
3150 {
3151 return generateCommandSet(
3152 definition,
3153 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3154 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
3155 generateCommandEnhanced(
3156 name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ) } );
3157 }
3158 }
3159 }
3160 }
3161 }
3162 }
3163 return "";
3164 }
3165
generateCommandResultMultiSuccessWithErrors(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3166 std::string VulkanHppGenerator::generateCommandResultMultiSuccessWithErrors( std::string const & name,
3167 CommandData const & commandData,
3168 size_t initialSkipCount,
3169 bool definition ) const
3170 {
3171 std::vector<size_t> returnParams = determineReturnParams( commandData.params );
3172 switch ( returnParams.size() )
3173 {
3174 case 0: return generateCommandResultWithErrors0Return( name, commandData, initialSkipCount, definition ); break;
3175 case 1: return generateCommandResultMultiSuccessWithErrors1Return( name, commandData, initialSkipCount, definition, returnParams[0] ); break;
3176 case 2: return generateCommandResultMultiSuccessWithErrors2Return( name, commandData, initialSkipCount, definition, returnParams ); break;
3177 case 3: return generateCommandResultMultiSuccessWithErrors3Return( name, commandData, initialSkipCount, definition, returnParams ); break;
3178 }
3179 return "";
3180 }
3181
generateCommandResultMultiSuccessWithErrors1Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3182 std::string VulkanHppGenerator::generateCommandResultMultiSuccessWithErrors1Return(
3183 std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3184 {
3185 if ( commandData.params[returnParam].type.type == "void" )
3186 {
3187 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3188 if ( vectorParams.size() == 1 )
3189 {
3190 if ( returnParam == vectorParams.begin()->first )
3191 {
3192 if ( commandData.params[vectorParams.begin()->second.lenParam].type.isValue() )
3193 {
3194 return generateCommandSet(
3195 definition,
3196 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3197 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3198 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) } );
3199 }
3200 }
3201 }
3202 }
3203 else if ( isHandleType( commandData.params[returnParam].type.type ) )
3204 {
3205 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3206 if ( vectorParams.size() == 2 )
3207 {
3208 if ( returnParam == std::next( vectorParams.begin() )->first )
3209 {
3210 if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
3211 {
3212 if ( commandData.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
3213 {
3214 if ( isStructureChainAnchor( commandData.params[vectorParams.begin()->first].type.type ) )
3215 {
3216 return generateCommandSet(
3217 definition,
3218 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3219 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3220 generateCommandEnhanced(
3221 name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::withAllocator ),
3222 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) },
3223 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::unique ),
3224 generateCommandEnhanced( name,
3225 commandData,
3226 initialSkipCount,
3227 definition,
3228 vectorParams,
3229 { returnParam },
3230 CommandFlavourFlagBits::unique | CommandFlavourFlagBits::withAllocator ),
3231 generateCommandEnhanced( name,
3232 commandData,
3233 initialSkipCount,
3234 definition,
3235 vectorParams,
3236 { returnParam },
3237 CommandFlavourFlagBits::unique | CommandFlavourFlagBits::singular ) } );
3238 }
3239 }
3240 }
3241 }
3242 }
3243 }
3244 else if ( isStructureChainAnchor( commandData.params[returnParam].type.type ) )
3245 {
3246 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3247 if ( vectorParams.empty() )
3248 {
3249 return generateCommandSet(
3250 definition,
3251 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3252 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3253 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::chained ) } );
3254 }
3255 }
3256 else
3257 {
3258 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3259 if ( vectorParams.empty() )
3260 {
3261 return generateCommandSet( definition,
3262 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3263 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ) } );
3264 }
3265 }
3266 return "";
3267 }
3268
generateCommandResultMultiSuccessWithErrors2Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const3269 std::string VulkanHppGenerator::generateCommandResultMultiSuccessWithErrors2Return(
3270 std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, std::vector<size_t> const & returnParams ) const
3271 {
3272 if ( ( commandData.successCodes.size() == 2 ) && ( commandData.successCodes[0] == "VK_SUCCESS" ) && ( commandData.successCodes[1] == "VK_INCOMPLETE" ) )
3273 {
3274 if ( ( commandData.params[returnParams[0]].type.type == "size_t" ) || ( commandData.params[returnParams[0]].type.type == "uint32_t" ) )
3275 {
3276 if ( isStructureChainAnchor( commandData.params[returnParams[1]].type.type ) )
3277 {
3278 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3279 if ( vectorParams.size() == 1 )
3280 {
3281 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
3282 {
3283 if ( returnParams[1] == vectorParams.begin()->first )
3284 {
3285 return generateCommandSet(
3286 definition,
3287 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3288 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
3289 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ),
3290 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::chained ),
3291 generateCommandEnhanced( name,
3292 commandData,
3293 initialSkipCount,
3294 definition,
3295 vectorParams,
3296 returnParams,
3297 CommandFlavourFlagBits::chained | CommandFlavourFlagBits::withAllocator ) } );
3298 }
3299 }
3300 }
3301 }
3302 else
3303 {
3304 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3305 if ( vectorParams.size() == 1 )
3306 {
3307 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
3308 {
3309 if ( returnParams[1] == vectorParams.begin()->first )
3310 {
3311 return generateCommandSet(
3312 definition,
3313 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3314 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
3315 generateCommandEnhanced(
3316 name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ) } );
3317 }
3318 }
3319 }
3320 }
3321 }
3322 else if ( ( commandData.params[returnParams[0]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[0]].type.type ) &&
3323 !isStructureChainAnchor( commandData.params[returnParams[0]].type.type ) )
3324 {
3325 if ( ( commandData.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[1]].type.type ) &&
3326 !isStructureChainAnchor( commandData.params[returnParams[1]].type.type ) )
3327 {
3328 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3329 if ( vectorParams.empty() )
3330 {
3331 return generateCommandSet( definition,
3332 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3333 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ) } );
3334 }
3335 }
3336 }
3337 }
3338 return "";
3339 }
3340
generateCommandResultMultiSuccessWithErrors3Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const3341 std::string VulkanHppGenerator::generateCommandResultMultiSuccessWithErrors3Return(
3342 std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, std::vector<size_t> const & returnParams ) const
3343 {
3344 if ( commandData.params[returnParams[0]].type.type == "uint32_t" )
3345 {
3346 if ( ( commandData.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[1]].type.type ) &&
3347 !isStructureChainAnchor( commandData.params[returnParams[1]].type.type ) )
3348 {
3349 if ( ( commandData.params[returnParams[2]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[2]].type.type ) &&
3350 !isStructureChainAnchor( commandData.params[returnParams[2]].type.type ) )
3351 {
3352 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3353 if ( vectorParams.size() == 2 )
3354 {
3355 if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
3356 {
3357 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
3358 {
3359 if ( returnParams[1] == vectorParams.begin()->first )
3360 {
3361 if ( returnParams[2] == std::next( vectorParams.begin() )->first )
3362 {
3363 return generateCommandSet(
3364 definition,
3365 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3366 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
3367 generateCommandEnhanced(
3368 name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ) } );
3369 }
3370 }
3371 }
3372 }
3373 }
3374 }
3375 }
3376 }
3377 return "";
3378 }
3379
generateCommandResultSingleSuccessNoErrors(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3380 std::string VulkanHppGenerator::generateCommandResultSingleSuccessNoErrors( std::string const & name,
3381 CommandData const & commandData,
3382 size_t initialSkipCount,
3383 bool definition ) const
3384 {
3385 std::vector<size_t> returnParams = determineReturnParams( commandData.params );
3386 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3387 switch ( returnParams.size() )
3388 {
3389 case 0:
3390 switch ( vectorParams.size() )
3391 {
3392 case 0:
3393 {
3394 std::vector<size_t> constPointerParams = determineConstPointerParams( commandData.params );
3395 switch ( constPointerParams.size() )
3396 {
3397 case 0:
3398 return generateCommandSet( generateCommandStandard( name, commandData, initialSkipCount, definition ),
3399 generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, {} ) );
3400 case 1:
3401 return generateCommandSet( definition,
3402 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3403 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, {} ) } );
3404 }
3405 }
3406 break;
3407 case 1:
3408 if ( commandData.params[vectorParams.begin()->second.lenParam].type.isValue() )
3409 {
3410 if ( isHandleType( commandData.params[vectorParams.begin()->first].type.type ) )
3411 {
3412 return generateCommandSet( definition,
3413 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3414 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, {} ) } );
3415 }
3416 }
3417 break;
3418 }
3419 break;
3420 case 1:
3421 if ( vectorParams.empty() )
3422 {
3423 if ( ( commandData.params[returnParams[0]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[0]].type.type ) &&
3424 !isStructureChainAnchor( commandData.params[returnParams[0]].type.type ) )
3425 {
3426 return generateCommandSet( definition,
3427 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3428 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ) } );
3429 }
3430 }
3431 break;
3432 }
3433 return "";
3434 }
3435
generateCommandResultSingleSuccessWithErrors(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3436 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors( std::string const & name,
3437 CommandData const & commandData,
3438 size_t initialSkipCount,
3439 bool definition ) const
3440 {
3441 std::vector<size_t> returnParams = determineReturnParams( commandData.params );
3442 switch ( returnParams.size() )
3443 {
3444 case 0: return generateCommandResultWithErrors0Return( name, commandData, initialSkipCount, definition ); break;
3445 case 1: return generateCommandResultSingleSuccessWithErrors1Return( name, commandData, initialSkipCount, definition, returnParams[0] ); break;
3446 case 2: return generateCommandResultSingleSuccessWithErrors2Return( name, commandData, initialSkipCount, definition, returnParams ); break;
3447 }
3448 return "";
3449 }
3450
generateCommandResultSingleSuccessWithErrors1Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3451 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1Return(
3452 std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3453 {
3454 if ( commandData.params[returnParam].type.type == "void" )
3455 {
3456 return generateCommandResultSingleSuccessWithErrors1ReturnVoid( name, commandData, initialSkipCount, definition, returnParam );
3457 }
3458 else if ( isHandleType( commandData.params[returnParam].type.type ) )
3459 {
3460 return generateCommandResultSingleSuccessWithErrors1ReturnHandle( name, commandData, initialSkipCount, definition, returnParam );
3461 }
3462 else if ( isStructureChainAnchor( commandData.params[returnParam].type.type ) )
3463 {
3464 return generateCommandResultSingleSuccessWithErrors1ReturnChain( name, commandData, initialSkipCount, definition, returnParam );
3465 }
3466 else
3467 {
3468 return generateCommandResultSingleSuccessWithErrors1ReturnValue( name, commandData, initialSkipCount, definition, returnParam );
3469 }
3470 }
3471
generateCommandResultSingleSuccessWithErrors1ReturnChain(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3472 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnChain(
3473 std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3474 {
3475 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3476 if ( vectorParams.empty() )
3477 {
3478 return generateCommandSet(
3479 definition,
3480 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3481 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3482 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::chained ) } );
3483 }
3484 return "";
3485 }
3486
generateCommandResultSingleSuccessWithErrors1ReturnHandle(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3487 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnHandle(
3488 std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3489 {
3490 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3491 switch ( vectorParams.size() )
3492 {
3493 case 0:
3494 return generateCommandSet(
3495 definition,
3496 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3497 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ) },
3498 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::unique ) } );
3499 break;
3500 case 1:
3501 return generateCommandResultSingleSuccessWithErrors1ReturnHandle1Vector(
3502 name, commandData, initialSkipCount, definition, returnParam, *vectorParams.begin() );
3503 break;
3504 case 2:
3505 return generateCommandResultSingleSuccessWithErrors1ReturnHandle2Vector( name, commandData, initialSkipCount, definition, returnParam, vectorParams );
3506 break;
3507 }
3508 return "";
3509 }
3510
3511 std::string
generateCommandResultSingleSuccessWithErrors1ReturnHandle1Vector(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam,std::pair<size_t,VectorParamData> const & vectorParamIndex) const3512 VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnHandle1Vector( std::string const & name,
3513 CommandData const & commandData,
3514 size_t initialSkipCount,
3515 bool definition,
3516 size_t returnParam,
3517 std::pair<size_t, VectorParamData> const & vectorParamIndex ) const
3518 {
3519 if ( returnParam == vectorParamIndex.first )
3520 {
3521 if ( isLenByStructMember( commandData.params[vectorParamIndex.first].len, commandData.params[vectorParamIndex.second.lenParam] ) )
3522 {
3523 return generateCommandSet(
3524 definition,
3525 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3526 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, { vectorParamIndex }, { returnParam } ),
3527 generateCommandEnhanced(
3528 name, commandData, initialSkipCount, definition, { vectorParamIndex }, { returnParam }, CommandFlavourFlagBits::withAllocator ) },
3529 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, { vectorParamIndex }, { returnParam }, CommandFlavourFlagBits::unique ),
3530 generateCommandEnhanced( name,
3531 commandData,
3532 initialSkipCount,
3533 definition,
3534 { vectorParamIndex },
3535 { returnParam },
3536 CommandFlavourFlagBits::unique | CommandFlavourFlagBits::withAllocator ) } );
3537 }
3538 }
3539 return "";
3540 }
3541
generateCommandResultSingleSuccessWithErrors1ReturnHandle2Vector(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam,std::map<size_t,VectorParamData> const & vectorParams) const3542 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnHandle2Vector( std::string const & name,
3543 CommandData const & commandData,
3544 size_t initialSkipCount,
3545 bool definition,
3546 size_t returnParam,
3547 std::map<size_t, VectorParamData> const & vectorParams ) const
3548 {
3549 if ( returnParam == std::next( vectorParams.begin() )->first )
3550 {
3551 if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
3552 {
3553 if ( commandData.params[vectorParams.begin()->second.lenParam].type.isValue() )
3554 {
3555 if ( ( commandData.params[vectorParams.begin()->first].type.type != "void" ) &&
3556 !isHandleType( commandData.params[vectorParams.begin()->first].type.type ) )
3557 {
3558 return generateCommandSet(
3559 definition,
3560 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3561 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3562 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::withAllocator ),
3563 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) },
3564 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::unique ),
3565 generateCommandEnhanced( name,
3566 commandData,
3567 initialSkipCount,
3568 definition,
3569 vectorParams,
3570 { returnParam },
3571 CommandFlavourFlagBits::unique | CommandFlavourFlagBits::withAllocator ),
3572 generateCommandEnhanced( name,
3573 commandData,
3574 initialSkipCount,
3575 definition,
3576 vectorParams,
3577 { returnParam },
3578 CommandFlavourFlagBits::singular | CommandFlavourFlagBits::unique ) } );
3579 }
3580 }
3581 }
3582 }
3583 return "";
3584 }
3585
generateCommandResultSingleSuccessWithErrors1ReturnValue(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3586 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnValue(
3587 std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3588 {
3589 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3590 switch ( vectorParams.size() )
3591 {
3592 case 0:
3593 return generateCommandSet( definition,
3594 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3595 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ) } );
3596 case 2:
3597 return generateCommandResultSingleSuccessWithErrors1ReturnValue2Vectors( name, commandData, initialSkipCount, definition, returnParam, vectorParams );
3598 break;
3599 }
3600 return "";
3601 }
3602
generateCommandResultSingleSuccessWithErrors1ReturnValue2Vectors(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam,std::map<size_t,VectorParamData> const & vectorParams) const3603 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnValue2Vectors( std::string const & name,
3604 CommandData const & commandData,
3605 size_t initialSkipCount,
3606 bool definition,
3607 size_t returnParam,
3608 std::map<size_t, VectorParamData> const & vectorParams ) const
3609 {
3610 if ( returnParam == std::next( vectorParams.begin() )->first )
3611 {
3612 if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
3613 {
3614 if ( commandData.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
3615 {
3616 if ( ( commandData.params[vectorParams.begin()->first].type.type != "void" ) &&
3617 !isHandleType( commandData.params[vectorParams.begin()->first].type.type ) &&
3618 !isStructureChainAnchor( commandData.params[vectorParams.begin()->first].type.type ) )
3619 {
3620 return generateCommandSet(
3621 definition,
3622 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3623 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3624 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::withAllocator ),
3625 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) } );
3626 }
3627 }
3628 }
3629 }
3630 return "";
3631 }
3632
generateCommandResultSingleSuccessWithErrors1ReturnVoid(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3633 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors1ReturnVoid(
3634 std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3635 {
3636 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3637 switch ( vectorParams.size() )
3638 {
3639 case 0:
3640 return generateCommandSet( definition,
3641 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3642 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ) } );
3643 break;
3644 case 1:
3645 if ( returnParam == vectorParams.begin()->first )
3646 {
3647 if ( commandData.params[vectorParams.begin()->second.lenParam].type.isValue() )
3648 {
3649 return generateCommandSet(
3650 definition,
3651 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3652 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3653 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) } );
3654 }
3655 }
3656 break;
3657 case 2:
3658 if ( returnParam == std::next( vectorParams.begin() )->first )
3659 {
3660 if ( vectorParams.begin()->second.lenParam != std::next( vectorParams.begin() )->second.lenParam )
3661 {
3662 if ( commandData.params[vectorParams.begin()->second.lenParam].type.isValue() )
3663 {
3664 if ( isHandleType( commandData.params[vectorParams.begin()->first].type.type ) )
3665 {
3666 if ( commandData.params[std::next( vectorParams.begin() )->second.lenParam].type.isValue() )
3667 {
3668 return generateCommandSet(
3669 definition,
3670 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3671 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3672 generateCommandEnhanced(
3673 name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) } );
3674 }
3675 }
3676 }
3677 }
3678 }
3679 break;
3680 }
3681 return "";
3682 }
3683
generateCommandResultSingleSuccessWithErrors2Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const3684 std::string VulkanHppGenerator::generateCommandResultSingleSuccessWithErrors2Return(
3685 std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, std::vector<size_t> const & returnParams ) const
3686 {
3687 if ( ( commandData.params[returnParams[0]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[0]].type.type ) &&
3688 !isStructureChainAnchor( commandData.params[returnParams[0]].type.type ) )
3689 {
3690 if ( ( commandData.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandData.params[returnParams[1]].type.type ) &&
3691 !isStructureChainAnchor( commandData.params[returnParams[1]].type.type ) )
3692 {
3693 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3694 if ( vectorParams.size() == 2 )
3695 {
3696 if ( returnParams[0] == std::next( vectorParams.begin() )->first )
3697 {
3698 if ( vectorParams.find( returnParams[1] ) == vectorParams.end() )
3699 {
3700 assert( ( returnParams[1] != vectorParams.begin()->second.lenParam ) && ( returnParams[1] != std::next( vectorParams.begin() )->second.lenParam ) );
3701 if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
3702 {
3703 if ( commandData.params[vectorParams.begin()->second.lenParam].type.isValue() )
3704 {
3705 if ( ( commandData.params[vectorParams.begin()->first].type.type != "void" ) &&
3706 !isHandleType( commandData.params[vectorParams.begin()->first].type.type ) &&
3707 !isStructureChainAnchor( commandData.params[vectorParams.begin()->first].type.type ) )
3708 {
3709 return generateCommandSet(
3710 definition,
3711 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3712 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
3713 generateCommandEnhanced(
3714 name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ),
3715 generateCommandEnhanced(
3716 name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::singular ) } );
3717 }
3718 }
3719 }
3720 }
3721 }
3722 }
3723 }
3724 }
3725 return "";
3726 }
3727
generateCommandResultWithErrors0Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3728 std::string VulkanHppGenerator::generateCommandResultWithErrors0Return( std::string const & name,
3729 CommandData const & commandData,
3730 size_t initialSkipCount,
3731 bool definition ) const
3732 {
3733 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3734 if ( vectorParams.empty() && determineConstPointerParams( commandData.params ).empty() )
3735 {
3736 return generateCommandSet( generateCommandStandard( name, commandData, initialSkipCount, definition ),
3737 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, {} ) );
3738 }
3739 else if ( allVectorSizesSupported( commandData.params, vectorParams ) )
3740 {
3741 return generateCommandSet( definition,
3742 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3743 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, {} ) } );
3744 }
3745 return "";
3746 }
3747
generateCommandSet(bool definition,std::string const & standard,std::vector<std::string> const & enhanced,std::vector<std::string> const & unique) const3748 std::string VulkanHppGenerator::generateCommandSet( bool definition,
3749 std::string const & standard,
3750 std::vector<std::string> const & enhanced,
3751 std::vector<std::string> const & unique ) const
3752 {
3753 assert( unique.empty() || ( enhanced.size() == unique.size() ) );
3754
3755 std::string commandSet = "\n" + standard;
3756 if ( !enhanced.empty() )
3757 {
3758 std::string separator = definition ? "\n" : "";
3759 commandSet += separator + "\n#ifndef VULKAN_HPP_DISABLE_ENHANCED_MODE\n";
3760 bool firstEnhanced = true;
3761 for ( auto const & e : enhanced )
3762 {
3763 if ( !firstEnhanced )
3764 {
3765 commandSet += separator + "\n";
3766 }
3767 firstEnhanced = false;
3768 commandSet += e;
3769 }
3770 if ( !unique.empty() )
3771 {
3772 commandSet += separator + "\n# ifndef VULKAN_HPP_NO_SMART_HANDLE\n";
3773 bool firstUnique = true;
3774 for ( auto const & u : unique )
3775 {
3776 if ( !firstUnique )
3777 {
3778 commandSet += separator + "\n";
3779 }
3780 firstUnique = false;
3781 commandSet += u;
3782 }
3783 commandSet += "\n# endif /* VULKAN_HPP_NO_SMART_HANDLE */";
3784 }
3785 commandSet += "\n#endif /* VULKAN_HPP_DISABLE_ENHANCED_MODE */";
3786 }
3787 commandSet += "\n";
3788 return commandSet;
3789 }
3790
generateCommandSet(std::string const & standard,std::string const & enhanced) const3791 std::string VulkanHppGenerator::generateCommandSet( std::string const & standard, std::string const & enhanced ) const
3792 {
3793 const std::string commandTemplate = R"(
3794 #ifdef VULKAN_HPP_DISABLE_ENHANCED_MODE
3795 ${commandStandard}
3796 #else
3797 ${commandEnhanced}
3798 #endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
3799 )";
3800
3801 return replaceWithMap( commandTemplate, std::map<std::string, std::string>( { { "commandEnhanced", enhanced }, { "commandStandard", standard } } ) );
3802 }
3803
3804 std::string
generateCommandStandard(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3805 VulkanHppGenerator::generateCommandStandard( std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition ) const
3806 {
3807 std::set<size_t> skippedParams = determineSkippedParams( commandData.params, initialSkipCount, {}, {}, false );
3808
3809 std::string argumentList = generateArgumentListStandard( commandData.params, skippedParams );
3810 std::string commandName = generateCommandName( name, commandData.params, initialSkipCount, m_tags );
3811 std::string nodiscard = ( 1 < commandData.successCodes.size() + commandData.errorCodes.size() ) ? "VULKAN_HPP_NODISCARD " : "";
3812 std::string returnType = stripPrefix( commandData.returnType, "Vk" );
3813
3814 if ( definition )
3815 {
3816 std::string functionBody = "d." + name + "( " + generateCallArgumentsStandard( commandData.handle, commandData.params ) + " )";
3817 if ( commandData.returnType.starts_with( "Vk" ) )
3818 {
3819 functionBody = "return static_cast<" + returnType + ">( " + functionBody + " )";
3820 }
3821 else if ( commandData.returnType != "void" )
3822 {
3823 functionBody = "return " + functionBody;
3824 }
3825
3826 std::string const functionTemplate =
3827 R"( template <typename Dispatch>
3828 ${nodiscard}VULKAN_HPP_INLINE ${returnType} ${className}${classSeparator}${commandName}( ${argumentList} )${const} VULKAN_HPP_NOEXCEPT
3829 {
3830 VULKAN_HPP_ASSERT( d.getVkHeaderVersion() == VK_HEADER_VERSION );
3831 ${functionBody};
3832 })";
3833
3834 return replaceWithMap( functionTemplate,
3835 { { "argumentList", argumentList },
3836 { "className", initialSkipCount ? stripPrefix( commandData.params[initialSkipCount - 1].type.type, "Vk" ) : "" },
3837 { "classSeparator", commandData.handle.empty() ? "" : "::" },
3838 { "commandName", commandName },
3839 { "const", commandData.handle.empty() ? "" : " const" },
3840 { "functionBody", functionBody },
3841 { "nodiscard", nodiscard },
3842 { "returnType", returnType } } );
3843 }
3844 else
3845 {
3846 std::string const functionTemplate =
3847 R"( template <typename Dispatch = VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>
3848 ${nodiscard}${returnType} ${commandName}( ${argumentList} VULKAN_HPP_DEFAULT_DISPATCHER_ASSIGNMENT )${const} VULKAN_HPP_NOEXCEPT;)";
3849
3850 return replaceWithMap( functionTemplate,
3851 { { "argumentList", argumentList },
3852 { "commandName", commandName },
3853 { "const", commandData.handle.empty() ? "" : " const" },
3854 { "nodiscard", nodiscard },
3855 { "returnType", returnType } } );
3856 }
3857 }
3858
3859 std::string
generateCommandValue(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3860 VulkanHppGenerator::generateCommandValue( std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition ) const
3861 {
3862 std::vector<size_t> returnParams = determineReturnParams( commandData.params );
3863 if ( returnParams.empty() )
3864 {
3865 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3866 if ( vectorParams.empty() && determineConstPointerParams( commandData.params ).empty() )
3867 {
3868 return generateCommandSet( definition, generateCommandStandard( name, commandData, initialSkipCount, definition ) );
3869 }
3870 else if ( vectorParams.size() <= 1 )
3871 {
3872 return generateCommandSet( definition,
3873 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3874 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ) } );
3875 }
3876 }
3877 return "";
3878 }
3879
3880 std::string
generateCommandVoid0Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition) const3881 VulkanHppGenerator::generateCommandVoid0Return( std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition ) const
3882 {
3883 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3884 if ( vectorParams.empty() && determineConstPointerParams( commandData.params ).empty() )
3885 {
3886 return generateCommandSet( definition, generateCommandStandard( name, commandData, initialSkipCount, definition ) );
3887 }
3888 else if ( allVectorSizesSupported( commandData.params, vectorParams ) )
3889 {
3890 // All the vectorParams have a counter by value, of type "uint32_t", "VkDeviceSize", or "VkSampleCountFlagBits" (!)
3891 return generateCommandSet( definition,
3892 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3893 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, {} ) } );
3894 }
3895 return "";
3896 }
3897
generateCommandVoid1Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,size_t returnParam) const3898 std::string VulkanHppGenerator::generateCommandVoid1Return(
3899 std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, size_t returnParam ) const
3900 {
3901 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
3902 if ( commandData.params[returnParam].type.postfix == "**" )
3903 {
3904 // get a pointer to something
3905 if ( commandData.params[returnParam].type.type == "void" )
3906 {
3907 if ( vectorParams.empty() )
3908 {
3909 return generateCommandSet( definition,
3910 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3911 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, { returnParam } ) } );
3912 }
3913 }
3914 }
3915 else if ( isHandleType( commandData.params[returnParam].type.type ) )
3916 {
3917 if ( vectorParams.empty() )
3918 {
3919 return generateCommandSet( definition,
3920 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3921 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, { returnParam } ) } );
3922 }
3923 }
3924 else if ( isStructureChainAnchor( commandData.params[returnParam].type.type ) )
3925 {
3926 if ( vectorParams.empty() )
3927 {
3928 return generateCommandSet(
3929 definition,
3930 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3931 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, { returnParam } ),
3932 generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, { returnParam }, CommandFlavourFlagBits::chained ) } );
3933 }
3934 }
3935 else if ( commandData.params[returnParam].type.type == "void" )
3936 {
3937 switch ( vectorParams.size() )
3938 {
3939 case 0:
3940 return generateCommandSet( definition,
3941 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3942 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ) } );
3943 case 1:
3944 if ( returnParam == vectorParams.begin()->first )
3945 {
3946 if ( name == stripPluralS( name, m_tags ) )
3947 {
3948 return generateCommandSet(
3949 definition,
3950 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3951 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::singular ) } );
3952 }
3953 }
3954 break;
3955 }
3956 }
3957 else
3958 {
3959 switch ( vectorParams.size() )
3960 {
3961 case 0:
3962 return generateCommandSet( definition,
3963 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3964 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, {}, { returnParam } ) } );
3965 break;
3966 case 1:
3967 if ( returnParam == vectorParams.begin()->first )
3968 {
3969 // you get a vector of stuff, with the size being one of the parameters
3970 return generateCommandSet(
3971 definition,
3972 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3973 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ),
3974 generateCommandEnhanced(
3975 name, commandData, initialSkipCount, definition, vectorParams, { returnParam }, CommandFlavourFlagBits::withAllocator ) } );
3976 }
3977 else
3978 {
3979 if ( !isHandleType( commandData.params[vectorParams.begin()->first].type.type ) &&
3980 !isStructureChainAnchor( commandData.params[vectorParams.begin()->first].type.type ) &&
3981 ( commandData.params[vectorParams.begin()->first].type.type != "void" ) )
3982 {
3983 if ( isLenByStructMember( commandData.params[vectorParams.begin()->first].len, commandData.params[vectorParams.begin()->second.lenParam] ) )
3984 {
3985 return generateCommandSet( definition,
3986 generateCommandStandard( name, commandData, initialSkipCount, definition ),
3987 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, { returnParam } ) } );
3988 }
3989 }
3990 }
3991 break;
3992 }
3993 }
3994 return "";
3995 }
3996
generateCommandVoid2Return(std::string const & name,CommandData const & commandData,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const3997 std::string VulkanHppGenerator::generateCommandVoid2Return(
3998 std::string const & name, CommandData const & commandData, size_t initialSkipCount, bool definition, std::vector<size_t> const & returnParams ) const
3999 {
4000 if ( commandData.params[returnParams[0]].type.type == "uint32_t" )
4001 {
4002 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandData.params );
4003 if ( vectorParams.size() == 1 )
4004 {
4005 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
4006 {
4007 if ( returnParams[1] == vectorParams.begin()->first )
4008 {
4009 if ( isStructureChainAnchor( commandData.params[returnParams[1]].type.type ) )
4010 {
4011 return generateCommandSet(
4012 definition,
4013 generateCommandStandard( name, commandData, initialSkipCount, definition ),
4014 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
4015 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ),
4016 generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::chained ),
4017 generateCommandEnhanced( name,
4018 commandData,
4019 initialSkipCount,
4020 definition,
4021 vectorParams,
4022 returnParams,
4023 CommandFlavourFlagBits::chained | CommandFlavourFlagBits::withAllocator ) } );
4024 }
4025 else if ( !isHandleType( commandData.params[returnParams[1]].type.type ) )
4026 {
4027 return generateCommandSet(
4028 definition,
4029 generateCommandStandard( name, commandData, initialSkipCount, definition ),
4030 { generateCommandEnhanced( name, commandData, initialSkipCount, definition, vectorParams, returnParams ),
4031 generateCommandEnhanced(
4032 name, commandData, initialSkipCount, definition, vectorParams, returnParams, CommandFlavourFlagBits::withAllocator ) } );
4033 }
4034 }
4035 }
4036 }
4037 }
4038 return "";
4039 }
4040
generateConstexprString(std::string const & structName) const4041 std::string VulkanHppGenerator::generateConstexprString( std::string const & structName ) const
4042 {
4043 // structs with a VkBaseInStructure and VkBaseOutStructure can't be a constexpr!
4044 bool isConstExpression = ( structName != "VkBaseInStructure" ) && ( structName != "VkBaseOutStructure" );
4045 return isConstExpression ? ( std::string( "VULKAN_HPP_CONSTEXPR" ) + ( ( containsUnion( structName ) || containsArray( structName ) ) ? "_14 " : " " ) ) : "";
4046 }
4047
generateDataDeclarations(CommandData const & commandData,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,std::set<size_t> const & templatedParams,CommandFlavourFlags flavourFlags,bool raii,std::vector<std::string> const & dataTypes,std::string const & dataType,std::string const & returnType,std::string const & returnVariable) const4048 std::string VulkanHppGenerator::generateDataDeclarations( CommandData const & commandData,
4049 std::vector<size_t> const & returnParams,
4050 std::map<size_t, VectorParamData> const & vectorParams,
4051 std::set<size_t> const & templatedParams,
4052 CommandFlavourFlags flavourFlags,
4053 bool raii,
4054 std::vector<std::string> const & dataTypes,
4055 std::string const & dataType,
4056 std::string const & returnType,
4057 std::string const & returnVariable ) const
4058 {
4059 assert( dataTypes.size() == returnParams.size() );
4060
4061 switch ( returnParams.size() )
4062 {
4063 case 0: return ""; // no returnParams -> no data declarations
4064 case 1:
4065 return generateDataDeclarations1Return(
4066 commandData, returnParams, vectorParams, templatedParams, flavourFlags, dataTypes, dataType, returnType, returnVariable );
4067 case 2:
4068 assert( !( flavourFlags & CommandFlavourFlagBits::unique ) );
4069 return generateDataDeclarations2Returns( commandData, returnParams, vectorParams, flavourFlags, raii, dataTypes, dataType, returnVariable );
4070 case 3:
4071 assert( ( vectorParams.size() == 2 ) && ( returnParams[0] == vectorParams.begin()->second.lenParam ) &&
4072 ( returnParams[1] == vectorParams.begin()->first ) && ( returnParams[2] == std::next( vectorParams.begin() )->first ) &&
4073 ( returnParams[0] == std::next( vectorParams.begin() )->second.lenParam ) && templatedParams.empty() &&
4074 !( flavourFlags & ( CommandFlavourFlagBits::chained | CommandFlavourFlagBits::singular | CommandFlavourFlagBits::unique ) ) );
4075 return generateDataDeclarations3Returns( commandData, returnParams, flavourFlags, raii, dataTypes );
4076 default: assert( false ); return "";
4077 }
4078 }
4079
generateDataDeclarations1Return(CommandData const & commandData,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,std::set<size_t> const & templatedParams,CommandFlavourFlags flavourFlags,std::vector<std::string> const & dataTypes,std::string const & dataType,std::string const & returnType,std::string const & returnVariable) const4080 std::string VulkanHppGenerator::generateDataDeclarations1Return( CommandData const & commandData,
4081 std::vector<size_t> const & returnParams,
4082 std::map<size_t, VectorParamData> const & vectorParams,
4083 std::set<size_t> const & templatedParams,
4084 CommandFlavourFlags flavourFlags,
4085 std::vector<std::string> const & dataTypes,
4086 std::string const & dataType,
4087 std::string const & returnType,
4088 std::string const & returnVariable ) const
4089 {
4090 auto vectorParamIt = vectorParams.find( returnParams[0] );
4091 if ( !( flavourFlags & CommandFlavourFlagBits::chained ) )
4092 {
4093 if ( ( vectorParamIt == vectorParams.end() ) || ( flavourFlags & CommandFlavourFlagBits::singular ) )
4094 {
4095 std::string const dataDeclarationsTemplate = R"(${returnType} ${returnVariable};)";
4096
4097 return replaceWithMap( dataDeclarationsTemplate, { { "returnType", dataType }, { "returnVariable", returnVariable } } );
4098 }
4099 else
4100 {
4101 std::string allocator = stripPrefix( dataTypes[0], "VULKAN_HPP_NAMESPACE::" ) + "Allocator";
4102 std::string vectorAllocator = ( ( flavourFlags & CommandFlavourFlagBits::withAllocator ) && !( flavourFlags & CommandFlavourFlagBits::unique ) )
4103 ? ( ", " + startLowerCase( allocator ) )
4104 : "";
4105 std::string vectorSize = getVectorSize( commandData.params, vectorParams, returnParams[0], dataTypes[0], templatedParams );
4106
4107 std::string const dataDeclarationsTemplate = R"(${dataType} ${returnVariable}( ${vectorSize}${vectorAllocator} );)";
4108
4109 return replaceWithMap(
4110 dataDeclarationsTemplate,
4111 { { "dataType", dataType }, { "returnVariable", returnVariable }, { "vectorAllocator", vectorAllocator }, { "vectorSize", vectorSize } } );
4112 }
4113 }
4114 else
4115 {
4116 assert( ( vectorParamIt == vectorParams.end() ) || ( flavourFlags & CommandFlavourFlagBits::singular ) );
4117
4118 std::string dataVariable = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
4119
4120 std::string const dataDeclarationsTemplate = R"(${returnType} ${returnVariable};
4121 ${dataType} & ${dataVariable} = ${returnVariable}.template get<${dataType}>();)";
4122
4123 return replaceWithMap( dataDeclarationsTemplate,
4124 { { "dataType", dataTypes[0] },
4125 { "dataVariable", dataVariable },
4126 { "returnType", ( commandData.returnType == "void" ) ? returnType : "StructureChain<X, Y, Z...>" },
4127 { "returnVariable", returnVariable } } );
4128 }
4129 }
4130
generateDataDeclarations2Returns(CommandData const & commandData,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,CommandFlavourFlags flavourFlags,bool raii,std::vector<std::string> const & dataTypes,std::string const & dataType,std::string const & returnVariable) const4131 std::string VulkanHppGenerator::generateDataDeclarations2Returns( CommandData const & commandData,
4132 std::vector<size_t> const & returnParams,
4133 std::map<size_t, VectorParamData> const & vectorParams,
4134 CommandFlavourFlags flavourFlags,
4135 bool raii,
4136 std::vector<std::string> const & dataTypes,
4137 std::string const & dataType,
4138 std::string const & returnVariable ) const
4139 {
4140 bool chained = flavourFlags & CommandFlavourFlagBits::chained;
4141 bool singular = flavourFlags & CommandFlavourFlagBits::singular;
4142 bool withAllocator = flavourFlags & CommandFlavourFlagBits::withAllocator;
4143
4144 switch ( vectorParams.size() )
4145 {
4146 case 0:
4147 assert( !singular && !chained );
4148 {
4149 std::string firstDataVariable = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
4150 std::string secondDataVariable = startLowerCase( stripPrefix( commandData.params[returnParams[1]].name, "p" ) );
4151
4152 std::string const dataDeclarationTemplate = R"(std::pair<${firstDataType},${secondDataType}> data;
4153 ${firstDataType} & ${firstDataVariable} = data.first;
4154 ${secondDataType} & ${secondDataVariable} = data.second;)";
4155
4156 return replaceWithMap( dataDeclarationTemplate,
4157 { { "firstDataType", dataTypes[0] },
4158 { "firstDataVariable", firstDataVariable },
4159 { "secondDataType", dataTypes[1] },
4160 { "secondDataVariable", secondDataVariable } } );
4161 }
4162 break;
4163 case 1:
4164 assert( ( returnParams[0] == vectorParams.begin()->second.lenParam ) && ( returnParams[1] == vectorParams.begin()->first ) && !singular );
4165 {
4166 std::string counterVariable = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
4167 if ( !chained )
4168 {
4169 std::string vectorAllocator = withAllocator ? ( "( " + startLowerCase( stripPrefix( dataTypes[1], "VULKAN_HPP_NAMESPACE::" ) ) + "Allocator )" ) : "";
4170
4171 std::string const dataDeclarationTemplate = R"(${returnType} ${returnVariable}${vectorAllocator};
4172 ${counterType} ${counterVariable};)";
4173
4174 return replaceWithMap( dataDeclarationTemplate,
4175 { { "counterType", dataTypes[0] },
4176 { "counterVariable", counterVariable },
4177 { "returnType", dataType },
4178 { "returnVariable", returnVariable },
4179 { "vectorAllocator", vectorAllocator } } );
4180 }
4181 else
4182 {
4183 std::string structureChainAllocator = raii ? "" : ", StructureChainAllocator";
4184 std::string structureChainInitializer = withAllocator ? ( "( structureChainAllocator )" ) : "";
4185 std::string vectorVariable = startLowerCase( stripPrefix( commandData.params[returnParams[1]].name, "p" ) );
4186
4187 std::string const dataDeclarationTemplate =
4188 R"(std::vector<StructureChain${structureChainAllocator}> structureChains${structureChainInitializer};
4189 std::vector<${vectorElementType}> ${vectorVariable};
4190 ${counterType} ${counterVariable};)";
4191
4192 return replaceWithMap( dataDeclarationTemplate,
4193 {
4194 { "counterType", dataTypes[0] },
4195 { "counterVariable", counterVariable },
4196 { "structureChainAllocator", structureChainAllocator },
4197 { "structureChainInitializer", structureChainInitializer },
4198 { "vectorElementType", dataTypes[1] },
4199 { "vectorVariable", vectorVariable },
4200 } );
4201 }
4202 }
4203 break;
4204 case 2:
4205 assert( ( returnParams[0] == std::next( vectorParams.begin() )->first ) && ( vectorParams.find( returnParams[1] ) == vectorParams.end() ) && !chained );
4206 {
4207 std::string firstDataVariable = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
4208 std::string secondDataVariable = startLowerCase( stripPrefix( commandData.params[returnParams[1]].name, "p" ) );
4209 if ( singular )
4210 {
4211 firstDataVariable = stripPluralS( firstDataVariable, m_tags );
4212
4213 std::string const dataDeclarationTemplate = R"(std::pair<${firstDataType},${secondDataType}> data;
4214 ${firstDataType} & ${firstDataVariable} = data.first;
4215 ${secondDataType} & ${secondDataVariable} = data.second;)";
4216
4217 return replaceWithMap( dataDeclarationTemplate,
4218 { { "firstDataType", dataTypes[0] },
4219 { "firstDataVariable", firstDataVariable },
4220 { "secondDataType", dataTypes[1] },
4221 { "secondDataVariable", secondDataVariable } } );
4222 }
4223 else
4224 {
4225 std::string allocatorType = raii ? "" : ( startUpperCase( stripPrefix( dataTypes[0], "VULKAN_HPP_NAMESPACE::" ) ) + "Allocator" );
4226 std::string allocateInitializer = withAllocator ? ( ", " + startLowerCase( allocatorType ) ) : "";
4227 if ( !raii )
4228 {
4229 allocatorType = ", " + allocatorType;
4230 }
4231 std::string vectorSize = startLowerCase( stripPrefix( commandData.params[vectorParams.begin()->first].name, "p" ) ) + ".size()";
4232
4233 std::string const dataDeclarationTemplate =
4234 R"(std::pair<std::vector<${firstDataType}${allocatorType}>,${secondDataType}> data( std::piecewise_construct, std::forward_as_tuple( ${vectorSize}${allocateInitializer} ), std::forward_as_tuple( 0 ) );
4235 std::vector<${firstDataType}${allocatorType}> & ${firstDataVariable} = data.first;
4236 ${secondDataType} & ${secondDataVariable} = data.second;)";
4237
4238 return replaceWithMap( dataDeclarationTemplate,
4239 { { "allocateInitializer", allocateInitializer },
4240 { "allocatorType", allocatorType },
4241 { "firstDataType", dataTypes[0] },
4242 { "firstDataVariable", firstDataVariable },
4243 { "secondDataType", dataTypes[1] },
4244 { "secondDataVariable", secondDataVariable },
4245 { "vectorSize", vectorSize } } );
4246 }
4247 }
4248 break;
4249 default: assert( false ); return "";
4250 }
4251 }
4252
generateDataDeclarations3Returns(CommandData const & commandData,std::vector<size_t> const & returnParams,CommandFlavourFlags flavourFlags,bool raii,std::vector<std::string> const & dataTypes) const4253 std::string VulkanHppGenerator::generateDataDeclarations3Returns( CommandData const & commandData,
4254 std::vector<size_t> const & returnParams,
4255 CommandFlavourFlags flavourFlags,
4256 bool raii,
4257 std::vector<std::string> const & dataTypes ) const
4258 {
4259 std::string counterVariable = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
4260 std::string firstVectorVariable = startLowerCase( stripPrefix( commandData.params[returnParams[1]].name, "p" ) );
4261 std::string secondVectorVariable = startLowerCase( stripPrefix( commandData.params[returnParams[2]].name, "p" ) );
4262 std::string firstVectorAllocatorType, secondVectorAllocatorType, pairConstructor;
4263 if ( !raii )
4264 {
4265 firstVectorAllocatorType = startUpperCase( stripPrefix( dataTypes[1], "VULKAN_HPP_NAMESPACE::" ) ) + "Allocator";
4266 secondVectorAllocatorType = startUpperCase( stripPrefix( dataTypes[2], "VULKAN_HPP_NAMESPACE::" ) ) + "Allocator";
4267 pairConstructor = ( flavourFlags & CommandFlavourFlagBits::withAllocator )
4268 ? ( "( std::piecewise_construct, std::forward_as_tuple( " + startLowerCase( firstVectorAllocatorType ) + " ), std::forward_as_tuple( " +
4269 startLowerCase( secondVectorAllocatorType ) + " ) )" )
4270 : "";
4271 firstVectorAllocatorType = ", " + firstVectorAllocatorType;
4272 secondVectorAllocatorType = ", " + secondVectorAllocatorType;
4273 }
4274
4275 std::string const dataDeclarationsTemplate =
4276 R"(std::pair<std::vector<${firstVectorElementType}${firstVectorAllocatorType}>, std::vector<${secondVectorElementType}${secondVectorAllocatorType}>> data${pairConstructor};
4277 std::vector<${firstVectorElementType}${firstVectorAllocatorType}> & ${firstVectorVariable} = data.first;
4278 std::vector<${secondVectorElementType}${secondVectorAllocatorType}> & ${secondVectorVariable} = data.second;
4279 ${counterType} ${counterVariable};)";
4280
4281 return replaceWithMap( dataDeclarationsTemplate,
4282 { { "counterType", dataTypes[0] },
4283 { "counterVariable", counterVariable },
4284 { "firstVectorAllocatorType", firstVectorAllocatorType },
4285 { "firstVectorElementType", dataTypes[1] },
4286 { "firstVectorVariable", firstVectorVariable },
4287 { "pairConstructor", pairConstructor },
4288 { "secondVectorAllocatorType", secondVectorAllocatorType },
4289 { "secondVectorElementType", dataTypes[2] },
4290 { "secondVectorVariable", secondVectorVariable } } );
4291 }
4292
generateDataPreparation(CommandData const & commandData,size_t initialSkipCount,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,std::set<size_t> const & templatedParams,CommandFlavourFlags flavourFlags,bool enumerating) const4293 std::string VulkanHppGenerator::generateDataPreparation( CommandData const & commandData,
4294 size_t initialSkipCount,
4295 std::vector<size_t> const & returnParams,
4296 std::map<size_t, VectorParamData> const & vectorParams,
4297 std::set<size_t> const & templatedParams,
4298 CommandFlavourFlags flavourFlags,
4299 bool enumerating ) const
4300 {
4301 bool chained = flavourFlags & CommandFlavourFlagBits::chained;
4302 bool singular = flavourFlags & CommandFlavourFlagBits::singular;
4303 bool unique = flavourFlags & CommandFlavourFlagBits::unique;
4304
4305 auto vectorParamIt = ( 1 < returnParams.size() ) ? vectorParams.find( returnParams[1] ) : vectorParams.end();
4306 if ( vectorParamIt != vectorParams.end() )
4307 {
4308 assert( !unique );
4309
4310 std::string vectorName = startLowerCase( stripPrefix( commandData.params[vectorParamIt->first].name, "p" ) );
4311
4312 if ( chained )
4313 {
4314 assert( !singular );
4315 assert( templatedParams.empty() );
4316 assert( returnParams.size() == 2 );
4317 assert( vectorParams.find( returnParams[0] ) == vectorParams.end() );
4318 assert( ( vectorParamIt != vectorParams.end() ) && ( vectorParamIt->second.lenParam == returnParams[0] ) );
4319
4320 std::string vectorElementType = stripPostfix( commandData.params[vectorParamIt->first].type.compose( "VULKAN_HPP_NAMESPACE" ), " *" );
4321
4322 if ( enumerating )
4323 {
4324 std::string const dataPreparationTemplate =
4325 R"(VULKAN_HPP_ASSERT( ${counterName} <= ${vectorName}.size() );
4326 if ( ${counterName} < ${vectorName}.size() )
4327 {
4328 structureChains.resize( ${counterName} );
4329 }
4330 for ( ${counterType} i = 0; i < ${counterName}; i++ )
4331 {
4332 structureChains[i].template get<${vectorElementType}>() = ${vectorName}[i];
4333 })";
4334
4335 return replaceWithMap( dataPreparationTemplate,
4336 { { "counterName", startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) ) },
4337 { "counterType", commandData.params[vectorParamIt->second.lenParam].type.type },
4338 { "vectorElementType", vectorElementType },
4339 { "vectorName", vectorName } } );
4340 }
4341 else
4342 {
4343 std::string const dataPreparationTemplate =
4344 R"(for ( ${counterType} i = 0; i < ${counterName}; i++ )
4345 {
4346 structureChains[i].template get<${vectorElementType}>() = ${vectorName}[i];
4347 })";
4348
4349 return replaceWithMap( dataPreparationTemplate,
4350 { { "counterName", startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) ) },
4351 { "counterType", commandData.params[vectorParamIt->second.lenParam].type.type },
4352 { "vectorElementType", vectorElementType },
4353 { "vectorName", vectorName } } );
4354 }
4355 }
4356 else if ( enumerating )
4357 {
4358 assert( !singular );
4359 assert( ( vectorParams.size() != 2 ) ||
4360 ( ( vectorParams.begin()->first == returnParams[1] ) && ( vectorParams.begin()->second.lenParam == returnParams[0] ) &&
4361 ( std::next( vectorParams.begin() )->first == returnParams[2] ) &&
4362 ( std::next( vectorParams.begin() )->second.lenParam == returnParams[0] ) ) );
4363
4364 std::string resizes;
4365 for ( auto const & vp : vectorParams )
4366 {
4367 assert( ( std::find( returnParams.begin(), returnParams.end(), vp.first ) != returnParams.end() ) &&
4368 ( std::find( returnParams.begin(), returnParams.end(), vp.second.lenParam ) != returnParams.end() ) );
4369 resizes += startLowerCase( stripPrefix( commandData.params[vp.first].name, "p" ) ) + ".resize( " +
4370 startLowerCase( stripPrefix( commandData.params[vp.second.lenParam].name, "p" ) ) + " );\n";
4371 }
4372 resizes.pop_back();
4373
4374 std::string const dataPreparationTemplate =
4375 R"(VULKAN_HPP_ASSERT( ${counterName} <= ${vectorName}.size() );
4376 if ( ${counterName} < ${vectorName}.size() )
4377 {
4378 ${resizes}
4379 })";
4380
4381 return replaceWithMap( dataPreparationTemplate,
4382 { { "counterName", startLowerCase( stripPrefix( commandData.params[vectorParamIt->second.lenParam].name, "p" ) ) },
4383 { "resizes", resizes },
4384 { "vectorName", vectorName } } );
4385 }
4386 }
4387 else if ( unique && !singular && ( returnParams.size() == 1 ) && ( vectorParams.find( returnParams[0] ) != vectorParams.end() ) )
4388 {
4389 assert( !enumerating );
4390 std::string className = initialSkipCount ? stripPrefix( commandData.params[initialSkipCount - 1].type.type, "Vk" ) : "";
4391 std::string deleterDefinition;
4392 std::vector<std::string> lenParts = tokenize( commandData.params[returnParams[0]].len, "->" );
4393 switch ( lenParts.size() )
4394 {
4395 case 1: deleterDefinition = "ObjectDestroy<" + className + ", Dispatch> deleter( *this, allocator, d )"; break;
4396 case 2:
4397 {
4398 auto vpiIt = vectorParams.find( returnParams[0] );
4399 assert( vpiIt != vectorParams.end() );
4400 std::string poolType, poolName;
4401 std::tie( poolType, poolName ) = getPoolTypeAndName( commandData.params[vpiIt->second.lenParam].type.type );
4402 assert( !poolType.empty() );
4403 poolType = stripPrefix( poolType, "Vk" );
4404 poolName = startLowerCase( stripPrefix( lenParts[0], "p" ) ) + "." + poolName;
4405 deleterDefinition = "PoolFree<" + className + ", " + poolType + ", Dispatch> deleter( *this, " + poolName + ", d )";
4406 }
4407 break;
4408 }
4409
4410 std::string handleType = stripPrefix( commandData.params[returnParams[0]].type.type, "Vk" );
4411 std::string uniqueVectorName = "unique" + stripPrefix( commandData.params[returnParams[0]].name, "p" );
4412 std::string vectorAllocator = ( flavourFlags & CommandFlavourFlagBits::withAllocator ) ? ( "( " + startLowerCase( handleType ) + "Allocator )" ) : "";
4413 std::string vectorName = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
4414 std::string elementName = stripPluralS( vectorName, m_tags );
4415 std::string vectorSize = getVectorSize( commandData.params, vectorParams, returnParams[0], commandData.params[returnParams[0]].type.type, templatedParams );
4416
4417 std::string const dataPreparationTemplate =
4418 R"(std::vector<UniqueHandle<VULKAN_HPP_NAMESPACE::${handleType}, Dispatch>, ${handleType}Allocator> ${uniqueVectorName}${vectorAllocator};
4419 ${uniqueVectorName}.reserve( ${vectorSize} );
4420 ${deleterDefinition};
4421 for ( auto const & ${elementName} : ${vectorName} )
4422 {
4423 ${uniqueVectorName}.push_back( UniqueHandle<${handleType}, Dispatch>( ${elementName}, deleter ) );
4424 })";
4425
4426 return replaceWithMap( dataPreparationTemplate,
4427 { { "elementName", elementName },
4428 { "deleterDefinition", deleterDefinition },
4429 { "handleType", handleType },
4430 { "uniqueVectorName", uniqueVectorName },
4431 { "vectorAllocator", vectorAllocator },
4432 { "vectorName", vectorName },
4433 { "vectorSize", vectorSize } } );
4434 }
4435 return "";
4436 }
4437
generateDataSizeChecks(CommandData const & commandData,std::vector<size_t> const & returnParams,std::vector<std::string> const & returnParamTypes,std::map<size_t,VectorParamData> const & vectorParams,std::set<size_t> const & templatedParams,bool singular) const4438 std::string VulkanHppGenerator::generateDataSizeChecks( CommandData const & commandData,
4439 std::vector<size_t> const & returnParams,
4440 std::vector<std::string> const & returnParamTypes,
4441 std::map<size_t, VectorParamData> const & vectorParams,
4442 std::set<size_t> const & templatedParams,
4443 bool singular ) const
4444 {
4445 assert( returnParams.size() == returnParamTypes.size() );
4446 std::string dataSizeChecks;
4447 if ( !singular )
4448 {
4449 const std::string dataSizeCheckTemplate = R"( VULKAN_HPP_ASSERT( ${dataSize} % sizeof( ${dataType} ) == 0 );)";
4450 for ( size_t i = 0; i < returnParams.size(); i++ )
4451 {
4452 auto vectorParamIt = vectorParams.find( returnParams[i] );
4453 if ( ( vectorParamIt != vectorParams.end() ) && ( templatedParams.find( returnParams[i] ) != templatedParams.end() ) &&
4454 ( std::find( returnParams.begin(), returnParams.end(), vectorParamIt->second.lenParam ) == returnParams.end() ) )
4455 {
4456 dataSizeChecks += replaceWithMap( dataSizeCheckTemplate,
4457 { { "dataSize", commandData.params[vectorParamIt->second.lenParam].name }, { "dataType", returnParamTypes[i] } } );
4458 }
4459 }
4460 }
4461
4462 return dataSizeChecks;
4463 }
4464
generateDispatchLoaderDynamic() const4465 std::string VulkanHppGenerator::generateDispatchLoaderDynamic() const
4466 {
4467 const std::string dispatchLoaderDynamicTemplate = R"(
4468 using PFN_dummy = void ( * )();
4469
4470 class DispatchLoaderDynamic : public DispatchLoaderBase
4471 {
4472 public:
4473 ${commandMembers}
4474
4475 public:
4476 DispatchLoaderDynamic() VULKAN_HPP_NOEXCEPT = default;
4477 DispatchLoaderDynamic( DispatchLoaderDynamic const & rhs ) VULKAN_HPP_NOEXCEPT = default;
4478
4479 DispatchLoaderDynamic(PFN_vkGetInstanceProcAddr getInstanceProcAddr) VULKAN_HPP_NOEXCEPT
4480 {
4481 init(getInstanceProcAddr);
4482 }
4483
4484 void init( PFN_vkGetInstanceProcAddr getInstanceProcAddr ) VULKAN_HPP_NOEXCEPT
4485 {
4486 VULKAN_HPP_ASSERT(getInstanceProcAddr);
4487
4488 vkGetInstanceProcAddr = getInstanceProcAddr;
4489
4490 ${initialCommandAssignments}
4491 }
4492
4493 // This interface does not require a linked vulkan library.
4494 DispatchLoaderDynamic( VkInstance instance,
4495 PFN_vkGetInstanceProcAddr getInstanceProcAddr,
4496 VkDevice device = {},
4497 PFN_vkGetDeviceProcAddr getDeviceProcAddr = nullptr ) VULKAN_HPP_NOEXCEPT
4498 {
4499 init( instance, getInstanceProcAddr, device, getDeviceProcAddr );
4500 }
4501
4502 // This interface does not require a linked vulkan library.
4503 void init( VkInstance instance,
4504 PFN_vkGetInstanceProcAddr getInstanceProcAddr,
4505 VkDevice device = {},
4506 PFN_vkGetDeviceProcAddr /*getDeviceProcAddr*/ = nullptr ) VULKAN_HPP_NOEXCEPT
4507 {
4508 VULKAN_HPP_ASSERT(instance && getInstanceProcAddr);
4509 vkGetInstanceProcAddr = getInstanceProcAddr;
4510 init( VULKAN_HPP_NAMESPACE::Instance(instance) );
4511 if (device) {
4512 init( VULKAN_HPP_NAMESPACE::Device(device) );
4513 }
4514 }
4515
4516 void init( VULKAN_HPP_NAMESPACE::Instance instanceCpp ) VULKAN_HPP_NOEXCEPT
4517 {
4518 VkInstance instance = static_cast<VkInstance>(instanceCpp);
4519
4520 ${instanceCommandAssignments}
4521 }
4522
4523 void init( VULKAN_HPP_NAMESPACE::Device deviceCpp ) VULKAN_HPP_NOEXCEPT
4524 {
4525 VkDevice device = static_cast<VkDevice>(deviceCpp);
4526
4527 ${deviceCommandAssignments}
4528 }
4529
4530 template <typename DynamicLoader>
4531 void init(VULKAN_HPP_NAMESPACE::Instance const & instance, VULKAN_HPP_NAMESPACE::Device const & device, DynamicLoader const & dl) VULKAN_HPP_NOEXCEPT
4532 {
4533 PFN_vkGetInstanceProcAddr getInstanceProcAddr = dl.template getProcAddress<PFN_vkGetInstanceProcAddr>("vkGetInstanceProcAddr");
4534 PFN_vkGetDeviceProcAddr getDeviceProcAddr = dl.template getProcAddress<PFN_vkGetDeviceProcAddr>("vkGetDeviceProcAddr");
4535 init(static_cast<VkInstance>(instance), getInstanceProcAddr, static_cast<VkDevice>(device), device ? getDeviceProcAddr : nullptr);
4536 }
4537
4538 template <typename DynamicLoader
4539 #if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
4540 = VULKAN_HPP_NAMESPACE::DynamicLoader
4541 #endif
4542 >
4543 void init(VULKAN_HPP_NAMESPACE::Instance const & instance, VULKAN_HPP_NAMESPACE::Device const & device) VULKAN_HPP_NOEXCEPT
4544 {
4545 static DynamicLoader dl;
4546 init(instance, device, dl);
4547 }
4548 };)";
4549
4550 std::string commandMembers, deviceCommandAssignments, initialCommandAssignments, instanceCommandAssignments;
4551 std::set<std::string> listedCommands; // some commands are listed with more than one extension!
4552 for ( auto const & feature : m_features )
4553 {
4554 appendDispatchLoaderDynamicCommands( feature.second.requireData,
4555 listedCommands,
4556 feature.first,
4557 commandMembers,
4558 initialCommandAssignments,
4559 instanceCommandAssignments,
4560 deviceCommandAssignments );
4561 }
4562 for ( auto const & extIt : m_extensionsByNumber )
4563 {
4564 appendDispatchLoaderDynamicCommands( extIt.second->second.requireData,
4565 listedCommands,
4566 extIt.second->first,
4567 commandMembers,
4568 initialCommandAssignments,
4569 instanceCommandAssignments,
4570 deviceCommandAssignments );
4571 }
4572
4573 return replaceWithMap( dispatchLoaderDynamicTemplate,
4574 { { "commandMembers", commandMembers },
4575 { "deviceCommandAssignments", deviceCommandAssignments },
4576 { "initialCommandAssignments", initialCommandAssignments },
4577 { "instanceCommandAssignments", instanceCommandAssignments } } );
4578 }
4579
generateDispatchLoaderStatic() const4580 std::string VulkanHppGenerator::generateDispatchLoaderStatic() const
4581 {
4582 const std::string dispatchLoaderStaticTemplate = R"(
4583 #if !defined( VK_NO_PROTOTYPES )
4584 class DispatchLoaderStatic : public DispatchLoaderBase
4585 {
4586 public:
4587 ${commands}
4588 };
4589 #endif
4590 )";
4591
4592 std::string commands;
4593 std::set<std::string> listedCommands;
4594 for ( auto const & feature : m_features )
4595 {
4596 commands += generateDispatchLoaderStaticCommands( feature.second.requireData, listedCommands, feature.first );
4597 }
4598 for ( auto const & extIt : m_extensionsByNumber )
4599 {
4600 commands += generateDispatchLoaderStaticCommands( extIt.second->second.requireData, listedCommands, extIt.second->first );
4601 }
4602
4603 return replaceWithMap( dispatchLoaderStaticTemplate, { { "commands", commands } } );
4604 }
4605
generateDestroyCommand(std::string const & name,CommandData const & commandData) const4606 std::string VulkanHppGenerator::generateDestroyCommand( std::string const & name, CommandData const & commandData ) const
4607 {
4608 // special handling for destroy functions, filter out alias functions
4609 std::string commandName = generateCommandName( name, commandData.params, 1, m_tags );
4610 if ( commandData.alias.empty() && ( ( ( name.substr( 2, 7 ) == "Destroy" ) && ( commandName != "destroy" ) ) || ( name.substr( 2, 4 ) == "Free" ) ||
4611 ( name == "vkReleasePerformanceConfigurationINTEL" ) ) )
4612 {
4613 assert( 1 < commandData.params.size() );
4614 // make sure, the object to destroy/free/release is not optional in the shortened version!
4615 CommandData localCommandData = commandData;
4616 localCommandData.params[1].optional = false;
4617
4618 std::string destroyCommandString = generateCommand( name, localCommandData, 1, false );
4619 std::string shortenedName;
4620 if ( name.substr( 2, 7 ) == "Destroy" )
4621 {
4622 shortenedName = "destroy";
4623 }
4624 else if ( name.substr( 2, 4 ) == "Free" )
4625 {
4626 // enclose "free" in parenthesis to prevent interference with MSVC debug free
4627 shortenedName = "( free )";
4628 }
4629 else
4630 {
4631 assert( name == "vkReleasePerformanceConfigurationINTEL" );
4632 shortenedName = "release";
4633 }
4634 size_t pos = destroyCommandString.find( commandName );
4635 while ( pos != std::string::npos )
4636 {
4637 destroyCommandString.replace( pos, commandName.length(), shortenedName );
4638 pos = destroyCommandString.find( commandName, pos );
4639 }
4640 // we need to remove the default argument for the first argument, to prevent ambiguities!
4641 assert( 1 < localCommandData.params.size() );
4642 pos = destroyCommandString.find( localCommandData.params[1].name ); // skip the standard version of the function
4643 assert( pos != std::string::npos );
4644 pos = destroyCommandString.find( localCommandData.params[1].name,
4645 pos + 1 ); // get the argument to destroy in the advanced version
4646 assert( pos != std::string::npos );
4647 pos = destroyCommandString.find( " VULKAN_HPP_DEFAULT_ARGUMENT_ASSIGNMENT", pos );
4648 if ( pos != std::string::npos )
4649 {
4650 destroyCommandString.erase( pos, strlen( " VULKAN_HPP_DEFAULT_ARGUMENT_ASSIGNMENT" ) );
4651 }
4652 return "\n" + destroyCommandString;
4653 }
4654 return "";
4655 }
4656
generateDispatchLoaderDynamicCommandAssignment(std::string const & commandName,CommandData const & commandData,std::string const & firstArg) const4657 std::string VulkanHppGenerator::generateDispatchLoaderDynamicCommandAssignment( std::string const & commandName,
4658 CommandData const & commandData,
4659 std::string const & firstArg ) const
4660 {
4661 if ( commandName == "vkGetInstanceProcAddr" )
4662 {
4663 // Don't overwite vkGetInstanceProcAddr with NULL.
4664 return "";
4665 }
4666 std::string str = " " + commandName + " = PFN_" + commandName + "( vkGet" + ( ( firstArg == "device" ) ? "Device" : "Instance" ) + "ProcAddr( " +
4667 firstArg + ", \"" + commandName + "\" ) );\n";
4668 // if this is an alias'ed function, use it as a fallback for the original one
4669 if ( !commandData.alias.empty() )
4670 {
4671 str += " if ( !" + commandData.alias + " ) " + commandData.alias + " = " + commandName + ";\n";
4672 }
4673 return str;
4674 }
4675
generateDispatchLoaderStaticCommands(std::vector<RequireData> const & requireData,std::set<std::string> & listedCommands,std::string const & title) const4676 std::string VulkanHppGenerator::generateDispatchLoaderStaticCommands( std::vector<RequireData> const & requireData,
4677 std::set<std::string> & listedCommands,
4678 std::string const & title ) const
4679 {
4680 std::string str;
4681 for ( auto const & require : requireData )
4682 {
4683 for ( auto const & command : require.commands )
4684 {
4685 // some commands are listed for multiple extensions !
4686 if ( listedCommands.insert( command ).second )
4687 {
4688 auto commandIt = m_commands.find( command );
4689 assert( commandIt != m_commands.end() );
4690
4691 str += "\n";
4692 std::string parameterList, parameters;
4693 assert( !commandIt->second.params.empty() );
4694 for ( auto param : commandIt->second.params )
4695 {
4696 parameterList += param.type.compose( "" ) + " " + param.name + generateCArraySizes( param.arraySizes ) + ", ";
4697 parameters += param.name + ", ";
4698 }
4699 assert( parameterList.ends_with( ", " ) && parameters.ends_with( ", " ) );
4700 parameterList.resize( parameterList.size() - 2 );
4701 parameters.resize( parameters.size() - 2 );
4702
4703 const std::string commandTemplate = R"(
4704 ${returnType} ${commandName}( ${parameterList} ) const VULKAN_HPP_NOEXCEPT
4705 {
4706 return ::${commandName}( ${parameters} );
4707 }
4708 )";
4709
4710 str += replaceWithMap( commandTemplate,
4711 { { "commandName", commandIt->first },
4712 { "parameterList", parameterList },
4713 { "parameters", parameters },
4714 { "returnType", commandIt->second.returnType } } );
4715 }
4716 }
4717 }
4718 return addTitleAndProtection( title, str );
4719 }
4720
generateEnum(std::pair<std::string,EnumData> const & enumData,std::string const & surroundingProtect) const4721 std::string VulkanHppGenerator::generateEnum( std::pair<std::string, EnumData> const & enumData, std::string const & surroundingProtect ) const
4722 {
4723 std::string baseType, bitmask;
4724 if ( enumData.second.isBitmask )
4725 {
4726 auto bitmaskIt =
4727 std::find_if( m_bitmasks.begin(), m_bitmasks.end(), [&enumData]( auto const & bitmask ) { return bitmask.second.requirements == enumData.first; } );
4728 assert( bitmaskIt != m_bitmasks.end() );
4729 baseType = " : " + bitmaskIt->first;
4730 bitmask = generateBitmask( bitmaskIt, surroundingProtect );
4731 }
4732
4733 std::string enumValues, previousEnter, previousLeave;
4734 std::map<std::string, std::string> valueToNameMap;
4735 for ( auto const & value : enumData.second.values )
4736 {
4737 // determine the values protect, if any
4738 std::string valueProtect = getProtect( value );
4739
4740 // if the value's protect differs from the surrounding protect, generate protection code
4741 std::string enter, leave;
4742 if ( !valueProtect.empty() && ( valueProtect != surroundingProtect ) )
4743 {
4744 tie( enter, leave ) = generateProtection( valueProtect );
4745 }
4746 if ( previousEnter != enter )
4747 {
4748 enumValues += previousLeave + enter;
4749 }
4750 std::string valueName = generateEnumValueName( enumData.first, value.name, enumData.second.isBitmask, m_tags );
4751 enumValues += " " + valueName + " = " + value.name + ",\n";
4752 assert( valueToNameMap.find( valueName ) == valueToNameMap.end() );
4753 valueToNameMap[valueName] = value.name;
4754
4755 previousEnter = enter;
4756 previousLeave = leave;
4757 }
4758 enumValues += previousLeave;
4759
4760 for ( auto const & alias : enumData.second.aliases )
4761 {
4762 std::string aliasName =
4763 generateEnumValueName( enumData.second.alias.empty() ? enumData.first : enumData.second.alias, alias.first, enumData.second.isBitmask, m_tags );
4764 // make sure to only list alias values that differ from all previous values
4765 auto valueToNameIt = valueToNameMap.find( aliasName );
4766 if ( valueToNameIt == valueToNameMap.end() )
4767 {
4768 #if !defined( NDEBUG )
4769 auto enumIt = std::find_if(
4770 enumData.second.values.begin(), enumData.second.values.end(), [&alias]( EnumValueData const & evd ) { return alias.second.name == evd.name; } );
4771 if ( enumIt == enumData.second.values.end() )
4772 {
4773 auto aliasIt = enumData.second.aliases.find( alias.second.name );
4774 assert( aliasIt != enumData.second.aliases.end() );
4775 auto nextAliasIt = enumData.second.aliases.find( aliasIt->second.name );
4776 while ( nextAliasIt != enumData.second.aliases.end() )
4777 {
4778 aliasIt = nextAliasIt;
4779 nextAliasIt = enumData.second.aliases.find( aliasIt->second.name );
4780 }
4781 enumIt = std::find_if(
4782 enumData.second.values.begin(), enumData.second.values.end(), [&aliasIt]( EnumValueData const & evd ) { return aliasIt->second.name == evd.name; } );
4783 }
4784 assert( enumIt != enumData.second.values.end() );
4785 assert( enumIt->extension.empty() || generateProtection( getProtectFromTitle( enumIt->extension ) ).first.empty() );
4786 #endif
4787 enumValues += " " + aliasName + " = " + alias.first + ",\n";
4788
4789 // map the aliasName to the name of the base
4790 std::string baseName = findBaseName( alias.second.name, enumData.second.aliases );
4791 assert( std::find_if( enumData.second.values.begin(),
4792 enumData.second.values.end(),
4793 [&baseName]( EnumValueData const & evd ) { return evd.name == baseName; } ) != enumData.second.values.end() );
4794 valueToNameMap[aliasName] = baseName;
4795 }
4796 #if !defined( NDEBUG )
4797 else
4798 {
4799 // verify, that the identical value represents the identical name
4800 std::string baseName = findBaseName( alias.second.name, enumData.second.aliases );
4801 assert( std::find_if( enumData.second.values.begin(),
4802 enumData.second.values.end(),
4803 [&baseName]( EnumValueData const & evd ) { return evd.name == baseName; } ) != enumData.second.values.end() );
4804 assert( baseName == valueToNameIt->second );
4805 }
4806 #endif
4807 }
4808 if ( !enumValues.empty() )
4809 {
4810 size_t pos = enumValues.rfind( ',' );
4811 assert( pos != std::string::npos );
4812 enumValues.erase( pos, 1 );
4813 enumValues = "\n" + enumValues + " ";
4814 }
4815
4816 std::string enumUsing;
4817 if ( !enumData.second.alias.empty() )
4818 {
4819 enumUsing += " using " + stripPrefix( enumData.second.alias, "Vk" ) + " = " + stripPrefix( enumData.first, "Vk" ) + ";\n";
4820 }
4821
4822 const std::string enumTemplate = R"( enum class ${enumName}${baseType}
4823 {${enumValues}};
4824 ${enumUsing}${bitmask})";
4825
4826 return replaceWithMap( enumTemplate,
4827 { { "baseType", baseType },
4828 { "bitmask", bitmask },
4829 { "enumName", stripPrefix( enumData.first, "Vk" ) },
4830 { "enumUsing", enumUsing },
4831 { "enumValues", enumValues } } );
4832 }
4833
generateEnums() const4834 std::string VulkanHppGenerator::generateEnums() const
4835 {
4836 const std::string enumsTemplate = R"(
4837 //=============
4838 //=== ENUMs ===
4839 //=============
4840
4841 ${enums}
4842 )";
4843
4844 std::string enums;
4845 std::set<std::string> listedEnums;
4846 for ( auto const & feature : m_features )
4847 {
4848 enums += generateEnums( feature.second.requireData, listedEnums, feature.first );
4849 }
4850 for ( auto const & extIt : m_extensionsByNumber )
4851 {
4852 enums += generateEnums( extIt.second->second.requireData, listedEnums, extIt.second->first );
4853 }
4854
4855 return replaceWithMap( enumsTemplate, { { "enums", enums } } );
4856 }
4857
4858 std::string
generateEnums(std::vector<RequireData> const & requireData,std::set<std::string> & listedEnums,std::string const & title) const4859 VulkanHppGenerator::generateEnums( std::vector<RequireData> const & requireData, std::set<std::string> & listedEnums, std::string const & title ) const
4860 {
4861 std::string surroundingProtect = getProtectFromTitle( title );
4862 std::string str;
4863 for ( auto const & require : requireData )
4864 {
4865 for ( auto const & type : require.types )
4866 {
4867 auto enumIt = m_enums.find( type );
4868 if ( ( enumIt != m_enums.end() ) && ( listedEnums.find( type ) == listedEnums.end() ) )
4869 {
4870 listedEnums.insert( type );
4871 str += "\n";
4872 str += generateEnum( *enumIt, surroundingProtect );
4873 }
4874 }
4875 }
4876 return addTitleAndProtection( title, str );
4877 }
4878
generateEnumsToString() const4879 std::string VulkanHppGenerator::generateEnumsToString() const
4880 {
4881 // start with toHexString, which is used in all the to_string functions here!
4882 const std::string enumsToStringTemplate = R"(
4883 //=======================
4884 //=== ENUMs to_string ===
4885 //=======================
4886
4887 VULKAN_HPP_INLINE std::string toHexString( uint32_t value )
4888 {
4889 #if __cpp_lib_format
4890 return std::format( "{:x}", value );
4891 #else
4892 std::stringstream stream;
4893 stream << std::hex << value;
4894 return stream.str();
4895 #endif
4896 }
4897
4898 ${enumsToString}
4899 )";
4900
4901 std::string enumsToString;
4902 std::set<std::string> listedEnums;
4903 for ( auto const & feature : m_features )
4904 {
4905 enumsToString += generateEnumsToString( feature.second.requireData, listedEnums, feature.first );
4906 }
4907 for ( auto const & extIt : m_extensionsByNumber )
4908 {
4909 enumsToString += generateEnumsToString( extIt.second->second.requireData, listedEnums, extIt.second->first );
4910 }
4911
4912 return replaceWithMap( enumsToStringTemplate, { { "enumsToString", enumsToString } } );
4913 }
4914
generateEnumsToString(std::vector<RequireData> const & requireData,std::set<std::string> & listedEnums,std::string const & title) const4915 std::string VulkanHppGenerator::generateEnumsToString( std::vector<RequireData> const & requireData,
4916 std::set<std::string> & listedEnums,
4917 std::string const & title ) const
4918 {
4919 std::string str;
4920 for ( auto const & require : requireData )
4921 {
4922 for ( auto const & type : require.types )
4923 {
4924 auto enumIt = m_enums.find( type );
4925 if ( ( enumIt != m_enums.end() ) && ( listedEnums.find( type ) == listedEnums.end() ) )
4926 {
4927 listedEnums.insert( type );
4928
4929 str += "\n";
4930 str += generateEnumToString( *enumIt );
4931 }
4932 }
4933 }
4934 return addTitleAndProtection( title, str );
4935 }
4936
generateEnumInitializer(TypeInfo const & type,std::vector<std::string> const & arraySizes,std::vector<EnumValueData> const & values,bool bitmask) const4937 std::string VulkanHppGenerator::generateEnumInitializer( TypeInfo const & type,
4938 std::vector<std::string> const & arraySizes,
4939 std::vector<EnumValueData> const & values,
4940 bool bitmask ) const
4941 {
4942 // enum arguments might need special initialization
4943 assert( type.prefix.empty() && !values.empty() );
4944 std::string valueName = generateEnumValueName( type.type, values.front().name, bitmask, m_tags );
4945 std::string value = generateNamespacedType( type.type ) + "::" + valueName;
4946 std::string str;
4947 if ( arraySizes.empty() )
4948 {
4949 str += value;
4950 }
4951 else
4952 {
4953 assert( arraySizes.size() == 1 );
4954 auto constIt = m_constants.find( arraySizes[0] );
4955 int count = std::stoi( ( constIt == m_constants.end() ) ? arraySizes[0] : constIt->second );
4956 assert( 1 < count );
4957 str += "{ { " + value;
4958 for ( int i = 1; i < count; i++ )
4959 {
4960 str += ", " + value;
4961 }
4962 str += " } }";
4963 }
4964 return str;
4965 }
4966
generateEnumToString(std::pair<std::string,EnumData> const & enumData) const4967 std::string VulkanHppGenerator::generateEnumToString( std::pair<std::string, EnumData> const & enumData ) const
4968 {
4969 std::string enumName = stripPrefix( enumData.first, "Vk" );
4970 std::string functionBody;
4971 if ( enumData.second.values.empty() )
4972 {
4973 functionBody = R"x( return "(void)";)x";
4974 }
4975 else
4976 {
4977 std::string cases, previousEnter, previousLeave;
4978 for ( auto const & value : enumData.second.values )
4979 {
4980 auto [enter, leave] = generateProtection( getProtect( value ) );
4981 if ( previousEnter != enter )
4982 {
4983 cases += previousLeave + enter;
4984 }
4985
4986 const std::string caseTemplate = R"( case ${enumName}::e${valueName} : return "${valueName}";
4987 )";
4988 cases += replaceWithMap(
4989 caseTemplate,
4990 { { "enumName", enumName }, { "valueName", generateEnumValueName( enumData.first, value.name, enumData.second.isBitmask, m_tags ).substr( 1 ) } } );
4991
4992 previousEnter = enter;
4993 previousLeave = leave;
4994 }
4995 cases += previousLeave;
4996
4997 const std::string functionBodyTemplate =
4998 R"x( switch ( value )
4999 {
5000 ${cases} default: return "invalid ( " + VULKAN_HPP_NAMESPACE::toHexString( static_cast<uint32_t>( value ) ) + " )";
5001 }
5002 )x";
5003
5004 functionBody = replaceWithMap( functionBodyTemplate, { { "cases", cases } } );
5005 }
5006
5007 const std::string enumToStringTemplate = R"(
5008 VULKAN_HPP_INLINE std::string to_string( ${enumName}${argument} )
5009 {
5010 ${functionBody}
5011 }
5012 )";
5013
5014 return replaceWithMap( enumToStringTemplate,
5015 { { "argument", enumData.second.values.empty() ? "" : " value" }, { "enumName", enumName }, { "functionBody", functionBody } } );
5016 }
5017
generateFailureCheck(std::vector<std::string> const & successCodes) const5018 std::string VulkanHppGenerator::generateFailureCheck( std::vector<std::string> const & successCodes ) const
5019 {
5020 assert( !successCodes.empty() );
5021 std::string failureCheck = "result != " + generateSuccessCode( successCodes[0], m_tags );
5022 if ( 1 < successCodes.size() )
5023 {
5024 failureCheck = "( " + failureCheck + " )";
5025 for ( size_t i = 1; i < successCodes.size(); ++i )
5026 {
5027 failureCheck += "&& ( result != " + generateSuccessCode( successCodes[i], m_tags ) + " )";
5028 }
5029 }
5030 return failureCheck;
5031 }
5032
generateFormatTraits() const5033 std::string VulkanHppGenerator::generateFormatTraits() const
5034 {
5035 if ( m_formats.empty() )
5036 {
5037 return "";
5038 }
5039
5040 const std::string formatTraitsTemplate = R"(
5041 //=====================
5042 //=== Format Traits ===
5043 //=====================
5044
5045 // The three-dimensional extent of a texel block.
5046 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 std::array<uint8_t, 3> blockExtent( VULKAN_HPP_NAMESPACE::Format format )
5047 {
5048 switch( format )
5049 {
5050 ${blockExtentCases}
5051 default: return {{1, 1, 1 }};
5052 }
5053 }
5054
5055 // The texel block size in bytes.
5056 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t blockSize( VULKAN_HPP_NAMESPACE::Format format )
5057 {
5058 switch( format )
5059 {
5060 ${blockSizeCases}
5061 default : VULKAN_HPP_ASSERT( false ); return 0;
5062 }
5063 }
5064
5065 // The class of the format (can't be just named "class"!)
5066 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 char const * compatibilityClass( VULKAN_HPP_NAMESPACE::Format format )
5067 {
5068 switch( format )
5069 {
5070 ${classCases}
5071 default : VULKAN_HPP_ASSERT( false ); return "";
5072 }
5073 }
5074
5075 // The number of bits in this component, if not compressed, otherwise 0.
5076 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t componentBits( VULKAN_HPP_NAMESPACE::Format format, uint8_t component )
5077 {
5078 switch( format )
5079 {
5080 ${componentBitsCases}
5081 default: return 0;
5082 }
5083 }
5084
5085 // The number of components of this format.
5086 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t componentCount( VULKAN_HPP_NAMESPACE::Format format )
5087 {
5088 switch( format )
5089 {
5090 ${componentCountCases}
5091 default: return 0;
5092 }
5093 }
5094
5095 // The name of the component
5096 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 char const * componentName( VULKAN_HPP_NAMESPACE::Format format, uint8_t component )
5097 {
5098 switch( format )
5099 {
5100 ${componentNameCases}
5101 default: return "";
5102 }
5103 }
5104
5105 // The numeric format of the component
5106 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 char const * componentNumericFormat( VULKAN_HPP_NAMESPACE::Format format, uint8_t component )
5107 {
5108 switch( format )
5109 {
5110 ${componentNumericFormatCases}
5111 default: return "";
5112 }
5113 }
5114
5115 // The plane this component lies in.
5116 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t componentPlaneIndex( VULKAN_HPP_NAMESPACE::Format format, uint8_t component )
5117 {
5118 switch( format )
5119 {
5120 ${componentPlaneIndexCases}
5121 default: return 0;
5122 }
5123 }
5124
5125 // True, if the components of this format are compressed, otherwise false.
5126 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 bool componentsAreCompressed( VULKAN_HPP_NAMESPACE::Format format )
5127 {
5128 switch( format )
5129 {
5130 ${componentsAreCompressedCases}
5131 return true;
5132 default: return false;
5133 }
5134 }
5135
5136 // A textual description of the compression scheme, or an empty string if it is not compressed
5137 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 char const * compressionScheme( VULKAN_HPP_NAMESPACE::Format format )
5138 {
5139 switch( format )
5140 {
5141 ${compressionSchemeCases}
5142 default: return "";
5143 }
5144 }
5145
5146 // True, if this format is a compressed one.
5147 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 bool isCompressed( VULKAN_HPP_NAMESPACE::Format format )
5148 {
5149 return ( *VULKAN_HPP_NAMESPACE::compressionScheme( format ) != 0 );
5150 }
5151
5152 // The number of bits into which the format is packed. A single image element in this format
5153 // can be stored in the same space as a scalar type of this bit width.
5154 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t packed( VULKAN_HPP_NAMESPACE::Format format )
5155 {
5156 switch( format )
5157 {
5158 ${packedCases}
5159 default: return 0;
5160 }
5161 }
5162
5163 // The single-plane format that this plane is compatible with.
5164 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 VULKAN_HPP_NAMESPACE::Format planeCompatibleFormat( VULKAN_HPP_NAMESPACE::Format format, uint8_t plane )
5165 {
5166 switch( format )
5167 {
5168 ${planeCompatibleCases}
5169 default: VULKAN_HPP_ASSERT( plane == 0 ); return format;
5170 }
5171 }
5172
5173 // The number of image planes of this format.
5174 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t planeCount( VULKAN_HPP_NAMESPACE::Format format )
5175 {
5176 switch( format )
5177 {
5178 ${planeCountCases}
5179 default: return 1;
5180 }
5181 }
5182
5183 // The relative height of this plane. A value of k means that this plane is 1/k the height of the overall format.
5184 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t planeHeightDivisor( VULKAN_HPP_NAMESPACE::Format format, uint8_t plane )
5185 {
5186 switch( format )
5187 {
5188 ${planeHeightDivisorCases}
5189 default: VULKAN_HPP_ASSERT( plane == 0 ); return 1;
5190 }
5191 }
5192
5193 // The relative width of this plane. A value of k means that this plane is 1/k the width of the overall format.
5194 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t planeWidthDivisor( VULKAN_HPP_NAMESPACE::Format format, uint8_t plane )
5195 {
5196 switch( format )
5197 {
5198 ${planeWidthDivisorCases}
5199 default: VULKAN_HPP_ASSERT( plane == 0 ); return 1;
5200 }
5201 }
5202
5203 // The number of texels in a texel block.
5204 VULKAN_HPP_INLINE VULKAN_HPP_CONSTEXPR_14 uint8_t texelsPerBlock( VULKAN_HPP_NAMESPACE::Format format )
5205 {
5206 switch( format )
5207 {
5208 ${texelsPerBlockCases}
5209 default: VULKAN_HPP_ASSERT( false ); return 0;
5210 }
5211 }
5212 )";
5213
5214 auto formatIt = m_enums.find( "VkFormat" );
5215 assert( formatIt != m_enums.end() );
5216 assert( formatIt->second.values.front().name == "VK_FORMAT_UNDEFINED" );
5217
5218 std::string blockSizeCases, blockExtentCases, classCases, componentBitsCases, componentCountCases, componentNameCases, componentNumericFormatCases,
5219 componentPlaneIndexCases, componentsAreCompressedCases, compressionSchemeCases, packedCases, planeCompatibleCases, planeCountCases, planeHeightDivisorCases,
5220 planeWidthDivisorCases, texelsPerBlockCases;
5221 for ( auto formatValuesIt = std::next( formatIt->second.values.begin() ); formatValuesIt != formatIt->second.values.end(); ++formatValuesIt )
5222 {
5223 auto traitIt = m_formats.find( formatValuesIt->name );
5224 assert( traitIt != m_formats.end() );
5225 std::string caseString = " case VULKAN_HPP_NAMESPACE::Format::" + generateEnumValueName( "VkFormat", traitIt->first, false, m_tags ) + ":";
5226
5227 blockSizeCases += caseString + " return " + traitIt->second.blockSize + ";\n";
5228
5229 if ( !traitIt->second.blockExtent.empty() )
5230 {
5231 std::vector<std::string> blockExtent = tokenize( traitIt->second.blockExtent, "," );
5232 assert( blockExtent.size() == 3 );
5233 blockExtentCases += caseString + " return {{ " + blockExtent[0] + ", " + blockExtent[1] + ", " + blockExtent[2] + " }};\n";
5234 }
5235
5236 classCases += caseString + " return \"" + traitIt->second.classAttribute + "\";\n";
5237
5238 if ( traitIt->second.components.front().bits != "compressed" )
5239 {
5240 const std::string componentBitsCaseTemplate = R"(${caseString}
5241 switch( component )
5242 {
5243 ${componentCases}
5244 default: VULKAN_HPP_ASSERT( false ); return 0;
5245 }
5246 )";
5247
5248 std::string componentCases;
5249 for ( size_t i = 0; i < traitIt->second.components.size(); ++i )
5250 {
5251 componentCases += " case " + std::to_string( i ) + ": return " + traitIt->second.components[i].bits + ";\n";
5252 }
5253 componentCases.pop_back();
5254 componentBitsCases += replaceWithMap( componentBitsCaseTemplate, { { "caseString", caseString }, { "componentCases", componentCases } } );
5255 }
5256
5257 componentCountCases += caseString + " return " + std::to_string( traitIt->second.components.size() ) + ";\n";
5258
5259 {
5260 const std::string componentNameCaseTemplate = R"(${caseString}
5261 switch( component )
5262 {
5263 ${componentCases}
5264 default: VULKAN_HPP_ASSERT( false ); return "";
5265 }
5266 )";
5267
5268 std::string componentCases;
5269 for ( size_t i = 0; i < traitIt->second.components.size(); ++i )
5270 {
5271 componentCases += " case " + std::to_string( i ) + ": return \"" + traitIt->second.components[i].name + "\";\n";
5272 }
5273 componentCases.pop_back();
5274 componentNameCases += replaceWithMap( componentNameCaseTemplate, { { "caseString", caseString }, { "componentCases", componentCases } } );
5275 }
5276
5277 {
5278 const std::string componentNumericFormatCaseTemplate = R"(${caseString}
5279 switch( component )
5280 {
5281 ${componentCases}
5282 default: VULKAN_HPP_ASSERT( false ); return "";
5283 }
5284 )";
5285
5286 std::string componentCases;
5287 for ( size_t i = 0; i < traitIt->second.components.size(); ++i )
5288 {
5289 componentCases += " case " + std::to_string( i ) + ": return \"" + traitIt->second.components[i].numericFormat + "\";\n";
5290 }
5291 componentCases.pop_back();
5292 componentNumericFormatCases +=
5293 replaceWithMap( componentNumericFormatCaseTemplate, { { "caseString", caseString }, { "componentCases", componentCases } } );
5294 }
5295
5296 if ( !traitIt->second.components.front().planeIndex.empty() )
5297 {
5298 const std::string componentPlaneIndexCaseTemplate = R"(${caseString}
5299 switch( component )
5300 {
5301 ${componentCases}
5302 default: VULKAN_HPP_ASSERT( false ); return 0;
5303 }
5304 )";
5305
5306 std::string componentCases;
5307 for ( size_t i = 0; i < traitIt->second.components.size(); ++i )
5308 {
5309 componentCases += " case " + std::to_string( i ) + ": return " + traitIt->second.components[i].planeIndex + ";\n";
5310 }
5311 componentCases.pop_back();
5312 componentPlaneIndexCases += replaceWithMap( componentPlaneIndexCaseTemplate, { { "caseString", caseString }, { "componentCases", componentCases } } );
5313 }
5314
5315 if ( traitIt->second.components.front().bits == "compressed" )
5316 {
5317 componentsAreCompressedCases += caseString + "\n";
5318 }
5319
5320 if ( !traitIt->second.compressed.empty() )
5321 {
5322 compressionSchemeCases += caseString + " return \"" + traitIt->second.compressed + "\";\n";
5323 }
5324
5325 if ( !traitIt->second.packed.empty() )
5326 {
5327 packedCases += caseString + " return " + traitIt->second.packed + ";\n";
5328 }
5329
5330 if ( !traitIt->second.planes.empty() )
5331 {
5332 const std::string planeCompatibleCaseTemplate = R"(${caseString}
5333 switch( plane )
5334 {
5335 ${compatibleCases}
5336 default: VULKAN_HPP_ASSERT( false ); return VULKAN_HPP_NAMESPACE::Format::eUndefined;
5337 }
5338 )";
5339
5340 const std::string planeHeightDivisorCaseTemplate = R"(${caseString}
5341 switch( plane )
5342 {
5343 ${heightDivisorCases}
5344 default: VULKAN_HPP_ASSERT( false ); return 1;
5345 }
5346 )";
5347
5348 const std::string planeWidthDivisorCaseTemplate = R"(${caseString}
5349 switch( plane )
5350 {
5351 ${widthDivisorCases}
5352 default: VULKAN_HPP_ASSERT( false ); return 1;
5353 }
5354 )";
5355
5356 std::string compatibleCases, heightDivisorCases, widthDivisorCases;
5357 for ( size_t i = 0; i < traitIt->second.planes.size(); ++i )
5358 {
5359 compatibleCases += " case " + std::to_string( i ) + ": return VULKAN_HPP_NAMESPACE::Format::" +
5360 generateEnumValueName( "VkFormat", traitIt->second.planes[i].compatible, false, m_tags ) + ";\n";
5361 heightDivisorCases += " case " + std::to_string( i ) + ": return " + traitIt->second.planes[i].heightDivisor + ";\n";
5362 widthDivisorCases += " case " + std::to_string( i ) + ": return " + traitIt->second.planes[i].widthDivisor + ";\n";
5363 }
5364 compatibleCases.pop_back();
5365 heightDivisorCases.pop_back();
5366 widthDivisorCases.pop_back();
5367
5368 planeCompatibleCases += replaceWithMap( planeCompatibleCaseTemplate, { { "caseString", caseString }, { "compatibleCases", compatibleCases } } );
5369
5370 planeCountCases += caseString + " return " + std::to_string( traitIt->second.planes.size() ) + ";\n";
5371
5372 planeHeightDivisorCases +=
5373 replaceWithMap( planeHeightDivisorCaseTemplate, { { "caseString", caseString }, { "heightDivisorCases", heightDivisorCases } } );
5374
5375 planeWidthDivisorCases += replaceWithMap( planeWidthDivisorCaseTemplate, { { "caseString", caseString }, { "widthDivisorCases", widthDivisorCases } } );
5376 }
5377
5378 texelsPerBlockCases += caseString + " return " + traitIt->second.texelsPerBlock + ";\n";
5379 }
5380
5381 return replaceWithMap( formatTraitsTemplate,
5382 { { "blockExtentCases", blockExtentCases },
5383 { "blockSizeCases", blockSizeCases },
5384 { "classCases", classCases },
5385 { "componentBitsCases", componentBitsCases },
5386 { "componentCountCases", componentCountCases },
5387 { "componentNameCases", componentNameCases },
5388 { "componentNumericFormatCases", componentNumericFormatCases },
5389 { "componentPlaneIndexCases", componentPlaneIndexCases },
5390 { "componentsAreCompressedCases", componentsAreCompressedCases },
5391 { "compressionSchemeCases", compressionSchemeCases },
5392 { "packedCases", packedCases },
5393 { "planeCompatibleCases", planeCompatibleCases },
5394 { "planeCountCases", planeCountCases },
5395 { "planeHeightDivisorCases", planeHeightDivisorCases },
5396 { "planeWidthDivisorCases", planeWidthDivisorCases },
5397 { "texelsPerBlockCases", texelsPerBlockCases } } );
5398 }
5399
generateFunctionPointerCheck(std::string const & function,std::string const & referencedIn) const5400 std::string VulkanHppGenerator::generateFunctionPointerCheck( std::string const & function, std::string const & referencedIn ) const
5401 {
5402 std::string functionPointerCheck;
5403 if ( m_extensions.find( referencedIn ) != m_extensions.end() )
5404 {
5405 std::string message = "Function <" + function + "> needs extension <" + referencedIn + "> enabled!";
5406 functionPointerCheck = "VULKAN_HPP_ASSERT( getDispatcher()->" + function + " && \"" + message + "\" );";
5407 }
5408 return functionPointerCheck;
5409 }
5410
generateHandle(std::pair<std::string,HandleData> const & handleData,std::set<std::string> & listedHandles) const5411 std::string VulkanHppGenerator::generateHandle( std::pair<std::string, HandleData> const & handleData, std::set<std::string> & listedHandles ) const
5412 {
5413 assert( listedHandles.find( handleData.first ) == listedHandles.end() );
5414
5415 // first check for any handle that needs to be listed before this one
5416 std::string str = generateHandleDependencies( handleData, listedHandles );
5417
5418 // list the commands of this handle
5419 if ( handleData.first.empty() )
5420 {
5421 // the free functions, not bound to any handle
5422 str += generateHandleEmpty( handleData.second );
5423 }
5424 else
5425 {
5426 // append any forward declaration of Deleters used by this handle
5427 if ( !handleData.second.childrenHandles.empty() )
5428 {
5429 str += generateUniqueTypes( handleData.first, handleData.second.childrenHandles );
5430 }
5431 else if ( handleData.first == "VkPhysicalDevice" )
5432 {
5433 // special handling for class Device, as it's created from PhysicalDevice, but destroys itself
5434 str += generateUniqueTypes( "", { "VkDevice" } );
5435 }
5436
5437 // list all the commands that are mapped to members of this class
5438 std::string commands = generateHandleCommandDeclarations( handleData.second.commands );
5439
5440 // create CPPType template specialization and the debugReportObjectType
5441 std::string valueName = handleData.second.objTypeEnum;
5442 valueName = valueName.replace( 3, 0, "DEBUG_REPORT_" ) + "_EXT";
5443 auto enumIt = m_enums.find( "VkDebugReportObjectTypeEXT" );
5444 assert( enumIt != m_enums.end() );
5445 auto valueIt =
5446 std::find_if( enumIt->second.values.begin(), enumIt->second.values.end(), [&valueName]( EnumValueData const & evd ) { return valueName == evd.name; } );
5447
5448 std::string className = stripPrefix( handleData.first, "Vk" );
5449 std::string cppType, debugReportObjectType;
5450 if ( valueIt == enumIt->second.values.end() )
5451 {
5452 debugReportObjectType = "eUnknown";
5453 }
5454 else
5455 {
5456 static const std::string cppTypeFromDebugReportObjectTypeEXTTemplate = R"(
5457 template <>
5458 struct CppType<VULKAN_HPP_NAMESPACE::DebugReportObjectTypeEXT, VULKAN_HPP_NAMESPACE::DebugReportObjectTypeEXT::e${className}>
5459 {
5460 using Type = VULKAN_HPP_NAMESPACE::${className};
5461 };
5462 )";
5463 cppType = replaceWithMap( cppTypeFromDebugReportObjectTypeEXTTemplate, { { "className", className } } );
5464 debugReportObjectType = generateEnumValueName( enumIt->first, valueIt->name, false, m_tags );
5465 }
5466
5467 auto [enter, leave] = generateProtection( handleData.second.alias.empty() ? getProtectFromType( handleData.first ) : "" );
5468
5469 assert( !handleData.second.objTypeEnum.empty() );
5470 enumIt = m_enums.find( "VkObjectType" );
5471 assert( enumIt != m_enums.end() );
5472 valueIt = std::find_if( enumIt->second.values.begin(),
5473 enumIt->second.values.end(),
5474 [&handleData]( EnumValueData const & evd ) { return evd.name == handleData.second.objTypeEnum; } );
5475 assert( valueIt != enumIt->second.values.end() );
5476 std::string usingAlias;
5477 if ( !handleData.second.alias.empty() )
5478 {
5479 usingAlias += " using " + stripPrefix( handleData.second.alias, "Vk" ) + " = " + stripPrefix( handleData.first, "Vk" ) + ";\n";
5480 }
5481
5482 const std::string typesafeExplicitKeyword = handleData.second.isDispatchable ? "" : "VULKAN_HPP_TYPESAFE_EXPLICIT ";
5483 const std::string typesafeConversionConditional = handleData.second.isDispatchable ? "" : "#if defined(VULKAN_HPP_TYPESAFE_CONVERSION)\n";
5484 const std::string typesafeConversionConditionalEnd = handleData.second.isDispatchable ? "" : "#endif\n";
5485
5486 static const std::string templateString = R"(
5487 ${enter} class ${className}
5488 {
5489 public:
5490 using CType = Vk${className};
5491 using NativeType = Vk${className};
5492
5493 static VULKAN_HPP_CONST_OR_CONSTEXPR VULKAN_HPP_NAMESPACE::ObjectType objectType = VULKAN_HPP_NAMESPACE::ObjectType::${objTypeEnum};
5494 static VULKAN_HPP_CONST_OR_CONSTEXPR VULKAN_HPP_NAMESPACE::DebugReportObjectTypeEXT debugReportObjectType = VULKAN_HPP_NAMESPACE::DebugReportObjectTypeEXT::${debugReportObjectType};
5495
5496 public:
5497 VULKAN_HPP_CONSTEXPR ${className}() = default;
5498 VULKAN_HPP_CONSTEXPR ${className}( std::nullptr_t ) VULKAN_HPP_NOEXCEPT
5499 {}
5500 ${typesafeExplicitKeyword}${className}( Vk${className} ${memberName} ) VULKAN_HPP_NOEXCEPT
5501 : m_${memberName}( ${memberName} )
5502 {}
5503
5504 ${typesafeConversionConditional} ${className} & operator=(Vk${className} ${memberName}) VULKAN_HPP_NOEXCEPT
5505 {
5506 m_${memberName} = ${memberName};
5507 return *this;
5508 }
5509 ${typesafeConversionConditionalEnd}
5510 ${className} & operator=( std::nullptr_t ) VULKAN_HPP_NOEXCEPT
5511 {
5512 m_${memberName} = {};
5513 return *this;
5514 }
5515
5516 #if defined(VULKAN_HPP_HAS_SPACESHIP_OPERATOR)
5517 auto operator<=>( ${className} const & ) const = default;
5518 #else
5519 bool operator==( ${className} const & rhs ) const VULKAN_HPP_NOEXCEPT
5520 {
5521 return m_${memberName} == rhs.m_${memberName};
5522 }
5523
5524 bool operator!=(${className} const & rhs ) const VULKAN_HPP_NOEXCEPT
5525 {
5526 return m_${memberName} != rhs.m_${memberName};
5527 }
5528
5529 bool operator<(${className} const & rhs ) const VULKAN_HPP_NOEXCEPT
5530 {
5531 return m_${memberName} < rhs.m_${memberName};
5532 }
5533 #endif
5534 ${commands}
5535 ${typesafeExplicitKeyword}operator Vk${className}() const VULKAN_HPP_NOEXCEPT
5536 {
5537 return m_${memberName};
5538 }
5539
5540 explicit operator bool() const VULKAN_HPP_NOEXCEPT
5541 {
5542 return m_${memberName} != VK_NULL_HANDLE;
5543 }
5544
5545 bool operator!() const VULKAN_HPP_NOEXCEPT
5546 {
5547 return m_${memberName} == VK_NULL_HANDLE;
5548 }
5549
5550 private:
5551 Vk${className} m_${memberName} = {};
5552 };
5553
5554 template <>
5555 struct CppType<VULKAN_HPP_NAMESPACE::ObjectType, VULKAN_HPP_NAMESPACE::ObjectType::${objTypeEnum}>
5556 {
5557 using Type = VULKAN_HPP_NAMESPACE::${className};
5558 };
5559
5560 ${CppType}
5561
5562 template <>
5563 struct isVulkanHandleType<VULKAN_HPP_NAMESPACE::${className}>
5564 {
5565 static VULKAN_HPP_CONST_OR_CONSTEXPR bool value = true;
5566 };
5567 ${usingAlias}${leave})";
5568
5569 str += replaceWithMap( templateString,
5570 { { "className", className },
5571 { "commands", commands },
5572 { "CppType", cppType },
5573 { "debugReportObjectType", debugReportObjectType },
5574 { "enter", enter },
5575 { "leave", leave },
5576 { "memberName", startLowerCase( stripPrefix( handleData.first, "Vk" ) ) },
5577 { "objTypeEnum", generateEnumValueName( enumIt->first, valueIt->name, false, m_tags ) },
5578 { "usingAlias", usingAlias },
5579 { "typesafeExplicitKeyword", typesafeExplicitKeyword },
5580 { "typesafeConversionConditional", typesafeConversionConditional },
5581 { "typesafeConversionConditionalEnd", typesafeConversionConditionalEnd } } );
5582 }
5583
5584 listedHandles.insert( handleData.first );
5585 return str;
5586 }
5587
generateHandleCommandDeclarations(std::set<std::string> const & commands) const5588 std::string VulkanHppGenerator::generateHandleCommandDeclarations( std::set<std::string> const & commands ) const
5589 {
5590 std::string str;
5591 std::set<std::string> listedCommands; // some commands are listed with more than one extension!
5592 for ( auto const & feature : m_features )
5593 {
5594 std::vector<std::string> commandNames = selectCommandsByHandle( feature.second.requireData, commands, listedCommands );
5595 if ( !commandNames.empty() )
5596 {
5597 str += "\n //=== " + feature.first + " ===\n";
5598 for ( auto const & command : commandNames )
5599 {
5600 auto commandIt = m_commands.find( command );
5601 assert( commandIt != m_commands.end() );
5602
5603 str += "\n";
5604 str += generateCommand( commandIt->first, commandIt->second, 1, false );
5605 str += generateDestroyCommand( commandIt->first, commandIt->second );
5606 }
5607 }
5608 }
5609 for ( auto const & extIt : m_extensionsByNumber )
5610 {
5611 std::vector<std::string> commandNames = selectCommandsByHandle( extIt.second->second.requireData, commands, listedCommands );
5612 if ( !commandNames.empty() )
5613 {
5614 auto [enter, leave] = generateProtection( getProtectFromTitle( extIt.second->first ) );
5615 str += "\n" + enter + " //=== " + extIt.second->first + " ===\n";
5616 for ( auto const & command : commandNames )
5617 {
5618 auto commandIt = m_commands.find( command );
5619 assert( commandIt != m_commands.end() );
5620
5621 std::string commandString;
5622 std::string commandName = generateCommandName( commandIt->first, commandIt->second.params, 1, m_tags );
5623 str += "\n";
5624 str += generateCommand( commandIt->first, commandIt->second, 1, false );
5625 str += generateDestroyCommand( commandIt->first, commandIt->second );
5626 }
5627 str += leave;
5628 }
5629 }
5630 return str;
5631 }
5632
generateHandleDependencies(std::pair<std::string,HandleData> const & handleData,std::set<std::string> & listedHandles) const5633 std::string VulkanHppGenerator::generateHandleDependencies( std::pair<std::string, HandleData> const & handleData, std::set<std::string> & listedHandles ) const
5634 {
5635 std::string str;
5636 for ( auto const & command : handleData.second.commands )
5637 {
5638 auto commandIt = m_commands.find( command );
5639 assert( commandIt != m_commands.end() );
5640 for ( auto const & parameter : commandIt->second.params )
5641 {
5642 auto handleIt = m_handles.find( parameter.type.type );
5643 if ( ( handleIt != m_handles.end() ) && ( parameter.type.type != handleData.first ) &&
5644 ( listedHandles.find( parameter.type.type ) == listedHandles.end() ) )
5645 {
5646 str += generateHandle( *handleIt, listedHandles );
5647 }
5648 }
5649 }
5650 return str;
5651 }
5652
generateHandleEmpty(HandleData const & handleData) const5653 std::string VulkanHppGenerator::generateHandleEmpty( HandleData const & handleData ) const
5654 {
5655 std::string str;
5656 std::set<std::string> listedCommands; // some commands are listed with more than one extension !
5657 for ( auto const & feature : m_features )
5658 {
5659 std::vector<std::string> commands = selectCommandsByHandle( feature.second.requireData, handleData.commands, listedCommands );
5660 if ( !commands.empty() )
5661 {
5662 str += "\n //=== " + feature.first + " ===\n";
5663 for ( auto const & command : commands )
5664 {
5665 auto commandIt = m_commands.find( command );
5666 assert( commandIt != m_commands.end() );
5667 if ( commandIt->first == "vkCreateInstance" )
5668 {
5669 // special handling for createInstance, as we need to explicitly place the forward declarations and the
5670 // deleter classes here
5671 #if !defined( NDEBUG )
5672 auto handleIt = m_handles.find( "" );
5673 assert( ( handleIt != m_handles.end() ) && ( handleIt->second.childrenHandles.size() == 2 ) );
5674 assert( handleIt->second.childrenHandles.find( "VkInstance" ) != handleIt->second.childrenHandles.end() );
5675 #endif
5676
5677 str += generateUniqueTypes( "", { "VkInstance" } );
5678 }
5679 str += "\n";
5680
5681 str += generateCommand( commandIt->first, commandIt->second, 0, false );
5682 }
5683 }
5684 }
5685 #if !defined( NDEBUG )
5686 for ( auto const & extIt : m_extensionsByNumber )
5687 {
5688 assert( selectCommandsByHandle( extIt.second->second.requireData, handleData.commands, listedCommands ).empty() );
5689 }
5690 #endif
5691 return str;
5692 }
5693
generateHandleHashStructures(std::vector<RequireData> const & requireData,std::string const & title) const5694 std::string VulkanHppGenerator::generateHandleHashStructures( std::vector<RequireData> const & requireData, std::string const & title ) const
5695 {
5696 const std::string hashTemplate = R"(
5697 template <> struct hash<VULKAN_HPP_NAMESPACE::${type}>
5698 {
5699 std::size_t operator()(VULKAN_HPP_NAMESPACE::${type} const & ${name}) const VULKAN_HPP_NOEXCEPT
5700 {
5701 return std::hash<Vk${type}>{}(static_cast<Vk${type}>(${name}));
5702 }
5703 };
5704 )";
5705
5706 std::string str;
5707 for ( auto const & require : requireData )
5708 {
5709 for ( auto const & type : require.types )
5710 {
5711 auto handleIt = m_handles.find( type );
5712 if ( handleIt != m_handles.end() )
5713 {
5714 std::string handleType = stripPrefix( handleIt->first, "Vk" );
5715 std::string handleName = startLowerCase( handleType );
5716 str += replaceWithMap( hashTemplate, { { "name", handleName }, { "type", handleType } } );
5717 }
5718 }
5719 }
5720 return addTitleAndProtection( title, str );
5721 }
5722
generateHandleHashStructures() const5723 std::string VulkanHppGenerator::generateHandleHashStructures() const
5724 {
5725 const std::string hashesTemplate = R"(
5726 //===================================
5727 //=== HASH structures for handles ===
5728 //===================================
5729
5730 ${hashes}
5731 )";
5732
5733 std::string hashes;
5734 for ( auto const & feature : m_features )
5735 {
5736 hashes += generateHandleHashStructures( feature.second.requireData, feature.first );
5737 }
5738 for ( auto const & extIt : m_extensionsByNumber )
5739 {
5740 hashes += generateHandleHashStructures( extIt.second->second.requireData, extIt.second->first );
5741 }
5742 return replaceWithMap( hashesTemplate, { { "hashes", hashes } } );
5743 }
5744
generateHandles() const5745 std::string VulkanHppGenerator::generateHandles() const
5746 {
5747 // Note: reordering structs or handles by features and extensions is not possible!
5748 std::string str = R"(
5749 //===============
5750 //=== HANDLEs ===
5751 //===============
5752
5753 template <typename Type>
5754 struct isVulkanHandleType
5755 {
5756 static VULKAN_HPP_CONST_OR_CONSTEXPR bool value = false;
5757 };
5758 )";
5759
5760 std::set<std::string> listedHandles;
5761 for ( auto const & handle : m_handles )
5762 {
5763 if ( listedHandles.find( handle.first ) == listedHandles.end() )
5764 {
5765 str += generateHandle( handle, listedHandles );
5766 }
5767 }
5768 return str;
5769 }
5770
generateIndexTypeTraits() const5771 std::string VulkanHppGenerator::generateIndexTypeTraits() const
5772 {
5773 const std::string indexTypeTraitsTemplate = R"(
5774 //=========================
5775 //=== Index Type Traits ===
5776 //=========================
5777
5778 template<typename T>
5779 struct IndexTypeValue
5780 {};
5781
5782 ${indexTypeTraits}
5783 )";
5784
5785 auto indexType = m_enums.find( "VkIndexType" );
5786 assert( indexType != m_enums.end() );
5787
5788 std::string indexTypeTraits;
5789 std::set<std::string> listedCppTypes;
5790 for ( auto const & value : indexType->second.values )
5791 {
5792 std::string valueName = generateEnumValueName( indexType->first, value.name, false, m_tags );
5793 std::string cppType;
5794 if ( !valueName.starts_with( "eNone" ) )
5795 {
5796 // get the bit count out of the value Name (8, 16, 32, ... ) and generate the cppType (uint8_t,...)
5797 assert( valueName.starts_with( "eUint" ) );
5798 auto beginDigit = valueName.begin() + strlen( "eUint" );
5799 assert( isdigit( *beginDigit ) );
5800 auto endDigit = std::find_if_not( beginDigit, valueName.end(), []( std::string::value_type c ) { return isdigit( c ); } );
5801 cppType = "uint" + valueName.substr( strlen( "eUint" ), endDigit - beginDigit ) + "_t";
5802 }
5803
5804 if ( !cppType.empty() )
5805 {
5806 if ( listedCppTypes.insert( cppType ).second )
5807 {
5808 // IndexType traits aren't necessarily invertible.
5809 // The Type -> Enum translation will only occur for the first prefixed enum value.
5810 // A hypothetical extension to this enum with a conflicting prefix will use the core spec value.
5811 const std::string typeToEnumTemplate = R"(
5812 template <>
5813 struct IndexTypeValue<${cppType}>
5814 {
5815 static VULKAN_HPP_CONST_OR_CONSTEXPR IndexType value = IndexType::${valueName};
5816 };
5817 )";
5818 indexTypeTraits += replaceWithMap( typeToEnumTemplate, { { "cppType", cppType }, { "valueName", valueName } } );
5819 }
5820
5821 // Enum -> Type translations are always able to occur.
5822 const std::string enumToTypeTemplate = R"(
5823 template <>
5824 struct CppType<IndexType, IndexType::${valueName}>
5825 {
5826 using Type = ${cppType};
5827 };
5828 )";
5829 indexTypeTraits += replaceWithMap( enumToTypeTemplate, { { "cppType", cppType }, { "valueName", valueName } } );
5830 }
5831 }
5832
5833 return replaceWithMap( indexTypeTraitsTemplate, { { "indexTypeTraits", indexTypeTraits } } );
5834 }
5835
generateLenInitializer(std::vector<MemberData>::const_iterator mit,std::map<std::vector<MemberData>::const_iterator,std::vector<std::vector<MemberData>::const_iterator>>::const_iterator litit,bool mutualExclusiveLens) const5836 std::string VulkanHppGenerator::generateLenInitializer(
5837 std::vector<MemberData>::const_iterator mit,
5838 std::map<std::vector<MemberData>::const_iterator, std::vector<std::vector<MemberData>::const_iterator>>::const_iterator litit,
5839 bool mutualExclusiveLens ) const
5840 {
5841 std::string initializer;
5842 if ( mutualExclusiveLens )
5843 {
5844 // there are multiple mutually exclusive arrays related to this len
5845 for ( size_t i = 0; i + 1 < litit->second.size(); i++ )
5846 {
5847 auto arrayIt = litit->second[i];
5848 std::string argumentName = startLowerCase( stripPrefix( arrayIt->name, "p" ) ) + "_";
5849 initializer += "!" + argumentName + ".empty() ? " + argumentName + ".size() : ";
5850 }
5851 auto arrayIt = litit->second.back();
5852 std::string argumentName = startLowerCase( stripPrefix( arrayIt->name, "p" ) ) + "_";
5853 initializer += argumentName + ".size()";
5854 }
5855 else
5856 {
5857 auto arrayIt = litit->second.front();
5858 assert( ( arrayIt->len.front() == litit->first->name ) || ( ( arrayIt->len.front() == "codeSize / 4" ) && ( litit->first->name == "codeSize" ) ) );
5859
5860 assert( arrayIt->name.starts_with( "p" ) );
5861 std::string argumentName = startLowerCase( stripPrefix( arrayIt->name, "p" ) ) + "_";
5862
5863 assert( mit->type.prefix.empty() && mit->type.postfix.empty() );
5864 initializer = argumentName + ".size()";
5865 if ( arrayIt->len.front() == "codeSize / 4" )
5866 {
5867 initializer += " * 4";
5868 }
5869 if ( ( arrayIt->type.type == "void" ) &&
5870 ( std::count_if( arrayIt->type.postfix.begin(), arrayIt->type.postfix.end(), []( char c ) { return c == '*'; } ) < 2 ) )
5871 {
5872 initializer += " * sizeof(T)";
5873 }
5874 }
5875 if ( mit->type.type != "size_t" )
5876 {
5877 initializer = "static_cast<" + mit->type.type + ">( " + initializer + " )";
5878 }
5879 return initializer;
5880 }
5881
generateName(TypeInfo const & typeInfo) const5882 std::string VulkanHppGenerator::generateName( TypeInfo const & typeInfo ) const
5883 {
5884 std::string name = stripPrefix( typeInfo.type, "Vk" );
5885 assert( typeInfo.prefix.find( '*' ) == std::string::npos );
5886 if ( typeInfo.postfix.find( '*' ) != std::string::npos )
5887 {
5888 assert( typeInfo.postfix.find_first_of( '*' ) == typeInfo.postfix.find_last_of( '*' ) );
5889 name = "p" + name;
5890 }
5891 else
5892 {
5893 name = startLowerCase( name );
5894 }
5895 return name;
5896 }
5897
generateNoExcept(std::vector<std::string> const & errorCodes,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,CommandFlavourFlags flavourFlags,bool vectorSizeCheck,bool raii) const5898 std::string VulkanHppGenerator::generateNoExcept( std::vector<std::string> const & errorCodes,
5899 std::vector<size_t> const & returnParams,
5900 std::map<size_t, VectorParamData> const & vectorParams,
5901 CommandFlavourFlags flavourFlags,
5902 bool vectorSizeCheck,
5903 bool raii ) const
5904 {
5905 // noexcept is only possible with no error codes, and the return param (if any) is not a vector param (unless it's the singular version)
5906 return ( errorCodes.empty() &&
5907 ( ( flavourFlags & CommandFlavourFlagBits::singular ) || returnParams.empty() ||
5908 ( std::find_if( returnParams.begin(),
5909 returnParams.end(),
5910 [&vectorParams]( size_t rp ) { return vectorParams.find( rp ) != vectorParams.end(); } ) == returnParams.end() ) ) )
5911 ? ( vectorSizeCheck ? ( raii ? "" : " VULKAN_HPP_NOEXCEPT_WHEN_NO_EXCEPTIONS" ) : " VULKAN_HPP_NOEXCEPT" )
5912 : "";
5913 }
5914
generateObjectDeleter(std::string const & commandName,CommandData const & commandData,size_t initialSkipCount,size_t returnParam) const5915 std::string VulkanHppGenerator::generateObjectDeleter( std::string const & commandName,
5916 CommandData const & commandData,
5917 size_t initialSkipCount,
5918 size_t returnParam ) const
5919 {
5920 std::string objectDeleter, allocator;
5921 if ( ( commandName.find( "Acquire" ) != std::string::npos ) || ( commandName.find( "Get" ) != std::string::npos ) )
5922 {
5923 if ( ( commandName == "vkAcquirePerformanceConfigurationINTEL" ) || ( commandName == "vkGetRandROutputDisplayEXT" ) ||
5924 ( commandName == "vkGetWinrtDisplayNV" ) || ( commandName == "vkGetDrmDisplayEXT" ) )
5925 {
5926 objectDeleter = "ObjectRelease";
5927 }
5928 else
5929 {
5930 throw std::runtime_error( "Found " + commandName + " which requires special handling for the object deleter" );
5931 }
5932 }
5933 else if ( commandName.find( "Allocate" ) != std::string::npos )
5934 {
5935 objectDeleter = "ObjectFree";
5936 allocator = "allocator, ";
5937 }
5938 else
5939 {
5940 assert( ( commandName.find( "Create" ) != std::string::npos ) || ( commandName.find( "Register" ) != std::string::npos ) );
5941 objectDeleter = "ObjectDestroy";
5942 allocator = "allocator, ";
5943 }
5944 std::string className = initialSkipCount ? stripPrefix( commandData.params[initialSkipCount - 1].type.type, "Vk" ) : "";
5945 std::string parentName = ( className.empty() || ( commandData.params[returnParam].type.type == "VkDevice" ) ) ? "NoParent" : className;
5946 return objectDeleter + "<" + parentName + ", Dispatch>( " + ( ( parentName == "NoParent" ) ? "" : "*this, " ) + allocator + "d )";
5947 }
5948
generateProtection(std::string const & protect) const5949 std::pair<std::string, std::string> VulkanHppGenerator::generateProtection( std::string const & protect ) const
5950 {
5951 return protect.empty() ? std::make_pair( "", "" ) : std::make_pair( "#if defined( " + protect + " )\n", "#endif /*" + protect + "*/\n" );
5952 }
5953
generateRAIICommandDefinitions() const5954 std::string VulkanHppGenerator::generateRAIICommandDefinitions() const
5955 {
5956 const std::string commandDefinitionsTemplate = R"(
5957 //===========================
5958 //=== COMMAND Definitions ===
5959 //===========================
5960
5961 ${commandDefinitions}
5962 )";
5963
5964 std::string commandDefinitions;
5965 std::set<std::string> listedCommands; // some commands are listed with more than one extension!
5966 for ( auto const & feature : m_features )
5967 {
5968 commandDefinitions += generateRAIICommandDefinitions( feature.second.requireData, listedCommands, feature.first );
5969 }
5970 for ( auto const & extIt : m_extensionsByNumber )
5971 {
5972 commandDefinitions += generateRAIICommandDefinitions( extIt.second->second.requireData, listedCommands, extIt.second->first );
5973 }
5974
5975 return replaceWithMap( commandDefinitionsTemplate, { { "commandDefinitions", commandDefinitions } } );
5976 }
5977
generateRAIICommandDefinitions(std::vector<RequireData> const & requireData,std::set<std::string> & listedCommands,std::string const & title) const5978 std::string VulkanHppGenerator::generateRAIICommandDefinitions( std::vector<RequireData> const & requireData,
5979 std::set<std::string> & listedCommands,
5980 std::string const & title ) const
5981 {
5982 std::string str;
5983 for ( auto const & require : requireData )
5984 {
5985 for ( auto const & command : require.commands )
5986 {
5987 if ( listedCommands.insert( command ).second )
5988 {
5989 str += generateRAIIHandleCommand( command, determineInitialSkipCount( command ), true );
5990 }
5991 }
5992 }
5993 return addTitleAndProtection( title, str );
5994 }
5995
generateRAIIDispatchers() const5996 std::string VulkanHppGenerator::generateRAIIDispatchers() const
5997 {
5998 std::string contextInitializers, contextMembers, deviceAssignments, deviceMembers, instanceAssignments, instanceMembers;
5999
6000 std::set<std::string> listedCommands;
6001 for ( auto const & feature : m_features )
6002 {
6003 appendRAIIDispatcherCommands( feature.second.requireData,
6004 listedCommands,
6005 feature.first,
6006 contextInitializers,
6007 contextMembers,
6008 deviceAssignments,
6009 deviceMembers,
6010 instanceAssignments,
6011 instanceMembers );
6012 }
6013 for ( auto const & extension : m_extensions )
6014 {
6015 appendRAIIDispatcherCommands( extension.second.requireData,
6016 listedCommands,
6017 extension.first,
6018 contextInitializers,
6019 contextMembers,
6020 deviceAssignments,
6021 deviceMembers,
6022 instanceAssignments,
6023 instanceMembers );
6024 }
6025
6026 std::string contextDispatcherTemplate = R"(
6027 class ContextDispatcher : public DispatchLoaderBase
6028 {
6029 public:
6030 ContextDispatcher( PFN_vkGetInstanceProcAddr getProcAddr )
6031 : vkGetInstanceProcAddr( getProcAddr )${contextInitializers}
6032 {}
6033
6034 public:
6035 PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = 0;
6036 ${contextMembers}
6037 };
6038 )";
6039
6040 std::string str = replaceWithMap( contextDispatcherTemplate, { { "contextInitializers", contextInitializers }, { "contextMembers", contextMembers } } );
6041
6042 std::string instanceDispatcherTemplate = R"(
6043 class InstanceDispatcher : public DispatchLoaderBase
6044 {
6045 public:
6046 InstanceDispatcher( PFN_vkGetInstanceProcAddr getProcAddr, VkInstance instance )
6047 : vkGetInstanceProcAddr( getProcAddr )
6048 {
6049 ${instanceAssignments}
6050 vkGetDeviceProcAddr =
6051 PFN_vkGetDeviceProcAddr( vkGetInstanceProcAddr( instance, "vkGetDeviceProcAddr" ) );
6052 }
6053
6054 public:
6055 ${instanceMembers}
6056 PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr = 0;
6057 };
6058 )";
6059
6060 str += replaceWithMap( instanceDispatcherTemplate, { { "instanceAssignments", instanceAssignments }, { "instanceMembers", instanceMembers } } );
6061
6062 std::string deviceDispatcherTemplate = R"(
6063 class DeviceDispatcher : public DispatchLoaderBase
6064 {
6065 public:
6066 DeviceDispatcher( PFN_vkGetDeviceProcAddr getProcAddr, VkDevice device ) : vkGetDeviceProcAddr( getProcAddr )
6067 {
6068 ${deviceAssignments}
6069 }
6070
6071 public:
6072 ${deviceMembers}
6073 };
6074 )";
6075
6076 str += replaceWithMap( deviceDispatcherTemplate, { { "deviceAssignments", deviceAssignments }, { "deviceMembers", deviceMembers } } );
6077 return str;
6078 }
6079
generateRAIIHandle(std::pair<std::string,HandleData> const & handle,std::set<std::string> & listedHandles,std::set<std::string> const & specialFunctions) const6080 std::string VulkanHppGenerator::generateRAIIHandle( std::pair<std::string, HandleData> const & handle,
6081 std::set<std::string> & listedHandles,
6082 std::set<std::string> const & specialFunctions ) const
6083 {
6084 std::string str;
6085 if ( listedHandles.find( handle.first ) == listedHandles.end() )
6086 {
6087 rescheduleRAIIHandle( str, handle, listedHandles, specialFunctions );
6088
6089 auto [enter, leave] = generateProtection( handle.second.alias.empty() ? getProtectFromType( handle.first ) : "" );
6090 std::string handleType = stripPrefix( handle.first, "Vk" );
6091 std::string handleName = generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
6092
6093 auto [singularStaticCreates, arrayStaticCreates] = generateRAIIHandleStaticCreates( handle );
6094 auto [singularConstructors, arrayConstructors] = generateRAIIHandleConstructors( handle );
6095
6096 auto [clearMembers, getConstructorSuccessCode, memberVariables, moveConstructorInitializerList, moveAssignmentInstructions, swapMembers, releaseMembers] =
6097 generateRAIIHandleDetails( handle );
6098
6099 std::string declarations = generateRAIIHandleCommandDeclarations( handle, specialFunctions );
6100
6101 assert( !handle.second.objTypeEnum.empty() );
6102 auto enumIt = m_enums.find( "VkObjectType" );
6103 assert( enumIt != m_enums.end() );
6104 auto valueIt = std::find_if(
6105 enumIt->second.values.begin(), enumIt->second.values.end(), [&handle]( EnumValueData const & evd ) { return evd.name == handle.second.objTypeEnum; } );
6106 assert( valueIt != enumIt->second.values.end() );
6107 std::string objTypeEnum = generateEnumValueName( enumIt->first, valueIt->name, false, m_tags );
6108
6109 enumIt = m_enums.find( "VkDebugReportObjectTypeEXT" );
6110 assert( enumIt != m_enums.end() );
6111 std::string valueName = handle.second.objTypeEnum;
6112 valueName = valueName.replace( 3, 0, "DEBUG_REPORT_" ) + "_EXT";
6113 valueIt =
6114 std::find_if( enumIt->second.values.begin(), enumIt->second.values.end(), [&valueName]( EnumValueData const & evd ) { return valueName == evd.name; } );
6115 std::string debugReportObjectType =
6116 ( valueIt != enumIt->second.values.end() ) ? generateEnumValueName( enumIt->first, valueIt->name, false, m_tags ) : "eUnknown";
6117
6118 std::string dispatcherType = ( ( handle.first == "VkDevice" ) || ( handle.second.constructorIts.front()->second.params.front().type.type == "VkDevice" ) )
6119 ? "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher"
6120 : "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::InstanceDispatcher";
6121
6122 std::string getParent;
6123 if ( ( handle.first != "VkInstance" ) && ( handle.first != "VkDevice" ) && ( handle.second.destructorIt != m_commands.end() ) )
6124 {
6125 assert( !handle.second.destructorIt->second.params.empty() );
6126 std::string parentType = stripPrefix( handle.second.destructorIt->second.params.front().type.type, "Vk" );
6127 getParent = " VULKAN_HPP_NAMESPACE::" + parentType + " get" + parentType + "() const\n";
6128 getParent += " {\n";
6129 getParent += " return m_" + handle.second.destructorIt->second.params.front().name + ";\n";
6130 getParent += " }\n";
6131 }
6132
6133 std::string assignmentOperator, copyConstructor;
6134 if ( handle.second.destructorIt == m_commands.end() )
6135 {
6136 // allow copy constructor and assignment operator for classes without destructor
6137 std::string const copyConstructorTemplate =
6138 R"( ${handleType}( ${handleType} const & rhs ) : m_${handleName}( rhs.m_${handleName} ), m_dispatcher( rhs.m_dispatcher ) {})";
6139 copyConstructor += replaceWithMap( copyConstructorTemplate, { { "handleName", handleName }, { "handleType", handleType } } );
6140
6141 std::string assignmentOperatorTemplate = R"( ${handleType} & operator=( ${handleType} const & rhs )
6142 {
6143 m_${handleName} = rhs.m_${handleName};
6144 m_dispatcher = rhs.m_dispatcher;
6145 return *this;
6146 })";
6147 assignmentOperator += replaceWithMap( assignmentOperatorTemplate, { { "handleName", handleName }, { "handleType", handleType } } );
6148 }
6149 else
6150 {
6151 std::string const copyConstructorTemplate = R"( ${handleType}( ${handleType} const & ) = delete;)";
6152 copyConstructor += replaceWithMap( copyConstructorTemplate, { { "handleType", handleType } } );
6153
6154 std::string const assignmentOperatorTemplate = R"( ${handleType} & operator=( ${handleType} const & ) = delete;)";
6155 assignmentOperator += replaceWithMap( assignmentOperatorTemplate, { { "handleType", handleType } } );
6156 }
6157
6158 const std::string handleTemplate = R"(
6159 ${enter} class ${handleType}
6160 {
6161 public:
6162 using CType = Vk${handleType};
6163
6164 static VULKAN_HPP_CONST_OR_CONSTEXPR VULKAN_HPP_NAMESPACE::ObjectType objectType = VULKAN_HPP_NAMESPACE::ObjectType::${objTypeEnum};
6165 static VULKAN_HPP_CONST_OR_CONSTEXPR VULKAN_HPP_NAMESPACE::DebugReportObjectTypeEXT debugReportObjectType = VULKAN_HPP_NAMESPACE::DebugReportObjectTypeEXT::${debugReportObjectType};
6166
6167 public:
6168 ${singularStaticCreates}
6169 ${singularConstructors}
6170
6171 ${handleType}( std::nullptr_t ) {}
6172
6173 ~${handleType}()
6174 {
6175 clear();
6176 }
6177
6178 ${handleType}() = delete;
6179 ${copyConstructor}
6180 ${handleType}( ${handleType} && rhs ) VULKAN_HPP_NOEXCEPT
6181 : ${moveConstructorInitializerList}
6182 {}
6183 ${assignmentOperator}
6184 ${handleType} & operator=( ${handleType} && rhs ) VULKAN_HPP_NOEXCEPT
6185 {
6186 if ( this != &rhs )
6187 {
6188 ${moveAssignmentInstructions}
6189 }
6190 return *this;
6191 }
6192
6193 VULKAN_HPP_NAMESPACE::${handleType} const & operator*() const VULKAN_HPP_NOEXCEPT
6194 {
6195 return m_${handleName};
6196 }
6197
6198 void clear() VULKAN_HPP_NOEXCEPT
6199 {
6200 ${clearMembers}
6201 }
6202
6203 VULKAN_HPP_NAMESPACE::${handleType} release()
6204 {
6205 ${releaseMembers}
6206 }
6207
6208 ${getConstructorSuccessCode}
6209 ${getParent}
6210 ${dispatcherType} const * getDispatcher() const
6211 {
6212 VULKAN_HPP_ASSERT( m_dispatcher->getVkHeaderVersion() == VK_HEADER_VERSION );
6213 return ${getDispatcherReturn}m_dispatcher;
6214 }
6215
6216 void swap( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::${handleType} & rhs ) VULKAN_HPP_NOEXCEPT
6217 {
6218 ${swapMembers}
6219 }
6220
6221 ${memberFunctionsDeclarations}
6222
6223 private:
6224
6225 ${memberVariables}
6226 };
6227 ${leave})";
6228
6229 str += replaceWithMap( handleTemplate,
6230 { { "assignmentOperator", assignmentOperator },
6231 { "clearMembers", clearMembers },
6232 { "copyConstructor", copyConstructor },
6233 { "debugReportObjectType", debugReportObjectType },
6234 { "dispatcherType", dispatcherType },
6235 { "enter", enter },
6236 { "getConstructorSuccessCode", getConstructorSuccessCode },
6237 { "getDispatcherReturn", ( handleType == "Device" ) || ( handleType == "Instance" ) ? "&*" : "" },
6238 { "getParent", getParent },
6239 { "handleName", handleName },
6240 { "handleType", handleType },
6241 { "leave", leave },
6242 { "memberFunctionsDeclarations", declarations },
6243 { "memberVariables", memberVariables },
6244 { "moveAssignmentInstructions", moveAssignmentInstructions },
6245 { "moveConstructorInitializerList", moveConstructorInitializerList },
6246 { "objTypeEnum", objTypeEnum },
6247 { "releaseMembers", releaseMembers },
6248 { "singularConstructors", singularConstructors },
6249 { "singularStaticCreates", singularStaticCreates },
6250 { "swapMembers", swapMembers } } );
6251
6252 if ( !arrayConstructors.empty() )
6253 {
6254 // it's a handle class with a friendly handles class
6255 const std::string handlesTemplate = R"(
6256 ${enter} class ${handleType}s : public std::vector<VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::${handleType}>
6257 {
6258 public:
6259 ${arrayStaticCreates}
6260 ${arrayConstructors}
6261 ${handleType}s( std::nullptr_t ) {}
6262
6263 ${handleType}s() = delete;
6264 ${handleType}s( ${handleType}s const & ) = delete;
6265 ${handleType}s( ${handleType}s && rhs ) = default;
6266 ${handleType}s & operator=( ${handleType}s const & ) = delete;
6267 ${handleType}s & operator=( ${handleType}s && rhs ) = default;
6268 };
6269 ${leave}
6270 )";
6271
6272 str += replaceWithMap( handlesTemplate,
6273 { { "arrayConstructors", arrayConstructors },
6274 { "arrayStaticCreates", arrayStaticCreates },
6275 { "enter", enter },
6276 { "handleType", handleType },
6277 { "leave", leave } } );
6278 }
6279 }
6280 return str;
6281 }
6282
generateRAIIHandleCommand(std::string const & command,size_t initialSkipCount,bool definition) const6283 std::string VulkanHppGenerator::generateRAIIHandleCommand( std::string const & command, size_t initialSkipCount, bool definition ) const
6284 {
6285 std::string str;
6286 if ( m_RAIISpecialFunctions.find( command ) == m_RAIISpecialFunctions.end() )
6287 {
6288 auto commandIt = m_commands.find( command );
6289 assert( commandIt != m_commands.end() );
6290
6291 if ( commandIt->second.returnType == "VkResult" )
6292 {
6293 str = generateRAIIHandleCommandResult( commandIt, initialSkipCount, definition );
6294 }
6295 else if ( commandIt->second.returnType == "void" )
6296 {
6297 str = generateRAIIHandleCommandVoid( commandIt, initialSkipCount, definition );
6298 }
6299 else
6300 {
6301 str = generateRAIIHandleCommandValue( commandIt, initialSkipCount, definition );
6302 }
6303
6304 if ( str.empty() )
6305 {
6306 throw std::runtime_error( "Never encountered a command like <" + command + "> !" );
6307 }
6308 }
6309 return str;
6310 }
6311
generateRAIIHandleCommandDeclarations(std::pair<std::string,HandleData> const & handle,std::set<std::string> const & specialFunctions) const6312 std::string VulkanHppGenerator::generateRAIIHandleCommandDeclarations( std::pair<std::string, HandleData> const & handle,
6313 std::set<std::string> const & specialFunctions ) const
6314 {
6315 std::string functionDeclarations;
6316 std::set<std::string> listedCommands; // some commands are listed with more than one extension !
6317 for ( auto const & feature : m_features )
6318 {
6319 std::vector<std::string> firstLevelCommands, secondLevelCommands;
6320
6321 for ( auto const & require : feature.second.requireData )
6322 {
6323 for ( auto const & command : require.commands )
6324 {
6325 if ( specialFunctions.find( command ) == specialFunctions.end() )
6326 {
6327 if ( handle.second.commands.find( command ) != handle.second.commands.end() )
6328 {
6329 assert( listedCommands.find( command ) == listedCommands.end() );
6330 listedCommands.insert( command );
6331 firstLevelCommands.push_back( command );
6332 }
6333 else if ( handle.second.secondLevelCommands.find( command ) != handle.second.secondLevelCommands.end() )
6334 {
6335 assert( listedCommands.find( command ) == listedCommands.end() );
6336 listedCommands.insert( command );
6337 assert( !handle.first.empty() );
6338 secondLevelCommands.push_back( command );
6339 }
6340 }
6341 }
6342 }
6343 if ( !firstLevelCommands.empty() || !secondLevelCommands.empty() )
6344 {
6345 functionDeclarations += "\n //=== " + feature.first + " ===\n";
6346 for ( auto const & command : firstLevelCommands )
6347 {
6348 functionDeclarations += generateRAIIHandleCommand( command, handle.first.empty() ? 0 : 1, false );
6349 }
6350 for ( auto const & command : secondLevelCommands )
6351 {
6352 assert( !handle.first.empty() );
6353 functionDeclarations += generateRAIIHandleCommand( command, 2, false );
6354 }
6355 }
6356 }
6357
6358 for ( auto const & extIt : m_extensionsByNumber )
6359 {
6360 std::vector<std::string> firstLevelCommands, secondLevelCommands;
6361 for ( auto & req : extIt.second->second.requireData )
6362 {
6363 for ( auto const & command : req.commands )
6364 {
6365 if ( ( specialFunctions.find( command ) == specialFunctions.end() ) && ( listedCommands.find( command ) == listedCommands.end() ) )
6366 {
6367 if ( handle.second.commands.find( command ) != handle.second.commands.end() )
6368 {
6369 listedCommands.insert( command );
6370 firstLevelCommands.push_back( command );
6371 }
6372 else if ( handle.second.secondLevelCommands.find( command ) != handle.second.secondLevelCommands.end() )
6373 {
6374 listedCommands.insert( command );
6375 secondLevelCommands.push_back( command );
6376 }
6377 }
6378 }
6379 }
6380 if ( !firstLevelCommands.empty() || !secondLevelCommands.empty() )
6381 {
6382 std::string enter, leave;
6383 if ( extIt.second->first != m_types.find( handle.first )->second.referencedIn )
6384 {
6385 std::tie( enter, leave ) = generateProtection( getProtectFromTitle( extIt.second->first ) );
6386 }
6387 functionDeclarations += "\n" + enter + " //=== " + extIt.second->first + " ===\n";
6388 for ( auto const & command : firstLevelCommands )
6389 {
6390 functionDeclarations += generateRAIIHandleCommand( command, handle.first.empty() ? 0 : 1, false );
6391 }
6392 for ( auto const & command : secondLevelCommands )
6393 {
6394 assert( !handle.first.empty() );
6395 functionDeclarations += generateRAIIHandleCommand( command, 2, false );
6396 }
6397 functionDeclarations += leave;
6398 }
6399 }
6400 return functionDeclarations;
6401 }
6402
generateRAIIHandleCommandEnhanced(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,bool definition,CommandFlavourFlags flavourFlags) const6403 std::string VulkanHppGenerator::generateRAIIHandleCommandEnhanced( std::map<std::string, CommandData>::const_iterator commandIt,
6404 size_t initialSkipCount,
6405 std::vector<size_t> const & returnParams,
6406 std::map<size_t, VectorParamData> const & vectorParams,
6407 bool definition,
6408 CommandFlavourFlags flavourFlags ) const
6409 {
6410 bool singular = flavourFlags & CommandFlavourFlagBits::singular;
6411
6412 std::set<size_t> skippedParams = determineSkippedParams( commandIt->second.params, initialSkipCount, vectorParams, returnParams, singular );
6413 std::set<size_t> singularParams = singular ? determineSingularParams( returnParams[0], vectorParams ) : std::set<size_t>();
6414 // special handling for vkGetMemoryHostPointerPropertiesEXT: here, we really need to stick with the const void * parameter !
6415 std::set<size_t> templatedParams =
6416 ( commandIt->first == "vkGetMemoryHostPointerPropertiesEXT" ) ? std::set<size_t>() : determineVoidPointerParams( commandIt->second.params );
6417
6418 bool enumerating = determineEnumeration( vectorParams, returnParams );
6419 std::vector<std::string> dataTypes = determineDataTypes( commandIt->second.params, vectorParams, returnParams, templatedParams );
6420 std::string dataType = combineDataTypes( vectorParams, returnParams, enumerating, dataTypes, flavourFlags, true );
6421
6422 std::string argumentTemplates = generateArgumentTemplates( commandIt->second.params, returnParams, vectorParams, templatedParams, flavourFlags, true );
6423 std::string argumentList = generateArgumentListEnhanced(
6424 commandIt->second.params, returnParams, vectorParams, skippedParams, singularParams, templatedParams, definition, flavourFlags, false );
6425 std::string commandName = generateCommandName( commandIt->first, commandIt->second.params, initialSkipCount, m_tags, flavourFlags );
6426 std::string nodiscard =
6427 generateNoDiscard( !returnParams.empty() || ( ( commandIt->second.returnType != "VkResult" ) && ( commandIt->second.returnType != "void" ) ),
6428 1 < commandIt->second.successCodes.size(),
6429 false );
6430 std::pair<bool, std::map<size_t, std::vector<size_t>>> vectorSizeCheck =
6431 needsVectorSizeCheck( commandIt->second.params, vectorParams, returnParams, singularParams );
6432 std::string noexceptString = generateNoExcept( commandIt->second.errorCodes, returnParams, vectorParams, flavourFlags, vectorSizeCheck.first, true );
6433 std::string returnType = generateReturnType( commandIt->second, returnParams, vectorParams, flavourFlags, true, dataType );
6434
6435 std::string debugHelper = "";
6436 #ifdef DEBUG_GENERATOR
6437 debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
6438 #endif
6439
6440 if ( definition )
6441 {
6442 std::string const definitionTemplate =
6443 R"(
6444 ${argumentTemplates}
6445 ${nodiscard} VULKAN_HPP_INLINE ${returnType} ${className}::${commandName}( ${argumentList} ) const ${noexcept} ${debugHelper}
6446 {
6447 ${functionPointerCheck}
6448 ${vectorSizeCheck}
6449 ${dataSizeChecks}
6450 ${dataDeclarations}
6451 ${callSequence}
6452 ${resultCheck}
6453 ${dataPreparation}
6454 ${returnStatement}
6455 }
6456 )";
6457
6458 std::string callSequence = generateCallSequence(
6459 commandIt->first, commandIt->second, returnParams, vectorParams, initialSkipCount, singularParams, templatedParams, flavourFlags, true );
6460 std::string className = initialSkipCount ? stripPrefix( commandIt->second.params[initialSkipCount - 1].type.type, "Vk" ) : "Context";
6461 std::string returnVariable = generateReturnVariable( commandIt->second, returnParams, vectorParams, flavourFlags );
6462 std::string dataDeclarations = generateDataDeclarations(
6463 commandIt->second, returnParams, vectorParams, templatedParams, flavourFlags, true, dataTypes, dataType, returnType, returnVariable );
6464 std::string dataPreparation =
6465 generateDataPreparation( commandIt->second, initialSkipCount, returnParams, vectorParams, templatedParams, flavourFlags, enumerating );
6466 std::string dataSizeChecks = generateDataSizeChecks( commandIt->second, returnParams, dataTypes, vectorParams, templatedParams, singular );
6467 std::string resultCheck = generateResultCheck( commandIt->second, className, "::", commandName, enumerating );
6468 std::string returnStatement = generateReturnStatement( commandIt->first,
6469 commandIt->second,
6470 returnVariable,
6471 returnType,
6472 dataType,
6473 initialSkipCount,
6474 returnParams.empty() ? INVALID_INDEX : returnParams[0],
6475 flavourFlags,
6476 enumerating,
6477 true );
6478 std::string vectorSizeCheckString =
6479 vectorSizeCheck.first ? generateRAIIHandleVectorSizeCheck( commandIt->first, commandIt->second, initialSkipCount, vectorSizeCheck.second, skippedParams )
6480 : "";
6481
6482 return replaceWithMap( definitionTemplate,
6483 { { "argumentList", argumentList },
6484 { "argumentTemplates", argumentTemplates },
6485 { "callSequence", callSequence },
6486 { "className", className },
6487 { "commandName", commandName },
6488 { "dataDeclarations", dataDeclarations },
6489 { "dataPreparation", dataPreparation },
6490 { "dataSizeChecks", dataSizeChecks },
6491 { "debugHelper", debugHelper },
6492 { "functionPointerCheck", generateFunctionPointerCheck( commandIt->first, commandIt->second.referencedIn ) },
6493 { "nodiscard", nodiscard },
6494 { "noexcept", noexceptString },
6495 { "resultCheck", resultCheck },
6496 { "returnStatement", returnStatement },
6497 { "returnType", returnType },
6498 { "vectorSizeCheck", vectorSizeCheckString } } );
6499 }
6500 else
6501 {
6502 std::string const declarationTemplate =
6503 R"(
6504 ${argumentTemplates}
6505 ${nodiscard} ${returnType} ${commandName}( ${argumentList} ) const ${noexcept};
6506 )";
6507
6508 return replaceWithMap( declarationTemplate,
6509 { { "argumentList", argumentList },
6510 { "argumentTemplates", argumentTemplates },
6511 { "commandName", commandName },
6512 { "nodiscard", nodiscard },
6513 { "noexcept", noexceptString },
6514 { "returnType", returnType } } );
6515 }
6516 }
6517
generateRAIIHandleCommandFactory(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,bool definition,CommandFlavourFlags flavourFlags) const6518 std::string VulkanHppGenerator::generateRAIIHandleCommandFactory( std::map<std::string, CommandData>::const_iterator commandIt,
6519 size_t initialSkipCount,
6520 std::vector<size_t> const & returnParams,
6521 std::map<size_t, VectorParamData> const & vectorParams,
6522 bool definition,
6523 CommandFlavourFlags flavourFlags ) const
6524 {
6525 bool singular = flavourFlags & CommandFlavourFlagBits::singular;
6526
6527 assert( isHandleType( commandIt->second.params[returnParams.back()].type.type ) );
6528 assert( ( returnParams.size() == 1 ) ||
6529 ( ( returnParams.size() == 2 ) && ( vectorParams.size() == 1 ) && ( returnParams[0] == vectorParams.begin()->second.lenParam ) &&
6530 ( returnParams[1] == vectorParams.begin()->first ) ) );
6531
6532 std::set<size_t> skippedParams = determineSkippedParams( commandIt->second.params, initialSkipCount, vectorParams, returnParams, singular );
6533 std::set<size_t> singularParams = singular ? determineSingularParams( returnParams.back(), vectorParams ) : std::set<size_t>();
6534 std::string argumentList = generateRAIIHandleCommandFactoryArgumentList( commandIt->second.params, skippedParams, definition, singular );
6535 std::string commandName = generateCommandName( commandIt->first, commandIt->second.params, initialSkipCount, m_tags, flavourFlags );
6536 std::string handleType = stripPostfix( commandIt->second.params[returnParams.back()].type.compose( "VULKAN_HPP_RAII_NAMESPACE" ), " *" );
6537 std::string returnType = handleType;
6538 if ( ( vectorParams.find( returnParams.back() ) != vectorParams.end() ) && !singular )
6539 {
6540 returnType = "std::vector<" + handleType + ">";
6541 handleType += "s";
6542 }
6543
6544 std::string debugHelper = "";
6545 #ifdef DEBUG_GENERATOR
6546 debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
6547 #endif
6548
6549 if ( definition )
6550 {
6551 std::string callArguments = generateCallArgumentsRAIIFactory( commandIt->second.params, initialSkipCount, skippedParams, singularParams );
6552 std::string className = initialSkipCount ? stripPrefix( commandIt->second.params[initialSkipCount - 1].type.type, "Vk" ) : "Context";
6553
6554 std::string const definitionTemplate =
6555 R"(
6556 #ifndef VULKAN_HPP_NO_EXCEPTIONS
6557 VULKAN_HPP_NODISCARD VULKAN_HPP_INLINE ${returnType} ${className}::${commandName}( ${argumentList} ) const ${debugHelper}
6558 {
6559 return ${handleType}( ${callArguments} );
6560 }
6561 #endif
6562 )";
6563
6564 return replaceWithMap( definitionTemplate,
6565 { { "argumentList", argumentList },
6566 { "callArguments", callArguments },
6567 { "className", className },
6568 { "commandName", commandName },
6569 { "debugHelper", debugHelper },
6570 { "handleType", handleType },
6571 { "returnType", returnType } } );
6572 }
6573 else
6574 {
6575 std::string const declarationTemplate =
6576 R"(
6577 #ifndef VULKAN_HPP_NO_EXCEPTIONS
6578 VULKAN_HPP_NODISCARD ${returnType} ${commandName}( ${argumentList} ) const; ${debugHelper}
6579 #endif
6580 )";
6581
6582 return replaceWithMap( declarationTemplate,
6583 { { "argumentList", argumentList },
6584 { "commandName", commandName },
6585 { "debugHelper", debugHelper },
6586 { "returnType", returnType } } );
6587 }
6588 }
6589
generateRAIIHandleCommandFactoryArgumentList(std::vector<ParamData> const & params,std::set<size_t> const & skippedParams,bool definition,bool singular) const6590 std::string VulkanHppGenerator::generateRAIIHandleCommandFactoryArgumentList( std::vector<ParamData> const & params,
6591 std::set<size_t> const & skippedParams,
6592 bool definition,
6593 bool singular ) const
6594 {
6595 std::string arguments;
6596 bool encounteredArgument = false;
6597 for ( size_t i = 0; i < params.size(); ++i )
6598 {
6599 if ( skippedParams.find( i ) == skippedParams.end() )
6600 {
6601 if ( encounteredArgument )
6602 {
6603 arguments += ", ";
6604 }
6605 arguments += generateRAIIHandleConstructorArgument( params[i], definition, singular, false );
6606 encounteredArgument = true;
6607 }
6608 }
6609 return arguments;
6610 }
6611
generateRAIIHandleCommandResult(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const6612 std::string VulkanHppGenerator::generateRAIIHandleCommandResult( std::map<std::string, CommandData>::const_iterator commandIt,
6613 size_t initialSkipCount,
6614 bool definition ) const
6615 {
6616 assert( !commandIt->second.successCodes.empty() );
6617 if ( commandIt->second.successCodes.size() == 1 )
6618 {
6619 if ( commandIt->second.errorCodes.empty() )
6620 {
6621 return generateRAIIHandleCommandResultSingleSuccessNoErrors( commandIt, initialSkipCount, definition );
6622 }
6623 else
6624 {
6625 return generateRAIIHandleCommandResultSingleSuccessWithErrors( commandIt, initialSkipCount, definition );
6626 }
6627 }
6628 else
6629 {
6630 if ( commandIt->second.errorCodes.empty() )
6631 {
6632 return generateRAIIHandleCommandResultMultiSuccessNoErrors( commandIt, initialSkipCount, definition );
6633 }
6634 else
6635 {
6636 return generateRAIIHandleCommandResultMultiSuccessWithErrors( commandIt, initialSkipCount, definition );
6637 }
6638 }
6639 }
6640
generateRAIIHandleCommandResultMultiSuccessNoErrors(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const6641 std::string VulkanHppGenerator::generateRAIIHandleCommandResultMultiSuccessNoErrors( std::map<std::string, CommandData>::const_iterator commandIt,
6642 size_t initialSkipCount,
6643 bool definition ) const
6644 {
6645 std::vector<size_t> returnParams = determineReturnParams( commandIt->second.params );
6646 switch ( returnParams.size() )
6647 {
6648 case 0:
6649 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, determineVectorParams( commandIt->second.params ), definition );
6650 case 2: return generateRAIIHandleCommandResultMultiSuccessNoErrors2Return( commandIt, initialSkipCount, definition, returnParams );
6651 }
6652 return "";
6653 }
6654
generateRAIIHandleCommandResultMultiSuccessNoErrors2Return(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const6655 std::string VulkanHppGenerator::generateRAIIHandleCommandResultMultiSuccessNoErrors2Return( std::map<std::string, CommandData>::const_iterator commandIt,
6656 size_t initialSkipCount,
6657 bool definition,
6658 std::vector<size_t> const & returnParams ) const
6659 {
6660 if ( ( commandIt->second.successCodes.size() == 2 ) && ( commandIt->second.successCodes[0] == "VK_SUCCESS" ) &&
6661 ( commandIt->second.successCodes[1] == "VK_INCOMPLETE" ) )
6662 {
6663 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6664 if ( vectorParams.size() == 1 )
6665 {
6666 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
6667 {
6668 if ( returnParams[1] == vectorParams.begin()->first )
6669 {
6670 if ( ( commandIt->second.params[returnParams[0]].type.type == "uint32_t" ) || ( commandIt->second.params[returnParams[0]].type.type == "size_t" ) )
6671 {
6672 if ( ( commandIt->second.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandIt->second.params[returnParams[1]].type.type ) &&
6673 !isStructureChainAnchor( commandIt->second.params[returnParams[1]].type.type ) )
6674 {
6675 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
6676 }
6677 }
6678 }
6679 }
6680 }
6681 }
6682 return "";
6683 }
6684
generateRAIIHandleCommandResultMultiSuccessWithErrors(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const6685 std::string VulkanHppGenerator::generateRAIIHandleCommandResultMultiSuccessWithErrors( std::map<std::string, CommandData>::const_iterator commandIt,
6686 size_t initialSkipCount,
6687 bool definition ) const
6688 {
6689 std::vector<size_t> returnParams = determineReturnParams( commandIt->second.params );
6690 switch ( returnParams.size() )
6691 {
6692 case 0:
6693 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, determineVectorParams( commandIt->second.params ), definition );
6694 break;
6695 case 1: return generateRAIIHandleCommandResultMultiSuccessWithErrors1Return( commandIt, initialSkipCount, definition, returnParams[0] ); break;
6696 case 2: return generateRAIIHandleCommandResultMultiSuccessWithErrors2Return( commandIt, initialSkipCount, definition, returnParams ); break;
6697 case 3: return generateRAIIHandleCommandResultMultiSuccessWithErrors3Return( commandIt, initialSkipCount, definition, returnParams ); break;
6698 }
6699 return "";
6700 }
6701
generateRAIIHandleCommandResultMultiSuccessWithErrors1Return(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam) const6702 std::string VulkanHppGenerator::generateRAIIHandleCommandResultMultiSuccessWithErrors1Return( std::map<std::string, CommandData>::const_iterator commandIt,
6703 size_t initialSkipCount,
6704 bool definition,
6705 size_t returnParam ) const
6706 {
6707 if ( commandIt->second.params[returnParam].type.type == "void" )
6708 {
6709 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6710 if ( vectorParams.size() == 1 )
6711 {
6712 if ( returnParam == vectorParams.begin()->first )
6713 {
6714 if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "size_t" )
6715 {
6716 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
6717 generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::singular );
6718 }
6719 }
6720 }
6721 }
6722 else if ( isHandleType( commandIt->second.params[returnParam].type.type ) )
6723 {
6724 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6725 if ( vectorParams.size() == 2 )
6726 {
6727 if ( returnParam == std::next( vectorParams.begin() )->first )
6728 {
6729 if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
6730 {
6731 if ( isStructureChainAnchor( commandIt->second.params[vectorParams.begin()->first].type.type ) )
6732 {
6733 return generateRAIIHandleCommandFactory( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
6734 generateRAIIHandleCommandFactory( commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::singular );
6735 }
6736 }
6737 }
6738 }
6739 }
6740 else
6741 {
6742 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6743 if ( vectorParams.empty() )
6744 {
6745 std::string str = generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition );
6746 if ( isStructureChainAnchor( commandIt->second.params[returnParam].type.type ) )
6747 {
6748 str += generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::chained );
6749 }
6750 return str;
6751 }
6752 }
6753 return "";
6754 }
6755
generateRAIIHandleCommandResultMultiSuccessWithErrors2Return(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const6756 std::string VulkanHppGenerator::generateRAIIHandleCommandResultMultiSuccessWithErrors2Return( std::map<std::string, CommandData>::const_iterator commandIt,
6757 size_t initialSkipCount,
6758 bool definition,
6759 std::vector<size_t> const & returnParams ) const
6760 {
6761 if ( ( commandIt->second.successCodes.size() == 2 ) && ( commandIt->second.successCodes[0] == "VK_SUCCESS" ) &&
6762 ( commandIt->second.successCodes[1] == "VK_INCOMPLETE" ) )
6763 {
6764 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6765 switch ( vectorParams.size() )
6766 {
6767 case 0:
6768 if ( ( commandIt->second.params[returnParams[0]].type.type != "void" ) && !isHandleType( commandIt->second.params[returnParams[0]].type.type ) &&
6769 !isStructureChainAnchor( commandIt->second.params[returnParams[0]].type.type ) )
6770 {
6771 if ( ( commandIt->second.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandIt->second.params[returnParams[1]].type.type ) &&
6772 !isStructureChainAnchor( commandIt->second.params[returnParams[1]].type.type ) )
6773 {
6774 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
6775 }
6776 }
6777 break;
6778 case 1:
6779 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
6780 {
6781 if ( returnParams[1] == vectorParams.begin()->first )
6782 {
6783 if ( ( commandIt->second.params[returnParams[0]].type.type == "uint32_t" ) || ( commandIt->second.params[returnParams[0]].type.type == "size_t" ) )
6784 {
6785 // needs some very special handling of "vkGetSwapchainImagesKHR" !!
6786 if ( isHandleType( commandIt->second.params[returnParams[1]].type.type ) && ( commandIt->first != "vkGetSwapchainImagesKHR" ) )
6787 {
6788 return generateRAIIHandleCommandFactory( commandIt, initialSkipCount, returnParams, vectorParams, definition );
6789 }
6790 else
6791 {
6792 std::string str = generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
6793 if ( isStructureChainAnchor( commandIt->second.params[returnParams[1]].type.type ) )
6794 {
6795 str +=
6796 generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition, CommandFlavourFlagBits::chained );
6797 }
6798 return str;
6799 }
6800 }
6801 }
6802 }
6803 break;
6804 }
6805 }
6806 return "";
6807 }
6808
generateRAIIHandleCommandResultMultiSuccessWithErrors3Return(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const6809 std::string VulkanHppGenerator::generateRAIIHandleCommandResultMultiSuccessWithErrors3Return( std::map<std::string, CommandData>::const_iterator commandIt,
6810 size_t initialSkipCount,
6811 bool definition,
6812 std::vector<size_t> const & returnParams ) const
6813 {
6814 if ( commandIt->second.params[returnParams[0]].type.type == "uint32_t" )
6815 {
6816 if ( ( commandIt->second.params[returnParams[1]].type.type != "void" ) && !isHandleType( commandIt->second.params[returnParams[1]].type.type ) &&
6817 !isStructureChainAnchor( commandIt->second.params[returnParams[1]].type.type ) )
6818 {
6819 if ( ( commandIt->second.params[returnParams[2]].type.type != "void" ) && !isHandleType( commandIt->second.params[returnParams[2]].type.type ) &&
6820 !isStructureChainAnchor( commandIt->second.params[returnParams[2]].type.type ) )
6821 {
6822 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6823 if ( vectorParams.size() == 2 )
6824 {
6825 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
6826 {
6827 if ( returnParams[1] == vectorParams.begin()->first )
6828 {
6829 if ( returnParams[2] == std::next( vectorParams.begin() )->first )
6830 {
6831 if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
6832 {
6833 if ( ( commandIt->second.successCodes.size() == 2 ) && ( commandIt->second.successCodes[0] == "VK_SUCCESS" ) &&
6834 ( commandIt->second.successCodes[1] == "VK_INCOMPLETE" ) )
6835 {
6836 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
6837 }
6838 }
6839 }
6840 }
6841 }
6842 }
6843 }
6844 }
6845 }
6846 return "";
6847 }
6848
generateRAIIHandleCommandResultSingleSuccessNoErrors(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const6849 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessNoErrors( std::map<std::string, CommandData>::const_iterator commandIt,
6850 size_t initialSkipCount,
6851 bool definition ) const
6852 {
6853 std::vector<size_t> returnParams = determineReturnParams( commandIt->second.params );
6854 if ( returnParams.size() < 2 )
6855 {
6856 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6857 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
6858 }
6859 return "";
6860 }
6861
generateRAIIHandleCommandResultSingleSuccessWithErrors(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const6862 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors( std::map<std::string, CommandData>::const_iterator commandIt,
6863 size_t initialSkipCount,
6864 bool definition ) const
6865 {
6866 std::vector<size_t> returnParams = determineReturnParams( commandIt->second.params );
6867 switch ( returnParams.size() )
6868 {
6869 case 0:
6870 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, determineVectorParams( commandIt->second.params ), definition );
6871 break;
6872 case 1: return generateRAIIHandleCommandResultSingleSuccessWithErrors1Return( commandIt, initialSkipCount, definition, returnParams[0] ); break;
6873 case 2: return generateRAIIHandleCommandResultSingleSuccessWithErrors2Return( commandIt, initialSkipCount, definition, returnParams ); break;
6874 }
6875 return "";
6876 }
6877
generateRAIIHandleCommandResultSingleSuccessWithErrors1Return(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam) const6878 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors1Return( std::map<std::string, CommandData>::const_iterator commandIt,
6879 size_t initialSkipCount,
6880 bool definition,
6881 size_t returnParam ) const
6882 {
6883 if ( commandIt->second.params[returnParam].type.type == "void" )
6884 {
6885 return generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnVoid( commandIt, initialSkipCount, definition, returnParam );
6886 }
6887 else if ( isHandleType( commandIt->second.params[returnParam].type.type ) )
6888 {
6889 return generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnHandle( commandIt, initialSkipCount, definition, returnParam );
6890 }
6891 else if ( isStructureChainAnchor( commandIt->second.params[returnParam].type.type ) )
6892 {
6893 return generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnChain( commandIt, initialSkipCount, definition, returnParam );
6894 }
6895 else
6896 {
6897 return generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnValue( commandIt, initialSkipCount, definition, returnParam );
6898 }
6899 }
6900
generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnChain(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam) const6901 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnChain(
6902 std::map<std::string, CommandData>::const_iterator commandIt, size_t initialSkipCount, bool definition, size_t returnParam ) const
6903 {
6904 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6905 if ( vectorParams.empty() )
6906 {
6907 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
6908 generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::chained );
6909 }
6910 return "";
6911 }
6912
generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnHandle(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam) const6913 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnHandle(
6914 std::map<std::string, CommandData>::const_iterator commandIt, size_t initialSkipCount, bool definition, size_t returnParam ) const
6915 {
6916 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6917 switch ( vectorParams.size() )
6918 {
6919 case 0: return generateRAIIHandleCommandFactory( commandIt, initialSkipCount, { returnParam }, vectorParams, definition );
6920 case 1:
6921 if ( returnParam == vectorParams.begin()->first )
6922 {
6923 if ( m_structures.find( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type ) != m_structures.end() )
6924 {
6925 return generateRAIIHandleCommandFactory( commandIt, initialSkipCount, { returnParam }, vectorParams, definition );
6926 }
6927 }
6928 break;
6929 case 2:
6930 if ( returnParam == std::next( vectorParams.begin() )->first )
6931 {
6932 if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
6933 {
6934 if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
6935 {
6936 if ( ( commandIt->second.params[vectorParams.begin()->first].type.type != "void" ) &&
6937 !isHandleType( commandIt->second.params[vectorParams.begin()->first].type.type ) )
6938 {
6939 return generateRAIIHandleCommandFactory( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
6940 generateRAIIHandleCommandFactory(
6941 commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::singular );
6942 }
6943 }
6944 }
6945 }
6946 break;
6947 }
6948 return "";
6949 }
6950
generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnValue(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam) const6951 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnValue(
6952 std::map<std::string, CommandData>::const_iterator commandIt, size_t initialSkipCount, bool definition, size_t returnParam ) const
6953 {
6954 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6955 switch ( vectorParams.size() )
6956 {
6957 case 0: return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition );
6958 case 2:
6959 return generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnValue2Vectors( commandIt, initialSkipCount, definition, returnParam, vectorParams );
6960 }
6961 return "";
6962 }
6963
6964 std::string
generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnValue2Vectors(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam,std::map<size_t,VectorParamData> const & vectorParams) const6965 VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnValue2Vectors( std::map<std::string, CommandData>::const_iterator commandIt,
6966 size_t initialSkipCount,
6967 bool definition,
6968 size_t returnParam,
6969 std::map<size_t, VectorParamData> const & vectorParams ) const
6970 {
6971 if ( returnParam == std::next( vectorParams.begin() )->first )
6972 {
6973 if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
6974 {
6975 if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
6976 {
6977 if ( ( commandIt->second.params[vectorParams.begin()->first].type.type != "void" ) &&
6978 !isHandleType( commandIt->second.params[vectorParams.begin()->first].type.type ) &&
6979 !isStructureChainAnchor( commandIt->second.params[vectorParams.begin()->first].type.type ) )
6980 {
6981 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
6982 generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::singular );
6983 }
6984 }
6985 }
6986 }
6987 return "";
6988 }
6989
generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnVoid(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,size_t returnParam) const6990 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors1ReturnVoid( std::map<std::string, CommandData>::const_iterator commandIt,
6991 size_t initialSkipCount,
6992 bool definition,
6993 size_t returnParam ) const
6994 {
6995 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
6996 switch ( vectorParams.size() )
6997 {
6998 case 0: return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition );
6999 case 1:
7000 if ( returnParam == vectorParams.begin()->first )
7001 {
7002 if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "size_t" )
7003 {
7004 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
7005 generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::singular );
7006 }
7007 }
7008 break;
7009 case 2:
7010 if ( returnParam == std::next( vectorParams.begin() )->first )
7011 {
7012 if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
7013 {
7014 if ( isHandleType( commandIt->second.params[vectorParams.begin()->first].type.type ) )
7015 {
7016 if ( commandIt->second.params[std::next( vectorParams.begin() )->second.lenParam].type.type == "size_t" )
7017 {
7018 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, { returnParam }, vectorParams, definition ) +
7019 generateRAIIHandleCommandEnhanced(
7020 commandIt, initialSkipCount, { returnParam }, vectorParams, definition, CommandFlavourFlagBits::singular );
7021 }
7022 }
7023 }
7024 }
7025 break;
7026 }
7027 return "";
7028 }
7029
generateRAIIHandleCommandResultSingleSuccessWithErrors2Return(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition,std::vector<size_t> const & returnParams) const7030 std::string VulkanHppGenerator::generateRAIIHandleCommandResultSingleSuccessWithErrors2Return( std::map<std::string, CommandData>::const_iterator commandIt,
7031 size_t initialSkipCount,
7032 bool definition,
7033 std::vector<size_t> const & returnParams ) const
7034 {
7035 if ( commandIt->second.params[returnParams[0]].type.type == "uint64_t" )
7036 {
7037 if ( commandIt->second.params[returnParams[1]].type.type == "uint64_t" )
7038 {
7039 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
7040 if ( vectorParams.size() == 2 )
7041 {
7042 if ( returnParams[0] == std::next( vectorParams.begin() )->first )
7043 {
7044 assert( returnParams[1] != std::next( vectorParams.begin() )->second.lenParam );
7045 if ( returnParams[1] != vectorParams.begin()->first )
7046 {
7047 assert( returnParams[1] != vectorParams.begin()->second.lenParam );
7048 if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
7049 {
7050 if ( commandIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
7051 {
7052 if ( ( commandIt->second.params[vectorParams.begin()->first].type.type != "void" ) &&
7053 !isHandleType( commandIt->second.params[vectorParams.begin()->first].type.type ) &&
7054 !isStructureChainAnchor( commandIt->second.params[vectorParams.begin()->first].type.type ) )
7055 {
7056 // two returns and two vectors! But one input vector, one output vector of the same size,
7057 // and one output value
7058 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition ) +
7059 generateRAIIHandleCommandEnhanced(
7060 commandIt, initialSkipCount, returnParams, vectorParams, definition, CommandFlavourFlagBits::singular );
7061 }
7062 }
7063 }
7064 }
7065 }
7066 }
7067 }
7068 }
7069 return "";
7070 }
7071
generateRAIIHandleCommandValue(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const7072 std::string VulkanHppGenerator::generateRAIIHandleCommandValue( std::map<std::string, CommandData>::const_iterator commandIt,
7073 size_t initialSkipCount,
7074 bool definition ) const
7075 {
7076 std::vector<size_t> returnParams = determineReturnParams( commandIt->second.params );
7077 if ( returnParams.empty() )
7078 {
7079 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
7080 if ( vectorParams.size() <= 1 )
7081 {
7082 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7083 }
7084 }
7085 return "";
7086 }
7087
generateRAIIHandleCommandVoid(std::map<std::string,CommandData>::const_iterator commandIt,size_t initialSkipCount,bool definition) const7088 std::string VulkanHppGenerator::generateRAIIHandleCommandVoid( std::map<std::string, CommandData>::const_iterator commandIt,
7089 size_t initialSkipCount,
7090 bool definition ) const
7091 {
7092 std::vector<size_t> returnParams = determineReturnParams( commandIt->second.params );
7093 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( commandIt->second.params );
7094 switch ( returnParams.size() )
7095 {
7096 case 0: return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7097 case 1:
7098 if ( commandIt->second.params[returnParams[0]].type.type == "void" )
7099 {
7100 if ( commandIt->second.params[returnParams[0]].type.postfix == "**" )
7101 {
7102 // get a pointer to something
7103 if ( vectorParams.empty() )
7104 {
7105 return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7106 }
7107 }
7108 else
7109 {
7110 switch ( vectorParams.size() )
7111 {
7112 case 0: return generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7113 case 1:
7114 {
7115 auto returnVectorParamIt = vectorParams.find( returnParams[0] );
7116 if ( returnVectorParamIt != vectorParams.end() )
7117 {
7118 return generateRAIIHandleCommandEnhanced(
7119 commandIt, initialSkipCount, returnParams, vectorParams, definition, CommandFlavourFlagBits::singular );
7120 }
7121 }
7122 break;
7123 }
7124 }
7125 }
7126 else if ( isHandleType( commandIt->second.params[returnParams[0]].type.type ) )
7127 {
7128 if ( vectorParams.empty() )
7129 {
7130 return generateRAIIHandleCommandFactory( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7131 }
7132 }
7133 else
7134 {
7135 auto returnVectorParamIt = vectorParams.find( returnParams[0] );
7136 if ( returnVectorParamIt == vectorParams.end() )
7137 {
7138 std::string str = generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7139 if ( isStructureChainAnchor( commandIt->second.params[returnParams[0]].type.type ) )
7140 {
7141 str += generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition, CommandFlavourFlagBits::chained );
7142 }
7143 return str;
7144 }
7145 }
7146 break;
7147 case 2:
7148 if ( commandIt->second.params[returnParams[0]].type.type == "uint32_t" )
7149 {
7150 if ( vectorParams.size() == 1 )
7151 {
7152 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
7153 {
7154 if ( returnParams[1] == vectorParams.begin()->first )
7155 {
7156 std::string str = generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition );
7157 if ( isStructureChainAnchor( commandIt->second.params[returnParams[1]].type.type ) )
7158 {
7159 str +=
7160 generateRAIIHandleCommandEnhanced( commandIt, initialSkipCount, returnParams, vectorParams, definition, CommandFlavourFlagBits::chained );
7161 }
7162 return str;
7163 }
7164 }
7165 }
7166 }
7167 break;
7168 }
7169 return "";
7170 }
7171
7172 std::pair<std::string, std::string>
generateRAIIHandleStaticCreate(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const7173 VulkanHppGenerator::generateRAIIHandleStaticCreate( std::pair<std::string, HandleData> const & handle,
7174 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7175 std::string const & enter,
7176 std::string const & leave ) const
7177 {
7178 std::string singularConstructor, arrayConstructor;
7179
7180 if ( constructorIt->second.returnType == "VkResult" )
7181 {
7182 std::tie( singularConstructor, arrayConstructor ) = generateRAIIHandleStaticCreateResult( handle, constructorIt, enter, leave );
7183 }
7184 else if ( constructorIt->second.returnType == "void" )
7185 {
7186 // If the return type of the construct method does not return a VkResult, and thus can not fail,
7187 // and thus does not throw an exception, a static create method is not needed.
7188 }
7189 else
7190 {
7191 if ( singularConstructor.empty() && arrayConstructor.empty() )
7192 {
7193 throw std::runtime_error( "Never encountered a function like <" + constructorIt->first + "> !" );
7194 }
7195 }
7196 return std::make_pair( singularConstructor, arrayConstructor );
7197 }
7198
7199
7200 std::pair<std::string, std::string>
generateRAIIHandleConstructor(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const7201 VulkanHppGenerator::generateRAIIHandleConstructor( std::pair<std::string, HandleData> const & handle,
7202 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7203 std::string const & enter,
7204 std::string const & leave ) const
7205 {
7206 std::string singularConstructor, arrayConstructor;
7207 if ( constructorIt->second.returnType == "VkResult" )
7208 {
7209 std::tie( singularConstructor, arrayConstructor ) = generateRAIIHandleConstructorResult( handle, constructorIt, enter, leave );
7210 }
7211 else if ( constructorIt->second.returnType == "void" )
7212 {
7213 std::tie( singularConstructor, arrayConstructor ) = generateRAIIHandleConstructorVoid( handle, constructorIt, enter, leave );
7214 }
7215 if ( singularConstructor.empty() && arrayConstructor.empty() )
7216 {
7217 throw std::runtime_error( "Never encountered a function like <" + constructorIt->first + "> !" );
7218 }
7219 return std::make_pair( singularConstructor, arrayConstructor );
7220 }
7221
7222 std::pair<std::string, std::string>
generateRAIIHandleStaticCreate1Return2Vector(std::pair<std::string,HandleData> const & handle,std::map<std::string,CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave,size_t returnParam,std::map<size_t,VectorParamData> const & vectorParams) const7223 VulkanHppGenerator::generateRAIIHandleStaticCreate1Return2Vector( std::pair<std::string, HandleData> const & handle,
7224 std::map<std::string, CommandData>::const_iterator constructorIt,
7225 std::string const & enter,
7226 std::string const & leave,
7227 size_t returnParam,
7228 std::map<size_t, VectorParamData> const & vectorParams ) const
7229 {
7230 if ( returnParam == std::next( vectorParams.begin() )->first )
7231 {
7232 if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
7233 {
7234 if ( constructorIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
7235 {
7236 if ( ( constructorIt->second.params[vectorParams.begin()->first].type.type != "void" ) &&
7237 !isHandleType( constructorIt->second.params[vectorParams.begin()->first].type.type ) )
7238 {
7239 std::string singularConstructor;
7240 auto lenParamIt = constructorIt->second.params.begin() + vectorParams.begin()->second.lenParam;
7241 auto handleParamIt = constructorIt->second.params.begin() + std::next( vectorParams.begin() )->first;
7242 if ( !checkEquivalentSingularConstructor( handle.second.constructorIts, constructorIt, lenParamIt ) )
7243 {
7244 singularConstructor = generateRAIIHandleStaticCreateVectorSingular( handle, constructorIt, handleParamIt, enter, leave );
7245 }
7246 return std::make_pair( singularConstructor, generateRAIIHandleStaticCreateVector( handle, constructorIt, handleParamIt, enter, leave ) );
7247 }
7248 }
7249 }
7250 }
7251 return std::make_pair( "", "" );
7252 }
7253
7254 std::pair<std::string, std::string>
generateRAIIHandleConstructor1Return2Vector(std::pair<std::string,HandleData> const & handle,std::map<std::string,CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave,size_t returnParam,std::map<size_t,VectorParamData> const & vectorParams) const7255 VulkanHppGenerator::generateRAIIHandleConstructor1Return2Vector( std::pair<std::string, HandleData> const & handle,
7256 std::map<std::string, CommandData>::const_iterator constructorIt,
7257 std::string const & enter,
7258 std::string const & leave,
7259 size_t returnParam,
7260 std::map<size_t, VectorParamData> const & vectorParams ) const
7261 {
7262 if ( returnParam == std::next( vectorParams.begin() )->first )
7263 {
7264 if ( vectorParams.begin()->second.lenParam == std::next( vectorParams.begin() )->second.lenParam )
7265 {
7266 if ( constructorIt->second.params[vectorParams.begin()->second.lenParam].type.type == "uint32_t" )
7267 {
7268 if ( ( constructorIt->second.params[vectorParams.begin()->first].type.type != "void" ) &&
7269 !isHandleType( constructorIt->second.params[vectorParams.begin()->first].type.type ) )
7270 {
7271 std::string singularConstructor;
7272 auto lenParamIt = constructorIt->second.params.begin() + vectorParams.begin()->second.lenParam;
7273 auto handleParamIt = constructorIt->second.params.begin() + std::next( vectorParams.begin() )->first;
7274 if ( !checkEquivalentSingularConstructor( handle.second.constructorIts, constructorIt, lenParamIt ) )
7275 {
7276 singularConstructor = generateRAIIHandleConstructorVectorSingular( handle, constructorIt, handleParamIt, enter, leave );
7277 }
7278 return std::make_pair( singularConstructor, generateRAIIHandleConstructorVector( handle, constructorIt, handleParamIt, enter, leave ) );
7279 }
7280 }
7281 }
7282 }
7283 return std::make_pair( "", "" );
7284 }
7285
generateRAIIHandleStaticCreates(std::pair<std::string,HandleData> const & handle) const7286 std::pair<std::string, std::string> VulkanHppGenerator::generateRAIIHandleStaticCreates( std::pair<std::string, HandleData> const & handle ) const
7287 {
7288 auto [enter, leave] = generateProtection( handle.second.alias.empty() ? getProtectFromType( handle.first ) : "" );
7289
7290 std::string singularConstructors, arrayConstructors;
7291 for ( auto constructorIt : handle.second.constructorIts )
7292 {
7293 // there is a non-const parameter with handle type : the to-be-constructed handle
7294
7295 // check for additional enter/leave guards for the constructors
7296 auto [constructorEnter, constructorLeave] = generateProtection( getProtectFromTitle( constructorIt->second.referencedIn ) );
7297 if ( constructorEnter == enter )
7298 {
7299 constructorEnter.clear();
7300 constructorLeave.clear();
7301 }
7302
7303 auto [singularConstructor, arrayConstructor] = generateRAIIHandleStaticCreate( handle, constructorIt, constructorEnter, constructorLeave );
7304 arrayConstructors += arrayConstructor;
7305 singularConstructors += singularConstructor;
7306 }
7307 return std::make_pair( singularConstructors, arrayConstructors );
7308 }
7309
generateRAIIHandleConstructors(std::pair<std::string,HandleData> const & handle) const7310 std::pair<std::string, std::string> VulkanHppGenerator::generateRAIIHandleConstructors( std::pair<std::string, HandleData> const & handle ) const
7311 {
7312 auto [enter, leave] = generateProtection( handle.second.alias.empty() ? getProtectFromType( handle.first ) : "" );
7313
7314 std::string singularConstructors, arrayConstructors;
7315 for ( auto constructorIt : handle.second.constructorIts )
7316 {
7317 // there is a non-const parameter with handle type : the to-be-constructed handle
7318
7319 // check for additional enter/leave guards for the constructors
7320 auto [constructorEnter, constructorLeave] = generateProtection( getProtectFromTitle( constructorIt->second.referencedIn ) );
7321 if ( constructorEnter == enter )
7322 {
7323 constructorEnter.clear();
7324 constructorLeave.clear();
7325 }
7326
7327 auto [singularConstructor, arrayConstructor] = generateRAIIHandleConstructor( handle, constructorIt, constructorEnter, constructorLeave );
7328 arrayConstructors += arrayConstructor;
7329 singularConstructors += singularConstructor;
7330 }
7331 singularConstructors += generateRAIIHandleConstructorTakeOwnership( handle );
7332 return std::make_pair( singularConstructors, arrayConstructors );
7333 }
7334
generateRAIIHandleConstructorArgument(ParamData const & param,bool definition,bool singular,bool takesOwnership) const7335 std::string VulkanHppGenerator::generateRAIIHandleConstructorArgument( ParamData const & param, bool definition, bool singular, bool takesOwnership ) const
7336 {
7337 std::string argument;
7338 if ( param.type.isConstPointer() )
7339 {
7340 assert( param.type.type.starts_with( "Vk" ) );
7341 assert( param.name.starts_with( "p" ) );
7342 std::string argumentName = startLowerCase( stripPrefix( param.name, "p" ) );
7343 std::string argumentType = generateNamespacedType( param.type.type );
7344 if ( param.optional )
7345 {
7346 assert( param.len.empty() );
7347 argument = "VULKAN_HPP_NAMESPACE::Optional<const " + argumentType + "> " + argumentName + ( definition ? "" : " = nullptr" );
7348 }
7349 else if ( param.len.empty() )
7350 {
7351 argument = argumentType + " const & " + argumentName;
7352 }
7353 else if ( singular )
7354 {
7355 argument = argumentType + " const & " + stripPluralS( argumentName, m_tags );
7356 }
7357 else
7358 {
7359 argument = "VULKAN_HPP_NAMESPACE::ArrayProxy<" + argumentType + "> const & " + argumentName;
7360 }
7361 }
7362 else if ( specialPointerTypes.find( param.type.type ) != specialPointerTypes.end() )
7363 {
7364 assert( !param.optional );
7365 assert( param.type.isNonConstPointer() );
7366 argument = param.type.type + " & " + param.name;
7367 }
7368 else if ( ( param.type.isValue() ) && isHandleType( param.type.type ) )
7369 {
7370 if ( takesOwnership )
7371 {
7372 assert( !param.optional );
7373 argument = param.type.type + " " + param.name;
7374 }
7375 else
7376 {
7377 argument = "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::" + stripPrefix( param.type.type, "Vk" );
7378 if ( param.optional )
7379 {
7380 argument = "VULKAN_HPP_NAMESPACE::Optional<const " + argument + ">";
7381 }
7382 argument += " const & " + param.name;
7383 }
7384 }
7385 else
7386 {
7387 assert( !param.optional );
7388 if ( param.arraySizes.empty() )
7389 {
7390 argument = param.type.compose( "VULKAN_HPP_NAMESPACE" ) + " ";
7391 }
7392 else
7393 {
7394 argument = generateStandardArray( param.type.compose( "VULKAN_HPP_NAMESPACE" ), param.arraySizes ) + " const & ";
7395 }
7396 argument += param.name;
7397 }
7398 return argument;
7399 }
7400
generateRAIIHandleConstructorArguments(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,bool singular,bool takesOwnership) const7401 std::string VulkanHppGenerator::generateRAIIHandleConstructorArguments( std::pair<std::string, HandleData> const & handle,
7402 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7403 bool singular,
7404 bool takesOwnership ) const
7405 {
7406 auto [parentType, parentName] = getParentTypeAndName( handle );
7407
7408 std::string arguments = "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::" + parentType + " const & " + parentName;
7409 if ( takesOwnership )
7410 {
7411 arguments += ", " + handle.first + " " + generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
7412 }
7413
7414 if ( constructorIt != m_commands.end() )
7415 {
7416 parentType = "Vk" + parentType;
7417 bool skip = skipLeadingGrandParent( handle );
7418 for ( size_t i = skip ? 1 : 0; i < constructorIt->second.params.size(); i++ )
7419 {
7420 ParamData const & param = constructorIt->second.params[i];
7421 // filter parent and handle type
7422 if ( ( param.type.type != parentType ) && ( param.type.type != handle.first ) )
7423 {
7424 // the specialPointerTypes are considered const-pointers!
7425 if ( param.type.isNonConstPointer() && ( specialPointerTypes.find( param.type.type ) == specialPointerTypes.end() ) )
7426 {
7427 // this is supposed to be the returned size on an enumeration function!
7428 #if !defined( NDEBUG )
7429 assert( param.type.type == "uint32_t" );
7430 auto typeIt = std::find_if( constructorIt->second.params.begin(),
7431 constructorIt->second.params.end(),
7432 [&handle]( ParamData const & pd ) { return pd.type.type == handle.first; } );
7433 assert( typeIt != constructorIt->second.params.end() );
7434 assert( typeIt->len == param.name );
7435 #endif
7436 continue;
7437 }
7438 else if ( std::find_if( constructorIt->second.params.begin(),
7439 constructorIt->second.params.end(),
7440 [¶m]( ParamData const & pd ) { return pd.len == param.name; } ) != constructorIt->second.params.end() )
7441 {
7442 // this is the len of an other parameter, which will be mapped to an ArrayProxy
7443 assert( param.type.isValue() && ( param.type.type == "uint32_t" ) );
7444 assert( param.arraySizes.empty() && param.len.empty() && !param.optional );
7445 continue;
7446 }
7447 arguments += ", " + generateRAIIHandleConstructorArgument( param, false, singular, takesOwnership );
7448 }
7449 }
7450 }
7451 return arguments;
7452 }
7453
7454 std::string
generateRAIIHandleConstructorCallArguments(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,bool nonConstPointerAsNullptr,std::set<size_t> const & singularParams,bool allocatorIsMemberVariable,bool handleParamsAreMembers) const7455 VulkanHppGenerator::generateRAIIHandleConstructorCallArguments( std::pair<std::string, HandleData> const & handle,
7456 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7457 bool nonConstPointerAsNullptr,
7458 std::set<size_t> const & singularParams,
7459 bool allocatorIsMemberVariable,
7460 bool handleParamsAreMembers ) const
7461 {
7462 std::string arguments;
7463 bool encounteredArgument = false;
7464 size_t i = 0;
7465 if ( skipLeadingGrandParent( handle ) )
7466 {
7467 assert( ( 1 < constructorIt->second.params.size() ) && ( m_handles.find( constructorIt->second.params[0].type.type ) != m_handles.end() ) &&
7468 ( m_handles.find( constructorIt->second.params[1].type.type ) != m_handles.end() ) );
7469 arguments += "static_cast<" + constructorIt->second.params[0].type.type + ">( " + constructorIt->second.params[1].name + ".get" +
7470 stripPrefix( constructorIt->second.params[0].type.type, "Vk" ) + "() )";
7471 encounteredArgument = true;
7472 i = 1;
7473 }
7474 for ( ; i < constructorIt->second.params.size(); ++i )
7475 {
7476 ParamData const & param = constructorIt->second.params[i];
7477 if ( encounteredArgument )
7478 {
7479 arguments += ", ";
7480 }
7481 if ( param.type.type == handle.first )
7482 {
7483 assert( param.type.isNonConstPointer() && param.arraySizes.empty() );
7484 if ( param.len.empty() || !singularParams.empty() )
7485 {
7486 assert( !param.optional );
7487 assert( singularParams.empty() || ( param.len == constructorIt->second.params[*singularParams.begin()].name ) );
7488 std::string paramName = generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
7489 if (handleParamsAreMembers) {
7490 paramName = "m_" + paramName;
7491 }
7492 arguments += "reinterpret_cast<" + handle.first + "*>( &" + paramName + " )";
7493 }
7494 else if ( nonConstPointerAsNullptr )
7495 {
7496 arguments += "nullptr";
7497 }
7498 else
7499 {
7500 arguments += startLowerCase( stripPrefix( param.name, "p" ) ) + ".data()";
7501 }
7502 }
7503 else if ( param.type.type == "VkAllocationCallbacks" )
7504 {
7505 assert( param.optional );
7506 if ( allocatorIsMemberVariable )
7507 {
7508 arguments += "reinterpret_cast<const VkAllocationCallbacks *>( m_allocator )";
7509 }
7510 else
7511 {
7512 arguments += "reinterpret_cast<const VkAllocationCallbacks *>(static_cast<const VULKAN_HPP_NAMESPACE::AllocationCallbacks *>( allocator ) )";
7513 }
7514 }
7515 else if ( m_handles.find( param.type.type ) != m_handles.end() )
7516 {
7517 assert( param.type.isValue() && param.arraySizes.empty() && param.len.empty() );
7518 if ( param.optional )
7519 {
7520 arguments += param.name + " ? static_cast<" + param.type.type + ">( **" + param.name + " ) : 0";
7521 }
7522 else
7523 {
7524 arguments += "static_cast<" + param.type.type + ">( *" + param.name + " )";
7525 }
7526 }
7527 else
7528 {
7529 assert( !param.optional );
7530 arguments += generateCallArgumentEnhanced( constructorIt->second.params, i, nonConstPointerAsNullptr, singularParams, {} );
7531 }
7532 encounteredArgument = true;
7533 }
7534 return arguments;
7535 }
7536
generateRAIIHandleStaticCreateEnumerate(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator handleParamIt,std::vector<ParamData>::const_iterator lenParamIt,std::string const & enter,std::string const & leave) const7537 std::string VulkanHppGenerator::generateRAIIHandleStaticCreateEnumerate( std::pair<std::string, HandleData> const & handle,
7538 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7539 std::vector<ParamData>::const_iterator handleParamIt,
7540 std::vector<ParamData>::const_iterator lenParamIt,
7541 std::string const & enter,
7542 std::string const & leave ) const
7543 {
7544 std::string handleConstructorArguments = generateRAIIHandleSingularConstructorArguments( handle, constructorIt );
7545 std::string handleType = stripPrefix( handle.first, "Vk" );
7546 std::string dispatcherType = hasParentHandle( handle.first, "VkDevice" ) ? "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher"
7547 : "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::InstanceDispatcher";
7548 std::string debugHelper = "";
7549 #ifdef DEBUG_GENERATOR
7550 debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
7551 #endif
7552
7553 const std::string constructorTemplate =
7554 R"(
7555 ${enter}
7556 static android::base::expected<${handleType}s, VULKAN_HPP_NAMESPACE::Result> create( ${constructorArguments} ) ${debugHelper}
7557 {
7558 ${dispatcherType} const * dispatcher = ${parentName}.getDispatcher();
7559 std::vector<${vectorElementType}> ${vectorName};
7560 ${counterType} ${counterName};
7561 VULKAN_HPP_NAMESPACE::Result result;
7562 do
7563 {
7564 result = static_cast<VULKAN_HPP_NAMESPACE::Result>( dispatcher->${constructorCall}( ${firstCallArguments} ) );
7565 if ( ( result == VULKAN_HPP_NAMESPACE::Result::eSuccess ) && ${counterName} )
7566 {
7567 ${vectorName}.resize( ${counterName} );
7568 result = static_cast<VULKAN_HPP_NAMESPACE::Result>( dispatcher->${constructorCall}( ${secondCallArguments} ) );
7569 }
7570 } while ( result == VULKAN_HPP_NAMESPACE::Result::eIncomplete );
7571 if ( result != VULKAN_HPP_NAMESPACE::Result::eSuccess )
7572 {
7573 return android::base::unexpected(result);
7574 }
7575 ${handleType}s ret(nullptr);
7576 ret.reserve( ${counterName} );
7577 for ( auto const & ${handleName} : ${vectorName} )
7578 {
7579 ret.emplace_back( ${parentName}, ${handleConstructorArguments} );
7580 }
7581 return std::move(ret);
7582 }
7583 ${leave})";
7584
7585 return replaceWithMap( constructorTemplate,
7586 { { "constructorArguments", generateRAIIHandleConstructorArguments( handle, constructorIt, false, false ) },
7587 { "constructorCall", constructorIt->first },
7588 { "counterName", startLowerCase( stripPrefix( lenParamIt->name, "p" ) ) },
7589 { "counterType", lenParamIt->type.type },
7590 { "debugHelper", debugHelper },
7591 { "dispatcherType", dispatcherType },
7592 { "enter", enter },
7593 { "firstCallArguments", generateRAIIHandleConstructorCallArguments( handle, constructorIt, true, {}, true, true ) },
7594 { "handleConstructorArguments", handleConstructorArguments },
7595 { "handleName", startLowerCase( handleType ) },
7596 { "handleType", handleType },
7597 { "leave", leave },
7598 { "parentName", constructorIt->second.params.front().name },
7599 { "secondCallArguments", generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, true, true ) },
7600 { "vectorElementType", handleParamIt->type.type },
7601 { "vectorName", startLowerCase( stripPrefix( handleParamIt->name, "p" ) ) } } );
7602 }
7603
generateRAIIHandleConstructorEnumerate(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator handleParamIt,std::vector<ParamData>::const_iterator lenParamIt,std::string const & enter,std::string const & leave) const7604 std::string VulkanHppGenerator::generateRAIIHandleConstructorEnumerate( std::pair<std::string, HandleData> const & handle,
7605 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7606 std::vector<ParamData>::const_iterator handleParamIt,
7607 std::vector<ParamData>::const_iterator lenParamIt,
7608 std::string const & enter,
7609 std::string const & leave ) const
7610 {
7611 std::string handleConstructorArguments = generateRAIIHandleSingularConstructorArguments( handle, constructorIt );
7612 std::string handleType = stripPrefix( handle.first, "Vk" );
7613 std::string dispatcherType = hasParentHandle( handle.first, "VkDevice" ) ? "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher"
7614 : "VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::InstanceDispatcher";
7615
7616 const std::string constructorTemplate =
7617 R"(
7618 ${enter}
7619 #ifndef VULKAN_HPP_NO_EXCEPTIONS
7620 ${handleType}s( ${constructorArguments} )
7621 {
7622 ${dispatcherType} const * dispatcher = ${parentName}.getDispatcher();
7623 std::vector<${vectorElementType}> ${vectorName};
7624 ${counterType} ${counterName};
7625 VULKAN_HPP_NAMESPACE::Result result;
7626 do
7627 {
7628 result = static_cast<VULKAN_HPP_NAMESPACE::Result>( dispatcher->${constructorCall}( ${firstCallArguments} ) );
7629 if ( ( result == VULKAN_HPP_NAMESPACE::Result::eSuccess ) && ${counterName} )
7630 {
7631 ${vectorName}.resize( ${counterName} );
7632 result = static_cast<VULKAN_HPP_NAMESPACE::Result>( dispatcher->${constructorCall}( ${secondCallArguments} ) );
7633 }
7634 } while ( result == VULKAN_HPP_NAMESPACE::Result::eIncomplete );
7635 if ( result == VULKAN_HPP_NAMESPACE::Result::eSuccess )
7636 {
7637 VULKAN_HPP_ASSERT( ${counterName} <= ${vectorName}.size() );
7638 this->reserve( ${counterName} );
7639 for ( auto const & ${handleName} : ${vectorName} )
7640 {
7641 this->emplace_back( ${parentName}, ${handleConstructorArguments} );
7642 }
7643 }
7644 else
7645 {
7646 throwResultException( result, "${constructorCall}" );
7647 }
7648 }
7649 #endif
7650 ${leave})";
7651
7652 return replaceWithMap( constructorTemplate,
7653 { { "constructorArguments", generateRAIIHandleConstructorArguments( handle, constructorIt, false, false ) },
7654 { "constructorCall", constructorIt->first },
7655 { "counterName", startLowerCase( stripPrefix( lenParamIt->name, "p" ) ) },
7656 { "counterType", lenParamIt->type.type },
7657 { "dispatcherType", dispatcherType },
7658 { "enter", enter },
7659 { "firstCallArguments", generateRAIIHandleConstructorCallArguments( handle, constructorIt, true, {}, true, true ) },
7660 { "handleConstructorArguments", handleConstructorArguments },
7661 { "handleName", startLowerCase( handleType ) },
7662 { "handleType", handleType },
7663 { "leave", leave },
7664 { "parentName", constructorIt->second.params.front().name },
7665 { "secondCallArguments", generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, true, true ) },
7666 { "vectorElementType", handleParamIt->type.type },
7667 { "vectorName", startLowerCase( stripPrefix( handleParamIt->name, "p" ) ) } } );
7668 }
7669
7670 std::string
generateRAIIHandleConstructorInitializationList(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator destructorIt,bool takesOwnership) const7671 VulkanHppGenerator::generateRAIIHandleConstructorInitializationList( std::pair<std::string, HandleData> const & handle,
7672 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
7673 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator destructorIt,
7674 bool takesOwnership ) const
7675 {
7676 auto [parentType, parentName] = getParentTypeAndName( handle );
7677 std::string handleName = generateRAIIHandleConstructorParamName( handle.first, destructorIt );
7678
7679 std::string initializationList;
7680 if ( destructorIt != m_commands.end() )
7681 {
7682 for ( auto destructorParam : destructorIt->second.params )
7683 {
7684 if ( destructorParam.type.type == "Vk" + parentType )
7685 {
7686 initializationList += "m_" + parentName + "( *" + parentName + " ), ";
7687 }
7688 else if ( destructorParam.type.type == handle.first )
7689 {
7690 if ( takesOwnership )
7691 {
7692 initializationList += "m_" + handleName + "( " + handleName + " ), ";
7693 }
7694 }
7695 else if ( destructorParam.type.type == "VkAllocationCallbacks" )
7696 {
7697 assert( destructorParam.type.isConstPointer() && destructorParam.arraySizes.empty() && destructorParam.len.empty() && destructorParam.optional );
7698 initializationList += "m_allocator( static_cast<const VULKAN_HPP_NAMESPACE::AllocationCallbacks *>( allocator ) ), ";
7699 }
7700 else if ( isHandleType( destructorParam.type.type ) )
7701 {
7702 assert( destructorParam.type.isValue() && destructorParam.arraySizes.empty() && destructorParam.len.empty() && !destructorParam.optional );
7703 initializationList += "m_" + destructorParam.name + "( ";
7704 auto constructorParamIt = std::find_if( constructorIt->second.params.begin(),
7705 constructorIt->second.params.end(),
7706 [&destructorParam]( ParamData const & pd ) { return pd.type.type == destructorParam.type.type; } );
7707 if ( constructorParamIt != constructorIt->second.params.end() )
7708 {
7709 assert( constructorParamIt->type.isValue() && constructorParamIt->arraySizes.empty() && constructorParamIt->len.empty() &&
7710 !constructorParamIt->optional );
7711 if ( constructorParamIt->type.type == "Vk" + parentType )
7712 {
7713 initializationList += "*";
7714 }
7715 initializationList += constructorParamIt->name;
7716 }
7717 else
7718 {
7719 #if !defined( NDEBUG )
7720 bool found = false;
7721 #endif
7722 for ( auto constructorParam : constructorIt->second.params )
7723 {
7724 auto structureIt = m_structures.find( constructorParam.type.type );
7725 if ( structureIt != m_structures.end() )
7726 {
7727 auto structureMemberIt = findStructMemberItByType( destructorParam.type.type, structureIt->second.members );
7728 if ( structureMemberIt != structureIt->second.members.end() )
7729 {
7730 assert( constructorParam.type.isConstPointer() && constructorParam.arraySizes.empty() && constructorParam.len.empty() &&
7731 !constructorParam.optional );
7732 initializationList += startLowerCase( stripPrefix( constructorParam.name, "p" ) ) + "." + structureMemberIt->name;
7733 #if !defined( NDEBUG )
7734 found = true;
7735 #endif
7736 break;
7737 }
7738 }
7739 }
7740 assert( found );
7741 }
7742 initializationList += " ), ";
7743 }
7744 else
7745 {
7746 // we can ignore all other parameters here !
7747 }
7748 }
7749 }
7750 else
7751 {
7752 if ( !handle.second.secondLevelCommands.empty() )
7753 {
7754 assert( !handle.second.constructorIts.empty() );
7755 #if !defined( NDEBUG )
7756 auto constructorCommandIt = m_commands.find( handle.second.constructorIts.front()->first );
7757 #endif
7758 assert( ( constructorCommandIt != m_commands.end() ) && ( 1 < constructorCommandIt->second.params.size() ) );
7759 assert( std::next( constructorCommandIt->second.params.begin() )->type.type == "Vk" + parentType );
7760
7761 auto commandIt = m_commands.find( *handle.second.secondLevelCommands.begin() );
7762 assert( ( commandIt != m_commands.end() ) && ( 1 < commandIt->second.params.size() ) );
7763 assert( commandIt->second.params.front().type.type == constructorCommandIt->second.params.front().type.type );
7764 assert( std::next( commandIt->second.params.begin() )->type.type == handle.first );
7765
7766 std::string grandParentType = stripPrefix( commandIt->second.params.front().type.type, "Vk" );
7767 initializationList += "m_" + startLowerCase( grandParentType ) + "( " + parentName + ".get" + grandParentType + "() ), ";
7768 }
7769 if ( takesOwnership )
7770 {
7771 initializationList += "m_" + handleName + "( " + handleName + " ), ";
7772 }
7773 }
7774 return initializationList.empty() ? initializationList : initializationList.substr( 0, initializationList.size() - 2 );
7775 }
7776
generateRAIIHandleConstructorParamName(std::string const & type,std::map<std::string,CommandData>::const_iterator destructorIt) const7777 std::string VulkanHppGenerator::generateRAIIHandleConstructorParamName( std::string const & type,
7778 std::map<std::string, CommandData>::const_iterator destructorIt ) const
7779 {
7780 if ( destructorIt != m_commands.end() )
7781 {
7782 auto destructorParamIt = std::find_if( destructorIt->second.params.begin(),
7783 destructorIt->second.params.end(),
7784 [&type]( ParamData const & destructorParam ) { return destructorParam.type.type == type; } );
7785 if ( destructorParamIt != destructorIt->second.params.end() )
7786 {
7787 assert( std::find_if( std::next( destructorParamIt ),
7788 destructorIt->second.params.end(),
7789 [&type]( ParamData const & destructorParam ) { return destructorParam.type.type == type; } ) == destructorIt->second.params.end() );
7790 if ( !destructorParamIt->type.isValue() )
7791 {
7792 return startLowerCase( stripPrefix( stripPluralS( destructorParamIt->name, m_tags ), "p" ) );
7793 }
7794 else
7795 {
7796 return destructorParamIt->name;
7797 }
7798 }
7799 }
7800 return startLowerCase( stripPrefix( type, "Vk" ) );
7801 }
7802
generateRAIIHandleStaticCreateResult(std::pair<std::string,HandleData> const & handle,std::map<std::string,CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const7803 std::pair<std::string, std::string> VulkanHppGenerator::generateRAIIHandleStaticCreateResult( std::pair<std::string, HandleData> const & handle,
7804 std::map<std::string, CommandData>::const_iterator constructorIt,
7805 std::string const & enter,
7806 std::string const & leave ) const
7807 {
7808 assert( !constructorIt->second.successCodes.empty() );
7809 assert( constructorIt->second.successCodes[0] == "VK_SUCCESS" );
7810 switch ( constructorIt->second.successCodes.size() )
7811 {
7812 case 1:
7813 if ( !constructorIt->second.errorCodes.empty() )
7814 {
7815 std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
7816 if ( returnParams.size() == 1 )
7817 {
7818 assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
7819 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7820 switch ( vectorParams.size() )
7821 {
7822 case 0:
7823 return std::make_pair( generateRAIIHandleStaticCreateResultSingleSuccessWithErrors1Return0Vector( handle, constructorIt, enter, leave ), "" );
7824 case 1:
7825 if ( returnParams[0] == vectorParams.begin()->first )
7826 {
7827 if ( isLenByStructMember( constructorIt->second.params[vectorParams.begin()->first].len,
7828 constructorIt->second.params[vectorParams.begin()->second.lenParam] ) )
7829 {
7830 auto handleParamIt = constructorIt->second.params.begin() + returnParams[0];
7831 return std::make_pair( "", generateRAIIHandleStaticCreateVector( handle, constructorIt, handleParamIt, enter, leave ) );
7832 }
7833 }
7834 break;
7835 case 2: return generateRAIIHandleStaticCreate1Return2Vector( handle, constructorIt, enter, leave, returnParams[0], vectorParams );
7836 }
7837 }
7838 }
7839 break;
7840 case 2:
7841 if ( !constructorIt->second.errorCodes.empty() )
7842 {
7843 std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
7844 switch ( returnParams.size() )
7845 {
7846 case 1:
7847 assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
7848 {
7849 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7850 if ( vectorParams.size() == 2 )
7851 {
7852 return generateRAIIHandleStaticCreate1Return2Vector( handle, constructorIt, enter, leave, returnParams[0], vectorParams );
7853 }
7854 }
7855 break;
7856 case 2:
7857 if ( constructorIt->second.params[returnParams[0]].type.type == "uint32_t" )
7858 {
7859 assert( isHandleType( constructorIt->second.params[returnParams[1]].type.type ) );
7860 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7861 if ( vectorParams.size() == 1 )
7862 {
7863 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
7864 {
7865 assert( returnParams[1] == vectorParams.begin()->first );
7866 assert( constructorIt->second.successCodes[1] == "VK_INCOMPLETE" );
7867 auto lenParamIt = constructorIt->second.params.begin() + returnParams[0];
7868 auto handleParamIt = constructorIt->second.params.begin() + returnParams[1];
7869 return std::make_pair( "", generateRAIIHandleStaticCreateEnumerate( handle, constructorIt, handleParamIt, lenParamIt, enter, leave ) );
7870 }
7871 }
7872 }
7873 break;
7874 }
7875 }
7876 break;
7877 case 4:
7878 if ( !constructorIt->second.errorCodes.empty() )
7879 {
7880 std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
7881 if ( returnParams.size() == 1 )
7882 {
7883 assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
7884 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7885 if ( vectorParams.size() == 2 )
7886 {
7887 return generateRAIIHandleStaticCreate1Return2Vector( handle, constructorIt, enter, leave, returnParams[0], vectorParams );
7888 }
7889 }
7890 }
7891 break;
7892 }
7893 return std::make_pair( "", "" );
7894 }
7895
generateRAIIHandleConstructorResult(std::pair<std::string,HandleData> const & handle,std::map<std::string,CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const7896 std::pair<std::string, std::string> VulkanHppGenerator::generateRAIIHandleConstructorResult( std::pair<std::string, HandleData> const & handle,
7897 std::map<std::string, CommandData>::const_iterator constructorIt,
7898 std::string const & enter,
7899 std::string const & leave ) const
7900 {
7901 assert( !constructorIt->second.successCodes.empty() );
7902 assert( constructorIt->second.successCodes[0] == "VK_SUCCESS" );
7903 switch ( constructorIt->second.successCodes.size() )
7904 {
7905 case 1:
7906 if ( !constructorIt->second.errorCodes.empty() )
7907 {
7908 std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
7909 if ( returnParams.size() == 1 )
7910 {
7911 assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
7912 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7913 switch ( vectorParams.size() )
7914 {
7915 case 0:
7916 return std::make_pair( generateRAIIHandleConstructorResultSingleSuccessWithErrors1Return0Vector( handle, constructorIt, enter, leave ), "" );
7917 case 1:
7918 if ( returnParams[0] == vectorParams.begin()->first )
7919 {
7920 if ( isLenByStructMember( constructorIt->second.params[vectorParams.begin()->first].len,
7921 constructorIt->second.params[vectorParams.begin()->second.lenParam] ) )
7922 {
7923 auto handleParamIt = constructorIt->second.params.begin() + returnParams[0];
7924 return std::make_pair( "", generateRAIIHandleConstructorVector( handle, constructorIt, handleParamIt, enter, leave ) );
7925 }
7926 }
7927 break;
7928 case 2: return generateRAIIHandleConstructor1Return2Vector( handle, constructorIt, enter, leave, returnParams[0], vectorParams );
7929 }
7930 }
7931 }
7932 break;
7933 case 2:
7934 if ( !constructorIt->second.errorCodes.empty() )
7935 {
7936 std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
7937 switch ( returnParams.size() )
7938 {
7939 case 1:
7940 assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
7941 {
7942 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7943 if ( vectorParams.size() == 2 )
7944 {
7945 return generateRAIIHandleConstructor1Return2Vector( handle, constructorIt, enter, leave, returnParams[0], vectorParams );
7946 }
7947 }
7948 break;
7949 case 2:
7950 if ( constructorIt->second.params[returnParams[0]].type.type == "uint32_t" )
7951 {
7952 assert( isHandleType( constructorIt->second.params[returnParams[1]].type.type ) );
7953 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7954 if ( vectorParams.size() == 1 )
7955 {
7956 if ( returnParams[0] == vectorParams.begin()->second.lenParam )
7957 {
7958 assert( returnParams[1] == vectorParams.begin()->first );
7959 assert( constructorIt->second.successCodes[1] == "VK_INCOMPLETE" );
7960 auto lenParamIt = constructorIt->second.params.begin() + returnParams[0];
7961 auto handleParamIt = constructorIt->second.params.begin() + returnParams[1];
7962 return std::make_pair( "", generateRAIIHandleConstructorEnumerate( handle, constructorIt, handleParamIt, lenParamIt, enter, leave ) );
7963 }
7964 }
7965 }
7966 break;
7967 }
7968 }
7969 break;
7970 case 4:
7971 if ( !constructorIt->second.errorCodes.empty() )
7972 {
7973 std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
7974 if ( returnParams.size() == 1 )
7975 {
7976 assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
7977 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
7978 if ( vectorParams.size() == 2 )
7979 {
7980 return generateRAIIHandleConstructor1Return2Vector( handle, constructorIt, enter, leave, returnParams[0], vectorParams );
7981 }
7982 }
7983 }
7984 break;
7985 }
7986 return std::make_pair( "", "" );
7987 }
7988
generateRAIIHandleStaticCreateToConstructorArgument(ParamData const & param,bool singular) const7989 std::string VulkanHppGenerator::generateRAIIHandleStaticCreateToConstructorArgument( ParamData const & param, bool singular ) const
7990 {
7991 std::string argument;
7992 if ( param.type.isConstPointer() )
7993 {
7994 assert( param.type.type.starts_with( "Vk" ) );
7995 assert( param.name.starts_with( "p" ) );
7996 std::string argumentName = startLowerCase( stripPrefix( param.name, "p" ) );
7997 std::string argumentType = generateNamespacedType( param.type.type );
7998 if ( param.optional )
7999 {
8000 assert( param.len.empty() );
8001 argument = argumentName;
8002 }
8003 else if ( param.len.empty() )
8004 {
8005 argument = argumentName;
8006 }
8007 else if ( singular )
8008 {
8009 argument = stripPluralS( argumentName, m_tags );
8010 }
8011 else
8012 {
8013 argument = argumentName;
8014 }
8015 }
8016 else if ( specialPointerTypes.find( param.type.type ) != specialPointerTypes.end() )
8017 {
8018 assert( !param.optional );
8019 assert( param.type.isNonConstPointer() );
8020 argument = param.name;
8021 }
8022 else if ( ( param.type.isValue() ) && isHandleType( param.type.type ) )
8023 {
8024 argument += param.name;
8025 }
8026 else
8027 {
8028 assert( !param.optional );
8029 argument += param.name;
8030 }
8031 return argument;
8032 }
8033
generateRAIIHandleStaticCreateToConstructorArguments(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt) const8034 std::string VulkanHppGenerator::generateRAIIHandleStaticCreateToConstructorArguments(
8035 std::pair<std::string, HandleData> const & handle,
8036 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt ) const
8037 {
8038 auto [parentType, parentName] = getParentTypeAndName( handle );
8039
8040 std::string arguments = parentName;
8041
8042 arguments += ", " + generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
8043
8044 if ( constructorIt != m_commands.end() )
8045 {
8046 parentType = "Vk" + parentType;
8047 bool skip = skipLeadingGrandParent( handle );
8048 for ( size_t i = skip ? 1 : 0; i < constructorIt->second.params.size(); i++ )
8049 {
8050 ParamData const & param = constructorIt->second.params[i];
8051 // filter parent and handle type
8052 if ( ( param.type.type != parentType ) && ( param.type.type != handle.first ) )
8053 {
8054 // the specialPointerTypes are considered const-pointers!
8055 if ( param.type.isNonConstPointer() && ( specialPointerTypes.find( param.type.type ) == specialPointerTypes.end() ) )
8056 {
8057 // this is supposed to be the returned size on an enumeration function!
8058 #if !defined( NDEBUG )
8059 assert( param.type.type == "uint32_t" );
8060 auto typeIt = std::find_if( constructorIt->second.params.begin(),
8061 constructorIt->second.params.end(),
8062 [&handle]( ParamData const & pd ) { return pd.type.type == handle.first; } );
8063 assert( typeIt != constructorIt->second.params.end() );
8064 assert( typeIt->len == param.name );
8065 #endif
8066 continue;
8067 }
8068 else if ( std::find_if( constructorIt->second.params.begin(),
8069 constructorIt->second.params.end(),
8070 [¶m]( ParamData const & pd ) { return pd.len == param.name; } ) != constructorIt->second.params.end() )
8071 {
8072 // this is the len of an other parameter, which will be mapped to an ArrayProxy
8073 assert( param.type.isValue() && ( param.type.type == "uint32_t" ) );
8074 assert( param.arraySizes.empty() && param.len.empty() && !param.optional );
8075 continue;
8076 }
8077 arguments += ", " + generateRAIIHandleStaticCreateToConstructorArgument(param, false);
8078 }
8079 }
8080 }
8081 return arguments;
8082 }
8083
generateRAIIHandleStaticCreateResultSingleSuccessWithErrors1Return0Vector(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const8084 std::string VulkanHppGenerator::generateRAIIHandleStaticCreateResultSingleSuccessWithErrors1Return0Vector(
8085 std::pair<std::string, HandleData> const & handle,
8086 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8087 std::string const & enter,
8088 std::string const & leave ) const
8089 {
8090 auto [parentType, parentName] = getParentTypeAndName( handle );
8091
8092 std::string getDispatcher = parentName + ".getDispatcher()";
8093
8094 std::string staticCreateArguments = generateRAIIHandleConstructorArguments( handle, constructorIt, false, false );
8095
8096 std::string callArguments = generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, false, false );
8097
8098 std::string localParamType = handle.first;
8099 std::string localParamName = generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
8100
8101 std::string callConstructorArguments = generateRAIIHandleStaticCreateToConstructorArguments( handle, handle.second.destructorIt );
8102
8103 std::string debugHelper = "";
8104 #ifdef DEBUG_GENERATOR
8105 debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
8106 #endif
8107
8108 const std::string constructorTemplate =
8109 R"(
8110 ${enter}
8111 static android::base::expected<${handleType}, VULKAN_HPP_NAMESPACE::Result> create( ${staticCreateArguments} ) ${debugHelper}
8112 {
8113 ${localParamType} ${localParamName};
8114 VULKAN_HPP_NAMESPACE::Result result = static_cast<VULKAN_HPP_NAMESPACE::Result>( ${getDispatcher}->${constructorCall}( ${callArguments} ) );
8115 if ( ${failureCheck} )
8116 {
8117 return android::base::unexpected(result);
8118 }
8119
8120 return VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::${handleType}(${callConstructorArguments});
8121 }
8122 ${leave})";
8123
8124 return replaceWithMap( constructorTemplate,
8125 { { "callArguments", callArguments },
8126 { "staticCreateArguments", staticCreateArguments },
8127 { "callConstructorArguments", callConstructorArguments },
8128 { "constructorCall", constructorIt->first },
8129 { "debugHelper", debugHelper },
8130 { "enter", enter },
8131 { "failureCheck", generateFailureCheck( constructorIt->second.successCodes ) },
8132 { "getDispatcher", getDispatcher },
8133 { "leave", leave },
8134 { "localParamName", localParamName },
8135 { "localParamType", localParamType },
8136 { "handleType", stripPrefix( handle.first, "Vk" ) } } );
8137 }
8138
generateRAIIHandleConstructorResultSingleSuccessWithErrors1Return0Vector(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const8139 std::string VulkanHppGenerator::generateRAIIHandleConstructorResultSingleSuccessWithErrors1Return0Vector(
8140 std::pair<std::string, HandleData> const & handle,
8141 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8142 std::string const & enter,
8143 std::string const & leave ) const
8144 {
8145 auto [parentType, parentName] = getParentTypeAndName( handle );
8146
8147 std::string getDispatcher = parentName + ".getDispatcher()";
8148 std::string dispatcherInitializer, dispatcherInit;
8149 if ( ( handle.first != "VkInstance" ) && ( handle.first != "VkDevice" ) )
8150 {
8151 dispatcherInitializer = "m_dispatcher( " + getDispatcher + " )";
8152 }
8153 else
8154 {
8155 std::string handleType = stripPrefix( handle.first, "Vk" );
8156 dispatcherInit = "\n m_dispatcher.reset( new VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::" + handleType + "Dispatcher( " + parentName +
8157 ".getDispatcher()->vkGet" + handleType + "ProcAddr, static_cast<" + handle.first + ">( m_" + startLowerCase( handleType ) + " ) ) );";
8158 }
8159
8160 std::string constructorArguments = generateRAIIHandleConstructorArguments( handle, constructorIt, false, false );
8161
8162 std::string callArguments = generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, handle.second.destructorIt != m_commands.end(), false );
8163
8164 std::string initializationList = generateRAIIHandleConstructorInitializationList( handle, constructorIt, handle.second.destructorIt, false );
8165 if ( !initializationList.empty() && !dispatcherInitializer.empty() )
8166 {
8167 initializationList += ", ";
8168 }
8169
8170 const std::string constructorTemplate =
8171 R"(
8172 ${enter}
8173 #ifndef VULKAN_HPP_NO_EXCEPTIONS
8174 ${handleType}( ${constructorArguments} )
8175 : ${initializationList}${dispatcherInitializer}
8176 {
8177 VULKAN_HPP_NAMESPACE::Result result = static_cast<VULKAN_HPP_NAMESPACE::Result>( ${getDispatcher}->${constructorCall}( ${callArguments} ) );
8178 if ( ${failureCheck} )
8179 {
8180 throwResultException( result, "${constructorCall}" );
8181 }${dispatcherInit}
8182 }
8183 #endif
8184 ${leave})";
8185
8186 return replaceWithMap( constructorTemplate,
8187 { { "callArguments", callArguments },
8188 { "constructorArguments", constructorArguments },
8189 { "constructorCall", constructorIt->first },
8190 { "dispatcherInitializer", dispatcherInitializer },
8191 { "dispatcherInit", dispatcherInit },
8192 { "enter", enter },
8193 { "failureCheck", generateFailureCheck( constructorIt->second.successCodes ) },
8194 { "getDispatcher", getDispatcher },
8195 { "leave", leave },
8196 { "handleType", stripPrefix( handle.first, "Vk" ) },
8197 { "initializationList", initializationList } } );
8198 }
8199
generateRAIIHandleConstructorTakeOwnership(std::pair<std::string,HandleData> const & handle) const8200 std::string VulkanHppGenerator::generateRAIIHandleConstructorTakeOwnership( std::pair<std::string, HandleData> const & handle ) const
8201 {
8202 std::string handleType = stripPrefix( handle.first, "Vk" );
8203 std::string handleName = startLowerCase( handleType );
8204
8205 auto [parentType, parentName] = getParentTypeAndName( handle );
8206
8207 std::string constructorArguments = generateRAIIHandleConstructorArguments( handle, handle.second.destructorIt, false, true );
8208 std::string initializationList = generateRAIIHandleConstructorInitializationList( handle, handle.second.destructorIt, handle.second.destructorIt, true );
8209 assert( !handle.second.constructorIts.empty() );
8210 if ( 1 < handle.second.constructorIts[0]->second.successCodes.size() && ( handle.second.constructorIts[0]->second.successCodes[1] != "VK_INCOMPLETE" ) )
8211 {
8212 #if !defined( NDEBUG )
8213 for ( size_t i = 1; i < handle.second.constructorIts.size(); ++i )
8214 {
8215 assert( 1 < handle.second.constructorIts[i]->second.successCodes.size() );
8216 }
8217 #endif
8218 constructorArguments += ", VULKAN_HPP_NAMESPACE::Result successCode = VULKAN_HPP_NAMESPACE::Result::eSuccess";
8219 initializationList += ", m_constructorSuccessCode( successCode )";
8220 }
8221
8222 std::string dispatcherInitializer;
8223 if ( ( handle.first != "VkInstance" ) && ( handle.first != "VkDevice" ) )
8224 {
8225 dispatcherInitializer = "m_dispatcher( " + parentName + ".getDispatcher() )";
8226 }
8227 if ( !initializationList.empty() && !dispatcherInitializer.empty() )
8228 {
8229 initializationList += ", ";
8230 }
8231
8232 std::string dispatcherInit;
8233 if ( ( handle.first == "VkDevice" ) || ( handle.first == "VkInstance" ) )
8234 {
8235 dispatcherInit = "\n m_dispatcher.reset( new VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::" + handleType + "Dispatcher( " + parentName +
8236 ".getDispatcher()->vkGet" + handleType + "ProcAddr, static_cast<" + handle.first + ">( m_" + startLowerCase( handleType ) + " ) ) );";
8237 }
8238
8239 const std::string constructorTemplate =
8240 R"(
8241 ${handleType}( ${constructorArguments} )
8242 : ${initializationList}${dispatcherInitializer}
8243 {${dispatcherInit}}
8244 )";
8245
8246 return replaceWithMap( constructorTemplate,
8247 { { "constructorArguments", constructorArguments },
8248 { "dispatcherInitializer", dispatcherInitializer },
8249 { "dispatcherInit", dispatcherInit },
8250 { "handleType", handleType },
8251 { "initializationList", initializationList } } );
8252 }
8253
generateRAIIHandleStaticCreateVector(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator handleParamIt,std::string const & enter,std::string const & leave) const8254 std::string VulkanHppGenerator::generateRAIIHandleStaticCreateVector( std::pair<std::string, HandleData> const & handle,
8255 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8256 std::vector<ParamData>::const_iterator handleParamIt,
8257 std::string const & enter,
8258 std::string const & leave ) const
8259 {
8260 std::string vectorSize;
8261 auto lenIt = std::find_if( constructorIt->second.params.begin(),
8262 constructorIt->second.params.end(),
8263 [&handleParamIt]( ParamData const & pd ) { return pd.name == handleParamIt->len; } );
8264 if ( lenIt == constructorIt->second.params.end() )
8265 {
8266 std::vector<std::string> lenParts = tokenize( handleParamIt->len, "->" );
8267 assert( lenParts.size() == 2 );
8268 lenIt = std::find_if(
8269 constructorIt->second.params.begin(), constructorIt->second.params.end(), [&lenParts]( ParamData const & pd ) { return pd.name == lenParts[0]; } );
8270 #if !defined( NDEBUG )
8271 assert( lenIt != constructorIt->second.params.end() );
8272 auto structureIt = m_structures.find( lenIt->type.type );
8273 assert( structureIt != m_structures.end() );
8274 assert( isStructMember( lenParts[1], structureIt->second.members ) );
8275 assert( constructorIt->second.successCodes.size() == 1 );
8276 #endif
8277 vectorSize = startLowerCase( stripPrefix( lenParts[0], "p" ) ) + "." + lenParts[1];
8278 }
8279 else
8280 {
8281 auto arrayIt = std::find_if( constructorIt->second.params.begin(),
8282 constructorIt->second.params.end(),
8283 [&lenIt, &handleParamIt]( ParamData const & pd ) { return ( pd.len == lenIt->name ) && ( pd.name != handleParamIt->name ); } );
8284 assert( arrayIt != constructorIt->second.params.end() );
8285 vectorSize = startLowerCase( stripPrefix( arrayIt->name, "p" ) ) + ".size()";
8286 }
8287
8288 std::string handleConstructorArguments = generateRAIIHandleSingularConstructorArguments( handle, constructorIt );
8289 std::string handleType = stripPrefix( handle.first, "Vk" );
8290 std::string successCodePassToElement = ( 1 < constructorIt->second.successCodes.size() ) ? ", result" : "";
8291
8292 std::string debugHelper = "";
8293 #ifdef DEBUG_GENERATOR
8294 debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
8295 #endif
8296
8297 const std::string constructorTemplate =
8298 R"(
8299 ${enter}
8300 static android::base::expected<${handleType}s, VULKAN_HPP_NAMESPACE::Result> create( ${staticCreateArguments} ) ${debugHelper}
8301 {
8302 VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher const * dispatcher = ${parentName}.getDispatcher();
8303 std::vector<${vectorElementType}> ${vectorName}( ${vectorSize} );
8304 VULKAN_HPP_NAMESPACE::Result result = static_cast<VULKAN_HPP_NAMESPACE::Result>( dispatcher->${constructorCall}( ${callArguments} ) );
8305 if ( ${successCheck} )
8306 {
8307 VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::${handleType}s ret(nullptr);
8308 ret.reserve( ${vectorSize} );
8309 for ( auto const & ${handleName} : ${vectorName} )
8310 {
8311 ret.emplace_back( ${parentName}, ${handleConstructorArguments}${successCodePassToElement} );
8312 }
8313 return std::move(ret);
8314 }
8315 else
8316 {
8317 return android::base::unexpected(result);
8318 }
8319 }
8320 ${leave})";
8321
8322 return replaceWithMap( constructorTemplate,
8323 { { "callArguments", generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, false, true ) },
8324 { "staticCreateArguments", generateRAIIHandleConstructorArguments( handle, constructorIt, false, false ) },
8325 { "constructorCall", constructorIt->first },
8326 { "debugHelper", debugHelper },
8327 { "enter", enter },
8328 { "handleConstructorArguments", handleConstructorArguments },
8329 { "handleName", startLowerCase( handleType ) },
8330 { "handleType", handleType },
8331 { "leave", leave },
8332 { "parentName", constructorIt->second.params.front().name },
8333 { "successCheck", generateSuccessCheck( constructorIt->second.successCodes ) },
8334 { "successCodePassToElement", successCodePassToElement },
8335 { "vectorElementType", handleParamIt->type.type },
8336 { "vectorName", startLowerCase( stripPrefix( handleParamIt->name, "p" ) ) },
8337 { "vectorSize", vectorSize } } );
8338 }
8339
generateRAIIHandleConstructorVector(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator handleParamIt,std::string const & enter,std::string const & leave) const8340 std::string VulkanHppGenerator::generateRAIIHandleConstructorVector( std::pair<std::string, HandleData> const & handle,
8341 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8342 std::vector<ParamData>::const_iterator handleParamIt,
8343 std::string const & enter,
8344 std::string const & leave ) const
8345 {
8346 std::string vectorSize;
8347 auto lenIt = std::find_if( constructorIt->second.params.begin(),
8348 constructorIt->second.params.end(),
8349 [&handleParamIt]( ParamData const & pd ) { return pd.name == handleParamIt->len; } );
8350 if ( lenIt == constructorIt->second.params.end() )
8351 {
8352 std::vector<std::string> lenParts = tokenize( handleParamIt->len, "->" );
8353 assert( lenParts.size() == 2 );
8354 lenIt = std::find_if(
8355 constructorIt->second.params.begin(), constructorIt->second.params.end(), [&lenParts]( ParamData const & pd ) { return pd.name == lenParts[0]; } );
8356 #if !defined( NDEBUG )
8357 assert( lenIt != constructorIt->second.params.end() );
8358 auto structureIt = m_structures.find( lenIt->type.type );
8359 assert( structureIt != m_structures.end() );
8360 assert( isStructMember( lenParts[1], structureIt->second.members ) );
8361 assert( constructorIt->second.successCodes.size() == 1 );
8362 #endif
8363 vectorSize = startLowerCase( stripPrefix( lenParts[0], "p" ) ) + "." + lenParts[1];
8364 }
8365 else
8366 {
8367 auto arrayIt = std::find_if( constructorIt->second.params.begin(),
8368 constructorIt->second.params.end(),
8369 [&lenIt, &handleParamIt]( ParamData const & pd ) { return ( pd.len == lenIt->name ) && ( pd.name != handleParamIt->name ); } );
8370 assert( arrayIt != constructorIt->second.params.end() );
8371 vectorSize = startLowerCase( stripPrefix( arrayIt->name, "p" ) ) + ".size()";
8372 }
8373
8374 std::string handleConstructorArguments = generateRAIIHandleSingularConstructorArguments( handle, constructorIt );
8375 std::string handleType = stripPrefix( handle.first, "Vk" );
8376 std::string successCodePassToElement = ( 1 < constructorIt->second.successCodes.size() ) ? ", result" : "";
8377
8378 std::string debugHelper = "";
8379 #ifdef DEBUG_GENERATOR
8380 debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
8381 #endif
8382
8383 const std::string constructorTemplate =
8384 R"(
8385 ${enter}
8386 #ifndef VULKAN_HPP_NO_EXCEPTIONS
8387 ${handleType}s( ${constructorArguments} ) ${debugHelper}
8388 {
8389 VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher const * dispatcher = ${parentName}.getDispatcher();
8390 std::vector<${vectorElementType}> ${vectorName}( ${vectorSize} );
8391 VULKAN_HPP_NAMESPACE::Result result = static_cast<VULKAN_HPP_NAMESPACE::Result>( dispatcher->${constructorCall}( ${callArguments} ) );
8392 if ( ${successCheck} )
8393 {
8394 this->reserve( ${vectorSize} );
8395 for ( auto const & ${handleName} : ${vectorName} )
8396 {
8397 this->emplace_back( ${parentName}, ${handleConstructorArguments}${successCodePassToElement} );
8398 }
8399 }
8400 else
8401 {
8402 throwResultException( result, "${constructorCall}" );
8403 }
8404 }
8405 #endif
8406 ${leave})";
8407
8408 return replaceWithMap( constructorTemplate,
8409 { { "callArguments", generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, false, true ) },
8410 { "constructorArguments", generateRAIIHandleConstructorArguments( handle, constructorIt, false, false ) },
8411 { "constructorCall", constructorIt->first },
8412 { "debugHelper", debugHelper },
8413 { "enter", enter },
8414 { "handleConstructorArguments", handleConstructorArguments },
8415 { "handleName", startLowerCase( handleType ) },
8416 { "handleType", handleType },
8417 { "leave", leave },
8418 { "parentName", constructorIt->second.params.front().name },
8419 { "successCheck", generateSuccessCheck( constructorIt->second.successCodes ) },
8420 { "successCodePassToElement", successCodePassToElement },
8421 { "vectorElementType", handleParamIt->type.type },
8422 { "vectorName", startLowerCase( stripPrefix( handleParamIt->name, "p" ) ) },
8423 { "vectorSize", vectorSize } } );
8424 }
8425
8426 std::string
generateRAIIHandleStaticCreateVectorSingular(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator handleParamIt,std::string const & enter,std::string const & leave) const8427 VulkanHppGenerator::generateRAIIHandleStaticCreateVectorSingular( std::pair<std::string, HandleData> const & handle,
8428 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8429 std::vector<ParamData>::const_iterator handleParamIt,
8430 std::string const & enter,
8431 std::string const & leave ) const
8432 {
8433 size_t returnParam = static_cast<size_t>( std::distance( constructorIt->second.params.begin(), handleParamIt ) );
8434 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
8435 std::set<size_t> singularParams = determineSingularParams( returnParam, vectorParams );
8436
8437 auto [parentType, parentName] = getParentTypeAndName( handle );
8438 std::string getDispatcher = parentName + ".getDispatcher()";
8439
8440 std::string callArguments = generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, singularParams, false, false );
8441 std::string failureCheck = generateFailureCheck( constructorIt->second.successCodes );
8442
8443 std::string localParamType = handle.first;
8444 std::string localParamName = generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
8445
8446 std::string callConstructorArguments = generateRAIIHandleStaticCreateToConstructorArguments( handle, handle.second.destructorIt );
8447
8448 std::string debugHelper = "";
8449 #ifdef DEBUG_GENERATOR
8450 debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
8451 #endif
8452
8453 const std::string singularConstructorTemplate =
8454 R"(
8455 ${enter}
8456 static android::base::expected<${handleType}, VULKAN_HPP_NAMESPACE::Result> create( ${staticCreateArguments} ) ${debugHelper}
8457 {
8458 ${localParamType} ${localParamName};
8459 VULKAN_HPP_NAMESPACE::Result result = static_cast<VULKAN_HPP_NAMESPACE::Result>( ${getDispatcher}->${constructorCall}( ${callArguments} ) );
8460 if ( ${failureCheck} )
8461 {
8462 return android::base::unexpected(result);
8463 }
8464 return VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::${handleType}(${callConstructorArguments});
8465 }
8466 ${leave})";
8467
8468 return replaceWithMap( singularConstructorTemplate,
8469 { { "callArguments", callArguments },
8470 { "callConstructorArguments", callConstructorArguments },
8471 { "staticCreateArguments", generateRAIIHandleConstructorArguments( handle, constructorIt, true, false ) },
8472 { "constructorCall", constructorIt->first },
8473 { "debugHelper", debugHelper },
8474 { "enter", enter },
8475 { "failureCheck", failureCheck },
8476 { "getDispatcher", getDispatcher },
8477 { "leave", leave },
8478 { "localParamType", localParamType },
8479 { "localParamName", localParamName },
8480 { "handleType", stripPrefix( handle.first, "Vk" ) } } );
8481 }
8482
8483 std::string
generateRAIIHandleConstructorVectorSingular(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::vector<ParamData>::const_iterator handleParamIt,std::string const & enter,std::string const & leave) const8484 VulkanHppGenerator::generateRAIIHandleConstructorVectorSingular( std::pair<std::string, HandleData> const & handle,
8485 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8486 std::vector<ParamData>::const_iterator handleParamIt,
8487 std::string const & enter,
8488 std::string const & leave ) const
8489 {
8490 size_t returnParam = static_cast<size_t>( std::distance( constructorIt->second.params.begin(), handleParamIt ) );
8491 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
8492 std::set<size_t> singularParams = determineSingularParams( returnParam, vectorParams );
8493
8494 std::string callArguments = generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, singularParams, true, true );
8495 std::string initializationList = generateRAIIHandleConstructorInitializationList( handle, constructorIt, handle.second.destructorIt, false );
8496 assert( !initializationList.empty() );
8497 std::string failureCheck = generateFailureCheck( constructorIt->second.successCodes );
8498 failureCheck = std::regex_replace( failureCheck, std::regex( "result" ), "m_constructorSuccessCode" );
8499
8500 std::string debugHelper = "";
8501 #ifdef DEBUG_GENERATOR
8502 debugHelper = "/*" + std::string(__FUNCTION__) + "*/";
8503 #endif
8504
8505 const std::string singularConstructorTemplate =
8506 R"(
8507 ${enter}
8508 #ifndef VULKAN_HPP_NO_EXCEPTIONS
8509 ${handleType}( ${constructorArguments} ) ${debugHelper}
8510 : ${initializationList}, m_dispatcher( ${firstArgument}.getDispatcher() )
8511 {
8512 m_constructorSuccessCode = static_cast<VULKAN_HPP_NAMESPACE::Result>( getDispatcher()->${constructorCall}( ${callArguments} ) );
8513 if ( ${failureCheck} )
8514 {
8515 throwResultException( m_constructorSuccessCode, "${constructorCall}" );
8516 }
8517 }
8518 #endif
8519 ${leave})";
8520
8521 return replaceWithMap( singularConstructorTemplate,
8522 { { "initializationList", initializationList },
8523 { "callArguments", callArguments },
8524 { "constructorArguments", generateRAIIHandleConstructorArguments( handle, constructorIt, true, false ) },
8525 { "constructorCall", constructorIt->first },
8526 { "debugHelper", debugHelper },
8527 { "enter", enter },
8528 { "firstArgument", constructorIt->second.params[0].name },
8529 { "failureCheck", failureCheck },
8530 { "leave", leave },
8531 { "handleType", stripPrefix( handle.first, "Vk" ) } } );
8532 }
8533
generateRAIIHandleConstructorVoid(std::pair<std::string,HandleData> const & handle,std::map<std::string,CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const8534 std::pair<std::string, std::string> VulkanHppGenerator::generateRAIIHandleConstructorVoid( std::pair<std::string, HandleData> const & handle,
8535 std::map<std::string, CommandData>::const_iterator constructorIt,
8536 std::string const & enter,
8537 std::string const & leave ) const
8538 {
8539 assert( constructorIt->second.successCodes.empty() && constructorIt->second.errorCodes.empty() );
8540 std::vector<size_t> returnParams = determineReturnParams( constructorIt->second.params );
8541 if ( returnParams.size() == 1 )
8542 {
8543 assert( isHandleType( constructorIt->second.params[returnParams[0]].type.type ) );
8544 std::map<size_t, VectorParamData> vectorParams = determineVectorParams( constructorIt->second.params );
8545 if ( vectorParams.empty() )
8546 {
8547 return std::make_pair( generateRAIIHandleConstructorVoid1Return0Vector( handle, constructorIt, enter, leave ), "" );
8548 }
8549 }
8550 return std::make_pair( "", "" );
8551 }
8552
8553 std::string
generateRAIIHandleConstructorVoid1Return0Vector(std::pair<std::string,HandleData> const & handle,std::map<std::string,VulkanHppGenerator::CommandData>::const_iterator constructorIt,std::string const & enter,std::string const & leave) const8554 VulkanHppGenerator::generateRAIIHandleConstructorVoid1Return0Vector( std::pair<std::string, HandleData> const & handle,
8555 std::map<std::string, VulkanHppGenerator::CommandData>::const_iterator constructorIt,
8556 std::string const & enter,
8557 std::string const & leave ) const
8558 {
8559 std::string callArguments = generateRAIIHandleConstructorCallArguments( handle, constructorIt, false, {}, true, true );
8560 std::string constructorArguments = generateRAIIHandleConstructorArguments( handle, constructorIt, false, false );
8561 std::string initializationList = generateRAIIHandleConstructorInitializationList( handle, constructorIt, handle.second.destructorIt, false );
8562 if ( !initializationList.empty() )
8563 {
8564 initializationList += ", ";
8565 }
8566
8567 const std::string constructorTemplate =
8568 R"(
8569 ${enter} ${handleType}( ${constructorArguments} )
8570 : ${initializationList}m_dispatcher( ${firstArgument}.getDispatcher() )
8571 {
8572 getDispatcher()->${constructorCall}( ${callArguments} );
8573 }
8574 ${leave})";
8575
8576 return replaceWithMap( constructorTemplate,
8577 { { "callArguments", callArguments },
8578 { "constructorArguments", constructorArguments },
8579 { "constructorCall", constructorIt->first },
8580 { "enter", enter },
8581 { "firstArgument", constructorIt->second.params[0].name },
8582 { "leave", leave },
8583 { "handleType", stripPrefix( handle.first, "Vk" ) },
8584 { "initializationList", initializationList } } );
8585 }
8586
generateRAIIHandleContext(std::pair<std::string,HandleData> const & handle,std::set<std::string> const & specialFunctions) const8587 std::string VulkanHppGenerator::generateRAIIHandleContext( std::pair<std::string, HandleData> const & handle,
8588 std::set<std::string> const & specialFunctions ) const
8589 {
8590 const std::string contextTemplate = R"(
8591 class Context
8592 {
8593 public:
8594 #if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
8595 Context()
8596 : m_dispatcher( new VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::ContextDispatcher(
8597 m_dynamicLoader.getProcAddress<PFN_vkGetInstanceProcAddr>( "vkGetInstanceProcAddr" ) ) )
8598 #else
8599 Context( PFN_vkGetInstanceProcAddr getInstanceProcAddr )
8600 : m_dispatcher( new VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::ContextDispatcher( getInstanceProcAddr ) )
8601 #endif
8602 {}
8603
8604 ~Context() = default;
8605
8606 Context( Context const & ) = delete;
8607 Context( Context && rhs ) VULKAN_HPP_NOEXCEPT
8608 #if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
8609 : m_dynamicLoader( std::move( rhs.m_dynamicLoader ) )
8610 , m_dispatcher( rhs.m_dispatcher.release() )
8611 #else
8612 : m_dispatcher( rhs.m_dispatcher.release() )
8613 #endif
8614 {}
8615 Context & operator=( Context const & ) = delete;
8616 Context & operator=( Context && rhs ) VULKAN_HPP_NOEXCEPT
8617 {
8618 if ( this != &rhs )
8619 {
8620 #if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
8621 m_dynamicLoader = std::move( rhs.m_dynamicLoader );
8622 #endif
8623 m_dispatcher.reset( rhs.m_dispatcher.release() );
8624 }
8625 return *this;
8626 }
8627
8628 VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::ContextDispatcher const * getDispatcher() const
8629 {
8630 VULKAN_HPP_ASSERT( m_dispatcher->getVkHeaderVersion() == VK_HEADER_VERSION );
8631 return &*m_dispatcher;
8632 }
8633
8634 void swap( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::Context & rhs )
8635 {
8636 #if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
8637 std::swap( m_dynamicLoader, rhs.m_dynamicLoader );
8638 #endif
8639 m_dispatcher.swap( rhs.m_dispatcher );
8640 }
8641
8642 ${memberFunctionDeclarations}
8643
8644 private:
8645 #if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL
8646 VULKAN_HPP_NAMESPACE::DynamicLoader m_dynamicLoader;
8647 #endif
8648 std::unique_ptr<VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::ContextDispatcher> m_dispatcher;
8649 };
8650
8651 )";
8652
8653 return replaceWithMap( contextTemplate, { { "memberFunctionDeclarations", generateRAIIHandleCommandDeclarations( handle, specialFunctions ) } } );
8654 }
8655
generateRAIIHandleDestructorCallArguments(std::string const & handleType,std::map<std::string,CommandData>::const_iterator destructorIt) const8656 std::string VulkanHppGenerator::generateRAIIHandleDestructorCallArguments( std::string const & handleType,
8657 std::map<std::string, CommandData>::const_iterator destructorIt ) const
8658 {
8659 std::string arguments;
8660 bool encounteredArgument = false;
8661 for ( auto param : destructorIt->second.params )
8662 {
8663 if ( encounteredArgument )
8664 {
8665 arguments += ", ";
8666 }
8667 if ( param.type.type == handleType )
8668 {
8669 std::string handleName = param.name;
8670 if ( param.type.isValue() )
8671 {
8672 arguments += "static_cast<" + handleType + ">( m_" + handleName + " )";
8673 }
8674 else
8675 {
8676 arguments += "reinterpret_cast<" + handleType + " const *>( &m_" + stripPluralS( startLowerCase( stripPrefix( handleName, "p" ) ), m_tags ) + " )";
8677 }
8678 }
8679 else if ( param.type.type == "VkAllocationCallbacks" )
8680 {
8681 // vk::AllocationCallbacks is stored as a member of the handle class
8682 arguments += "reinterpret_cast<const VkAllocationCallbacks *>( m_allocator )";
8683 }
8684 else if ( isHandleType( param.type.type ) )
8685 {
8686 assert( param.arraySizes.empty() );
8687 std::string argument = "m_" + param.name;
8688 if ( param.type.isValue() )
8689 {
8690 arguments += "static_cast<" + param.type.type + ">( " + argument + " )";
8691 }
8692 else
8693 {
8694 assert( param.type.isConstPointer() );
8695 assert( !param.len.empty() &&
8696 ( std::find_if( destructorIt->second.params.begin(),
8697 destructorIt->second.params.end(),
8698 [¶m]( ParamData const & pd ) { return pd.name == param.len; } ) != destructorIt->second.params.end() ) );
8699 arguments += "reinterpret_cast<" + param.type.type + " const *>( &" + argument + " )";
8700 }
8701 }
8702 else
8703 {
8704 assert( ( param.type.type == "uint32_t" ) && param.type.isValue() && param.arraySizes.empty() && param.len.empty() && !param.optional );
8705 assert( std::find_if( destructorIt->second.params.begin(),
8706 destructorIt->second.params.end(),
8707 [¶m]( ParamData const & pd ) { return pd.len == param.name; } ) != destructorIt->second.params.end() );
8708 arguments += "1";
8709 }
8710 encounteredArgument = true;
8711 }
8712 return arguments;
8713 }
8714
8715 std::tuple<std::string, std::string, std::string, std::string, std::string, std::string, std::string>
generateRAIIHandleDetails(std::pair<std::string,HandleData> const & handle) const8716 VulkanHppGenerator::generateRAIIHandleDetails( std::pair<std::string, HandleData> const & handle ) const
8717 {
8718 std::string getConstructorSuccessCode;
8719 bool multiSuccessCodeContructor = isMultiSuccessCodeConstructor( handle.second.constructorIts );
8720 if ( multiSuccessCodeContructor )
8721 {
8722 getConstructorSuccessCode = R"(
8723 VULKAN_HPP_NAMESPACE::Result getConstructorSuccessCode() const
8724 {
8725 return m_constructorSuccessCode;
8726 }
8727 )";
8728 }
8729
8730 auto [parentType, parentName] = getParentTypeAndName( handle );
8731
8732 std::string handleName = generateRAIIHandleConstructorParamName( handle.first, handle.second.destructorIt );
8733
8734 std::string clearMembers, moveConstructorInitializerList, moveAssignmentInstructions, memberVariables, swapMembers, releaseMembers;
8735
8736 if ( handle.second.destructorIt != m_commands.end() )
8737 {
8738 moveAssignmentInstructions = " clear();";
8739
8740 clearMembers = " if ( m_" + handleName + " )\n";
8741 clearMembers += " {\n";
8742 clearMembers += " getDispatcher()->" + handle.second.destructorIt->first + "( " +
8743 generateRAIIHandleDestructorCallArguments( handle.first, handle.second.destructorIt ) + " );\n";
8744 clearMembers += " }";
8745 for ( auto const & destructorParam : handle.second.destructorIt->second.params )
8746 {
8747 std::string memberName, memberType;
8748 if ( destructorParam.type.type == "Vk" + parentType )
8749 {
8750 memberName = parentName;
8751 memberType = "VULKAN_HPP_NAMESPACE::" + parentType;
8752 }
8753 else if ( destructorParam.type.type == handle.first )
8754 {
8755 memberName = handleName;
8756 memberType = generateNamespacedType( handle.first );
8757 }
8758 else if ( std::find_if( handle.second.destructorIt->second.params.begin(),
8759 handle.second.destructorIt->second.params.end(),
8760 [&destructorParam]( ParamData const & pd )
8761 { return pd.len == destructorParam.name; } ) == handle.second.destructorIt->second.params.end() )
8762 {
8763 std::string name = destructorParam.name;
8764 if ( !destructorParam.type.isValue() )
8765 {
8766 name = startLowerCase( stripPrefix( name, "p" ) );
8767 }
8768 memberName = name;
8769 memberType = destructorParam.type.compose( "VULKAN_HPP_NAMESPACE" );
8770 }
8771 if ( !memberName.empty() )
8772 {
8773 clearMembers += "\n m_" + memberName + " = nullptr;";
8774 moveConstructorInitializerList += "m_" + memberName + "( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_" + memberName + ", {} ) ), ";
8775 moveAssignmentInstructions +=
8776 "\n m_" + memberName + " = VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_" + memberName + ", {} );";
8777 memberVariables += "\n " + memberType + " m_" + memberName + " = {};";
8778 swapMembers += "\n std::swap( m_" + memberName + ", rhs.m_" + memberName + " );";
8779 if ( destructorParam.type.type != handle.first )
8780 {
8781 releaseMembers += "\n m_" + memberName + " = nullptr;";
8782 }
8783 }
8784 }
8785 }
8786 else
8787 {
8788 if ( !handle.second.secondLevelCommands.empty() )
8789 {
8790 assert( !handle.second.constructorIts.empty() );
8791 assert( !handle.second.constructorIts.front()->second.params.empty() );
8792 auto const & frontType = handle.second.constructorIts.front()->second.params.front().type.type;
8793 assert( isHandleType( frontType ) );
8794 #if !defined( NDEBUG )
8795 auto handleIt = m_handles.find( "Vk" + parentType );
8796 #endif
8797 assert( handleIt != m_handles.end() );
8798 assert( handleIt->second.parent == frontType );
8799 std::string frontName = handle.second.constructorIts.front()->second.params.front().name;
8800
8801 clearMembers += "\n m_" + frontName + " = nullptr;";
8802 moveConstructorInitializerList = "m_" + frontName + "( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_" + frontName + ", {} ) ), ";
8803 moveAssignmentInstructions =
8804 "\n m_" + frontName + " = VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_" + frontName + ", {} );";
8805 memberVariables = "\n VULKAN_HPP_NAMESPACE::" + stripPrefix( frontType, "Vk" ) + " m_" + frontName + " = {};";
8806 swapMembers = "\n std::swap( m_" + frontName + ", rhs.m_" + frontName + " );";
8807 releaseMembers += "\n m_" + frontName + " = nullptr;";
8808 }
8809 clearMembers += "\n m_" + handleName + " = nullptr;";
8810 moveConstructorInitializerList += "m_" + handleName + "( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_" + handleName + ", {} ) ), ";
8811 moveAssignmentInstructions +=
8812 "\n m_" + handleName + " = VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_" + handleName + ", {} );";
8813 memberVariables += "\n " + generateNamespacedType( handle.first ) + " m_" + handleName + " = {};";
8814 swapMembers += "\n std::swap( m_" + handleName + ", rhs.m_" + handleName + " );";
8815 }
8816
8817 if ( multiSuccessCodeContructor )
8818 {
8819 clearMembers += "\n m_constructorSuccessCode = VULKAN_HPP_NAMESPACE::Result::eErrorUnknown;";
8820 memberVariables += "\n VULKAN_HPP_NAMESPACE::Result m_constructorSuccessCode = VULKAN_HPP_NAMESPACE::Result::eErrorUnknown;";
8821 swapMembers += "\n std::swap( m_constructorSuccessCode, rhs.m_constructorSuccessCode );";
8822 moveConstructorInitializerList +=
8823 "m_constructorSuccessCode( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_constructorSuccessCode, {} ) ), ";
8824 moveAssignmentInstructions +=
8825 "\n m_constructorSuccessCode = VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_constructorSuccessCode, {} );";
8826 releaseMembers += "\n m_constructorSuccessCode = VULKAN_HPP_NAMESPACE::Result::eErrorUnknown;";
8827 }
8828
8829 if ( handle.first == "VkInstance" )
8830 {
8831 memberVariables += "\n std::unique_ptr<VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::InstanceDispatcher> m_dispatcher;";
8832 }
8833 else if ( handle.first == "VkDevice" )
8834 {
8835 memberVariables += "\n std::unique_ptr<VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher> m_dispatcher;";
8836 }
8837 else if ( handle.second.constructorIts.front()->second.params.front().type.type == "VkDevice" )
8838 {
8839 memberVariables += "\n VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::DeviceDispatcher const * m_dispatcher = nullptr;";
8840 }
8841 else
8842 {
8843 memberVariables += "\n VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::InstanceDispatcher const * m_dispatcher = nullptr;";
8844 }
8845 clearMembers += "\n m_dispatcher = nullptr;";
8846 swapMembers += "\n std::swap( m_dispatcher, rhs.m_dispatcher );";
8847 releaseMembers += "\n m_dispatcher = nullptr;";
8848 releaseMembers += "\n return VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( m_" + handleName + ", nullptr );";
8849
8850 if ( ( handle.first == "VkInstance" ) || ( handle.first == "VkDevice" ) )
8851 {
8852 moveConstructorInitializerList += "m_dispatcher( rhs.m_dispatcher.release() )";
8853 moveAssignmentInstructions += "\n m_dispatcher.reset( rhs.m_dispatcher.release() );";
8854 }
8855 else
8856 {
8857 moveConstructorInitializerList += "m_dispatcher( VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_dispatcher, nullptr ) )";
8858 moveAssignmentInstructions += "\n m_dispatcher = VULKAN_HPP_NAMESPACE::VULKAN_HPP_RAII_NAMESPACE::exchange( rhs.m_dispatcher, nullptr );";
8859 }
8860
8861 return std::make_tuple(
8862 clearMembers, getConstructorSuccessCode, memberVariables, moveConstructorInitializerList, moveAssignmentInstructions, swapMembers, releaseMembers );
8863 }
8864
generateRAIIHandleForwardDeclarations(std::vector<RequireData> const & requireData,std::string const & title) const8865 std::string VulkanHppGenerator::generateRAIIHandleForwardDeclarations( std::vector<RequireData> const & requireData, std::string const & title ) const
8866 {
8867 std::string str;
8868 for ( auto const & require : requireData )
8869 {
8870 for ( auto const & type : require.types )
8871 {
8872 auto handleIt = m_handles.find( type );
8873 if ( handleIt != m_handles.end() )
8874 {
8875 str += " class " + stripPrefix( handleIt->first, "Vk" ) + ";\n";
8876 }
8877 }
8878 }
8879 return addTitleAndProtection( title, str );
8880 }
8881
generateRAIIHandles() const8882 std::string VulkanHppGenerator::generateRAIIHandles() const
8883 {
8884 const std::string raiiHandlesTemplate = R"(
8885 //========================================
8886 //=== RAII HANDLE forward declarations ===
8887 //========================================
8888
8889 ${forwardDeclarations}
8890
8891 //====================
8892 //=== RAII HANDLES ===
8893 //====================
8894
8895 ${raiiHandles}
8896 )";
8897
8898 std::string forwardDeclarations;
8899 for ( auto const & feature : m_features )
8900 {
8901 forwardDeclarations += generateRAIIHandleForwardDeclarations( feature.second.requireData, feature.first );
8902 }
8903 for ( auto const & extIt : m_extensionsByNumber )
8904 {
8905 forwardDeclarations += generateRAIIHandleForwardDeclarations( extIt.second->second.requireData, extIt.second->first );
8906 }
8907
8908 std::set<std::string> listedHandles;
8909 auto handleIt = m_handles.begin();
8910 assert( handleIt->first.empty() );
8911 std::string raiiHandles = generateRAIIHandleContext( *handleIt, m_RAIISpecialFunctions );
8912 for ( ++handleIt; handleIt != m_handles.end(); ++handleIt )
8913 {
8914 raiiHandles += generateRAIIHandle( *handleIt, listedHandles, m_RAIISpecialFunctions );
8915 }
8916 return replaceWithMap( raiiHandlesTemplate, { { "forwardDeclarations", forwardDeclarations }, { "raiiHandles", raiiHandles } } );
8917 }
8918
generateRAIIHandleSingularConstructorArguments(std::pair<std::string,HandleData> const & handle,std::map<std::string,CommandData>::const_iterator constructorIt) const8919 std::string VulkanHppGenerator::generateRAIIHandleSingularConstructorArguments( std::pair<std::string, HandleData> const & handle,
8920 std::map<std::string, CommandData>::const_iterator constructorIt ) const
8921 {
8922 std::string arguments = startLowerCase( stripPrefix( handle.first, "Vk" ) );
8923 if ( handle.second.destructorIt != m_commands.end() )
8924 {
8925 auto [parentType, parentName] = getParentTypeAndName( handle );
8926 parentType = "Vk" + parentType;
8927 for ( auto const & destructorParam : handle.second.destructorIt->second.params )
8928 {
8929 if ( ( destructorParam.type.type != parentType ) && ( destructorParam.type.type != handle.first ) &&
8930 ( std::find_if( handle.second.destructorIt->second.params.begin(),
8931 handle.second.destructorIt->second.params.end(),
8932 [&destructorParam]( ParamData const & pd )
8933 { return pd.len == destructorParam.name; } ) == handle.second.destructorIt->second.params.end() ) )
8934 {
8935 if ( std::find_if( constructorIt->second.params.begin(),
8936 constructorIt->second.params.end(),
8937 [&destructorParam]( ParamData const & pd )
8938 { return pd.type.type == destructorParam.type.type; } ) != constructorIt->second.params.end() )
8939 {
8940 if ( isHandleType( destructorParam.type.type ) )
8941 {
8942 assert( destructorParam.type.isValue() );
8943 arguments += ", static_cast<" + destructorParam.type.type + ">( *" + destructorParam.name + " )";
8944 }
8945 else
8946 {
8947 assert( destructorParam.type.type == "VkAllocationCallbacks" );
8948 arguments += ", allocator";
8949 }
8950 }
8951 else
8952 {
8953 #if !defined( NDEBUG )
8954 bool found = false;
8955 #endif
8956 for ( auto const & constructorParam : constructorIt->second.params )
8957 {
8958 auto structureIt = m_structures.find( constructorParam.type.type );
8959 if ( structureIt != m_structures.end() )
8960 {
8961 auto memberIt = findStructMemberItByType( destructorParam.type.type, structureIt->second.members );
8962 if ( memberIt != structureIt->second.members.end() )
8963 {
8964 #if !defined( NDEBUG )
8965 found = true;
8966 #endif
8967 assert( !constructorParam.type.isValue() );
8968 std::string argument = startLowerCase( stripPrefix( constructorParam.name, "p" ) ) + "." + memberIt->name;
8969 if ( isHandleType( memberIt->type.type ) )
8970 {
8971 argument = "static_cast<" + memberIt->type.type + ">( " + argument + " )";
8972 }
8973 arguments += ", " + argument;
8974 break;
8975 }
8976 }
8977 }
8978 assert( found );
8979 }
8980 }
8981 }
8982 }
8983 return arguments;
8984 }
8985
generateRAIIHandleVectorSizeCheck(std::string const & name,CommandData const & commandData,size_t initialSkipCount,std::map<size_t,std::vector<size_t>> const & countToVectorMap,std::set<size_t> const & skippedParams) const8986 std::string VulkanHppGenerator::generateRAIIHandleVectorSizeCheck( std::string const & name,
8987 CommandData const & commandData,
8988 size_t initialSkipCount,
8989 std::map<size_t, std::vector<size_t>> const & countToVectorMap,
8990 std::set<size_t> const & skippedParams ) const
8991 {
8992 std::string const throwTemplate =
8993 R"#( if ( ${zeroSizeCheck}${firstVectorName}.size() != ${secondVectorName}.size() )
8994 {
8995 #ifndef VULKAN_HPP_NO_EXCEPTIONS
8996 throw LogicError( VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${firstVectorName}.size() != ${secondVectorName}.size()" );
8997 #else
8998 LOG(FATAL) << VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${firstVectorName}.size() != ${secondVectorName}.size()";
8999 #endif
9000 })#";
9001
9002 std::string const throwTemplateVoid =
9003 R"#( if ( ${zeroSizeCheck}${firstVectorName}.size() * sizeof( ${firstDataType} ) != ${secondVectorName}.size() * sizeof( ${secondDataType} ) )
9004 {
9005 #ifndef VULKAN_HPP_NO_EXCEPTIONS
9006 throw LogicError( VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${firstVectorName}.size() * sizeof( ${firstDataType} ) != ${secondVectorName}.size() * sizeof( ${secondDataType} )" );
9007 #else
9008 LOG(FATAL) << VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${firstVectorName}.size() * sizeof( ${firstDataType} ) != ${secondVectorName}.size() * sizeof( ${secondDataType} )";
9009 #endif
9010 })#";
9011
9012 std::string const throwTemplateByLen = R"#( if ( ${vectorName}.size() != ${sizeValue} )
9013 {
9014 #ifndef VULKAN_HPP_NO_EXCEPTIONS
9015 throw LogicError( VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${vectorName}.size() != ${sizeValue}" );
9016 #else
9017 LOG(FATAL) << VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${vectorName}.size() != ${sizeValue}";
9018 #endif
9019 })#";
9020
9021 std::string className = stripPrefix( commandData.params[initialSkipCount - 1].type.type, "Vk" );
9022 std::string commandName = generateCommandName( name, commandData.params, initialSkipCount, m_tags );
9023
9024 std::string sizeChecks;
9025 for ( auto const & cvm : countToVectorMap )
9026 {
9027 size_t defaultStartIndex = determineDefaultStartIndex( commandData.params, skippedParams );
9028 std::string firstVectorName = startLowerCase( stripPrefix( commandData.params[cvm.second[0]].name, "p" ) );
9029
9030 if ( cvm.second.size() == 1 )
9031 {
9032 assert( isLenByStructMember( commandData.params[cvm.second[0]].len, commandData.params[cvm.first] ) );
9033
9034 std::vector<std::string> lenParts = tokenize( commandData.params[cvm.second[0]].len, "->" );
9035 assert( lenParts.size() == 2 );
9036 std::string sizeValue = startLowerCase( stripPrefix( lenParts[0], "p" ) ) + "." + lenParts[1];
9037 sizeChecks += replaceWithMap(
9038 throwTemplateByLen, { { "className", className }, { "commandName", commandName }, { "sizeValue", sizeValue }, { "vectorName", firstVectorName } } );
9039 }
9040 else
9041 {
9042 for ( size_t i = 1; i < cvm.second.size(); i++ )
9043 {
9044 std::string secondVectorName = startLowerCase( stripPrefix( commandData.params[cvm.second[i]].name, "p" ) );
9045 bool withZeroSizeCheck = commandData.params[cvm.second[i]].optional && ( defaultStartIndex <= cvm.second[i] );
9046 if ( commandData.params[cvm.second[0]].type.type == "void" )
9047 {
9048 assert( commandData.params[cvm.second[i]].type.type == "void" );
9049 std::string firstDataType = stripPrefix( commandData.params[cvm.second[0]].name, "p" ) + "Type";
9050 std::string secondDataType = stripPrefix( commandData.params[cvm.second[i]].name, "p" ) + "Type";
9051 sizeChecks += replaceWithMap( throwTemplateVoid,
9052 { { "firstDataType", firstDataType },
9053 { "firstVectorName", firstVectorName },
9054 { "className", className },
9055 { "commandName", commandName },
9056 { "secondDataType", secondDataType },
9057 { "secondVectorName", secondVectorName },
9058 { "zeroSizeCheck", withZeroSizeCheck ? ( "!" + secondVectorName + ".empty() && " ) : "" } } );
9059 }
9060 else
9061 {
9062 sizeChecks += replaceWithMap( throwTemplate,
9063 { { "firstVectorName", firstVectorName },
9064 { "className", className },
9065 { "commandName", commandName },
9066 { "secondVectorName", secondVectorName },
9067 { "zeroSizeCheck", withZeroSizeCheck ? ( "!" + secondVectorName + ".empty() && " ) : "" } } );
9068 }
9069 if ( i + 1 < cvm.second.size() )
9070 {
9071 sizeChecks += "\n";
9072 }
9073 }
9074 }
9075 }
9076 if ( !sizeChecks.empty() )
9077 {
9078 sizeChecks += "\n";
9079 }
9080
9081 return sizeChecks;
9082 }
9083
generateResultAssignment(CommandData const & commandData) const9084 std::string VulkanHppGenerator::generateResultAssignment( CommandData const & commandData ) const
9085 {
9086 std::string resultAssignment;
9087 if ( ( commandData.returnType != "void" ) &&
9088 !( ( commandData.returnType == "VkResult" ) && ( commandData.successCodes.size() == 1 ) && commandData.errorCodes.empty() ) )
9089 {
9090 resultAssignment = commandData.returnType + " result = ";
9091 }
9092 return resultAssignment;
9093 }
9094
generateResultCheck(CommandData const & commandData,std::string const & className,std::string const & classSeparator,std::string commandName,bool enumerating) const9095 std::string VulkanHppGenerator::generateResultCheck(
9096 CommandData const & commandData, std::string const & className, std::string const & classSeparator, std::string commandName, bool enumerating ) const
9097 {
9098 std::string resultCheck;
9099 if ( !commandData.errorCodes.empty() )
9100 {
9101 std::string successCodeList = generateSuccessCodeList( commandData.successCodes, enumerating );
9102
9103 std::string const resultCheckTemplate =
9104 R"(resultCheck( static_cast<VULKAN_HPP_NAMESPACE::Result>( result ), VULKAN_HPP_NAMESPACE_STRING "::${className}${classSeparator}${commandName}"${successCodeList} );)";
9105
9106 resultCheck = replaceWithMap(
9107 resultCheckTemplate,
9108 { { "className", className }, { "classSeparator", classSeparator }, { "commandName", commandName }, { "successCodeList", successCodeList } } );
9109 }
9110 return resultCheck;
9111 }
9112
9113 // Intended only for `enum class Result`!
generateResultExceptions() const9114 std::string VulkanHppGenerator::generateResultExceptions() const
9115 {
9116 const std::string templateString = R"(
9117 ${enter} class ${className} : public SystemError
9118 {
9119 public:
9120 ${className}( std::string const & message )
9121 : SystemError( make_error_code( ${enumName}::${enumMemberName} ), message ) {}
9122 ${className}( char const * message )
9123 : SystemError( make_error_code( ${enumName}::${enumMemberName} ), message ) {}
9124 };
9125 ${leave})";
9126
9127 std::string str;
9128 auto enumIt = m_enums.find( "VkResult" );
9129 for ( auto const & value : enumIt->second.values )
9130 {
9131 if ( value.name.starts_with( "VK_ERROR" ) )
9132 {
9133 auto [enter, leave] = generateProtection( getProtect( value ) );
9134 std::string valueName = generateEnumValueName( enumIt->first, value.name, false, m_tags );
9135 str += replaceWithMap( templateString,
9136 { { "className", stripPrefix( valueName, "eError" ) + "Error" },
9137 { "enter", enter },
9138 { "enumName", stripPrefix( enumIt->first, "Vk" ) },
9139 { "enumMemberName", valueName },
9140 { "leave", leave } } );
9141 }
9142 }
9143 return str;
9144 }
9145
generateReturnStatement(std::string const & commandName,CommandData const & commandData,std::string const & returnVariable,std::string const & returnType,std::string const & dataType,size_t initialSkipCount,size_t returnParam,CommandFlavourFlags flavourFlags,bool enumerating,bool raii) const9146 std::string VulkanHppGenerator::generateReturnStatement( std::string const & commandName,
9147 CommandData const & commandData,
9148 std::string const & returnVariable,
9149 std::string const & returnType,
9150 std::string const & dataType,
9151 size_t initialSkipCount,
9152 size_t returnParam,
9153 CommandFlavourFlags flavourFlags,
9154 bool enumerating,
9155 bool raii ) const
9156 {
9157 bool unique = flavourFlags & CommandFlavourFlagBits::unique;
9158
9159 std::string returnStatement;
9160 if ( commandData.returnType.starts_with( "Vk" ) )
9161 {
9162 if ( ( commandData.successCodes.size() == 1 ) || enumerating )
9163 {
9164 assert( commandData.successCodes[0] == "VK_SUCCESS" );
9165 if ( raii || commandData.errorCodes.empty() )
9166 {
9167 if ( !returnVariable.empty() )
9168 {
9169 returnStatement = "return " + returnVariable + ";";
9170 }
9171 }
9172 else
9173 {
9174 if ( returnVariable.empty() )
9175 {
9176 assert( !unique );
9177 returnStatement = "return createResultValueType( static_cast<VULKAN_HPP_NAMESPACE::Result>( result ) );";
9178 }
9179 else if ( unique )
9180 {
9181 assert( returnParam != INVALID_INDEX );
9182 returnStatement = "return createResultValueType( static_cast<VULKAN_HPP_NAMESPACE::Result>( result ), ";
9183 if ( dataType.starts_with( "std::" ) )
9184 {
9185 returnStatement += "std::move( unique" + startUpperCase( returnVariable ) + " )";
9186 }
9187 else
9188 {
9189 returnStatement += "UniqueHandle<" + dataType + ", Dispatch>( " + returnVariable + ", " +
9190 generateObjectDeleter( commandName, commandData, initialSkipCount, returnParam ) + " )";
9191 }
9192 returnStatement += " );";
9193 }
9194 else
9195 {
9196 returnStatement = "return createResultValueType( static_cast<VULKAN_HPP_NAMESPACE::Result>( result ), " + returnVariable + " );";
9197 }
9198 }
9199 }
9200 else
9201 {
9202 if ( returnVariable.empty() )
9203 {
9204 assert( !unique );
9205 returnStatement = "return static_cast<VULKAN_HPP_NAMESPACE::" + stripPrefix( commandData.returnType, "Vk" ) + ">( result );";
9206 }
9207 else if ( unique )
9208 {
9209 assert( returnParam != INVALID_INDEX );
9210 assert( returnType.starts_with( "ResultValue<" ) && returnType.ends_with( ">" ) );
9211 returnStatement = "return " + returnType + "( static_cast<VULKAN_HPP_NAMESPACE::Result>( result ), ";
9212 if ( dataType.starts_with( "std::" ) )
9213 {
9214 returnStatement += "std::move( unique" + startUpperCase( returnVariable ) + " )";
9215 }
9216 else
9217 {
9218 returnStatement += "UniqueHandle<" + dataType + ", Dispatch>( " + returnVariable + ", " +
9219 generateObjectDeleter( commandName, commandData, initialSkipCount, returnParam ) + " )";
9220 }
9221 returnStatement += " );";
9222 }
9223 else
9224 {
9225 assert( returnType.starts_with( raii ? "std::pair<VULKAN_HPP_NAMESPACE::Result, " : "ResultValue<" ) && returnType.ends_with( ">" ) );
9226 returnStatement =
9227 "return " + ( raii ? "std::make_pair" : returnType ) + "( static_cast<VULKAN_HPP_NAMESPACE::Result>( result ), " + returnVariable + " );";
9228 }
9229 }
9230 }
9231 else
9232 {
9233 assert( !unique );
9234 if ( returnVariable.empty() )
9235 {
9236 if ( commandData.returnType != "void" )
9237 {
9238 returnStatement = "return result;";
9239 }
9240 }
9241 else
9242 {
9243 returnStatement = "return " + returnVariable + ";";
9244 }
9245 }
9246 return returnStatement;
9247 }
9248
generateReturnType(CommandData const & commandData,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,CommandFlavourFlags flavourFlags,bool raii,std::string const & dataType) const9249 std::string VulkanHppGenerator::generateReturnType( CommandData const & commandData,
9250 std::vector<size_t> const & returnParams,
9251 std::map<size_t, VectorParamData> const & vectorParams,
9252 CommandFlavourFlags flavourFlags,
9253 bool raii,
9254 std::string const & dataType ) const
9255 {
9256 bool chained = flavourFlags & CommandFlavourFlagBits::chained;
9257 bool unique = flavourFlags & CommandFlavourFlagBits::unique;
9258
9259 std::string modifiedDataType = dataType;
9260 if ( chained )
9261 {
9262 assert( !unique );
9263 modifiedDataType = dataType.starts_with( "std::vector" )
9264 ? ( std::string( "std::vector<StructureChain" ) + ( raii ? "" : ", StructureChainAllocator" ) + ">" )
9265 : "StructureChain<X, Y, Z...>";
9266 }
9267 else if ( unique )
9268 {
9269 assert( !chained );
9270 assert( ( returnParams.size() == 1 ) && isHandleType( commandData.params[returnParams[0]].type.type ) );
9271 if ( dataType.starts_with( "std::vector" ) )
9272 {
9273 auto from = dataType.find( '<' ) + 1;
9274 assert( from != std::string::npos );
9275 auto to = dataType.find( '>', from );
9276 assert( to == dataType.length() - 1 );
9277 std::string type = dataType.substr( from, to - from );
9278 assert( type.starts_with( "VULKAN_HPP_NAMESPACE::" ) );
9279 modifiedDataType.replace( from, to - from, "UniqueHandle<" + type + ", Dispatch>, " + stripPrefix( type, "VULKAN_HPP_NAMESPACE::" ) + "Allocator" );
9280 }
9281 else
9282 {
9283 assert( !dataType.starts_with( "std::" ) );
9284 modifiedDataType = "UniqueHandle<" + dataType + ", Dispatch>";
9285 }
9286 }
9287
9288 std::string returnType;
9289 if ( ( 1 < commandData.successCodes.size() ) && returnParams.empty() && !chained )
9290 {
9291 assert( ( commandData.returnType == "VkResult" ) && !unique );
9292 returnType = "VULKAN_HPP_NAMESPACE::Result";
9293 }
9294 else if ( ( commandData.returnType != "VkResult" ) && ( commandData.returnType != "void" ) )
9295 {
9296 assert( returnParams.empty() && !chained && !unique );
9297 if ( commandData.returnType.starts_with( "Vk" ) )
9298 {
9299 returnType = generateNamespacedType( commandData.returnType );
9300 }
9301 else
9302 {
9303 returnType = commandData.returnType;
9304 }
9305 }
9306 else if ( ( commandData.returnType == "void" ) ||
9307 ( ( commandData.returnType == "VkResult" ) && ( commandData.successCodes.size() == 1 ) && ( commandData.errorCodes.empty() || raii ) ) )
9308 {
9309 assert( !unique );
9310 assert( ( commandData.returnType != "void" ) || ( returnParams.size() <= 2 ) );
9311 returnType = modifiedDataType;
9312 }
9313 else
9314 {
9315 assert( commandData.returnType == "VkResult" );
9316 assert( !commandData.successCodes.empty() && ( commandData.successCodes[0] == "VK_SUCCESS" ) );
9317 if ( ( 1 < commandData.successCodes.size() ) && ( ( returnParams.size() == 1 ) || ( ( returnParams.size() == 2 ) && vectorParams.empty() ) ) )
9318 {
9319 assert( !commandData.errorCodes.empty() );
9320 returnType = ( raii ? "std::pair<VULKAN_HPP_NAMESPACE::Result, " : "ResultValue<" ) + modifiedDataType + ">";
9321 }
9322 else
9323 {
9324 assert(
9325 ( ( commandData.successCodes.size() == 1 ) || ( ( commandData.successCodes.size() == 2 ) && ( commandData.successCodes[1] == "VK_INCOMPLETE" ) ) ) &&
9326 ( returnParams.size() <= 3 ) );
9327 returnType = raii ? modifiedDataType : ( "typename ResultValueType<" + modifiedDataType + ">::type" );
9328 }
9329 }
9330 return returnType;
9331 }
9332
generateReturnVariable(CommandData const & commandData,std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,CommandFlavourFlags flavourFlags) const9333 std::string VulkanHppGenerator::generateReturnVariable( CommandData const & commandData,
9334 std::vector<size_t> const & returnParams,
9335 std::map<size_t, VectorParamData> const & vectorParams,
9336 CommandFlavourFlags flavourFlags ) const
9337 {
9338 bool chained = flavourFlags & CommandFlavourFlagBits::chained;
9339 bool singular = flavourFlags & CommandFlavourFlagBits::singular;
9340
9341 std::string returnVariable;
9342 switch ( returnParams.size() )
9343 {
9344 case 0: break; // no return variable
9345 case 1:
9346 if ( chained )
9347 {
9348 returnVariable = "structureChain";
9349 }
9350 else
9351 {
9352 returnVariable = startLowerCase( stripPrefix( commandData.params[returnParams[0]].name, "p" ) );
9353 if ( singular )
9354 {
9355 returnVariable = stripPluralS( returnVariable, m_tags );
9356 }
9357 }
9358 break;
9359 case 2:
9360 if ( chained )
9361 {
9362 returnVariable = "structureChains";
9363 }
9364 else
9365 {
9366 auto vectorParamIt = vectorParams.find( returnParams[1] );
9367 if ( vectorParamIt == vectorParams.end() )
9368 { // the return variable is simply named "data", and holds the multi-return value stuff
9369 returnVariable = "data";
9370 }
9371 else
9372 {
9373 assert( vectorParamIt->second.lenParam == returnParams[0] );
9374 assert( !singular );
9375 returnVariable = startLowerCase( stripPrefix( commandData.params[returnParams[1]].name, "p" ) );
9376 }
9377 }
9378 break;
9379 case 3:
9380 assert( !chained && !singular );
9381 assert( ( vectorParams.size() == 2 ) && ( vectorParams.begin()->first == returnParams[1] ) &&
9382 ( vectorParams.begin()->second.lenParam == returnParams[0] ) && ( std::next( vectorParams.begin() )->first == returnParams[2] ) &&
9383 ( std::next( vectorParams.begin() )->second.lenParam == returnParams[0] ) );
9384 returnVariable = "data";
9385 break;
9386 }
9387 return returnVariable;
9388 }
9389
generateSizeCheck(std::vector<std::vector<MemberData>::const_iterator> const & arrayIts,std::string const & structName,bool mutualExclusiveLens) const9390 std::string VulkanHppGenerator::generateSizeCheck( std::vector<std::vector<MemberData>::const_iterator> const & arrayIts,
9391 std::string const & structName,
9392 bool mutualExclusiveLens ) const
9393 {
9394 std::string sizeCheck;
9395 if ( 1 < arrayIts.size() )
9396 {
9397 static const std::string throwTextTemplate = R"( if ( ${throwCheck} )
9398 {
9399 throw LogicError( VULKAN_HPP_NAMESPACE_STRING"::${structName}::${structName}: ${throwCheck}" );
9400 }
9401 )";
9402
9403 std::string assertionText, throwText;
9404 if ( mutualExclusiveLens )
9405 {
9406 // exactly one of the arrays has to be non-empty
9407 std::string sum;
9408 for ( auto it : arrayIts )
9409 {
9410 sum += "!" + startLowerCase( stripPrefix( it->name, "p" ) ) + "_.empty() + ";
9411 }
9412 sum.resize( sum.size() - 3 );
9413 assertionText += " VULKAN_HPP_ASSERT( ( " + sum + " ) <= 1);\n";
9414 throwText += replaceWithMap( throwTextTemplate, { { "structName", structName }, { "throwCheck", "1 < ( " + sum + " )" } } );
9415 }
9416 else
9417 {
9418 for ( size_t first = 0; first + 1 < arrayIts.size(); ++first )
9419 {
9420 assert( arrayIts[first]->name.starts_with( "p" ) );
9421 std::string firstName = startLowerCase( stripPrefix( arrayIts[first]->name, "p" ) ) + "_";
9422 for ( auto second = first + 1; second < arrayIts.size(); ++second )
9423 {
9424 assert( arrayIts[second]->name.starts_with( "p" ) );
9425 std::string secondName = startLowerCase( stripPrefix( arrayIts[second]->name, "p" ) ) + "_";
9426 std::string assertionCheck = firstName + ".size() == " + secondName + ".size()";
9427 std::string throwCheck = firstName + ".size() != " + secondName + ".size()";
9428 if ( ( !arrayIts[first]->optional.empty() && arrayIts[first]->optional.front() ) ||
9429 ( !arrayIts[second]->optional.empty() && arrayIts[second]->optional.front() ) )
9430 {
9431 assertionCheck = "( " + assertionCheck + " )";
9432 throwCheck = "( " + throwCheck + " )";
9433 if ( !arrayIts[second]->optional.empty() && arrayIts[second]->optional.front() )
9434 {
9435 assertionCheck = secondName + ".empty() || " + assertionCheck;
9436 throwCheck = "!" + secondName + ".empty() && " + throwCheck;
9437 }
9438 if ( !arrayIts[first]->optional.empty() && arrayIts[first]->optional.front() )
9439 {
9440 assertionCheck = firstName + ".empty() || " + assertionCheck;
9441 throwCheck = "!" + firstName + ".empty() && " + throwCheck;
9442 }
9443 }
9444 assertionText += " VULKAN_HPP_ASSERT( " + assertionCheck + " );\n";
9445 throwText += replaceWithMap( throwTextTemplate, { { "structName", structName }, { "throwCheck", throwCheck } } );
9446 }
9447 }
9448 }
9449 sizeCheck += "\n#ifdef VULKAN_HPP_NO_EXCEPTIONS\n" + assertionText + "#else\n" + throwText + "#endif /*VULKAN_HPP_NO_EXCEPTIONS*/\n" + " ";
9450 }
9451 return sizeCheck;
9452 }
9453
generateStaticAssertions() const9454 std::string VulkanHppGenerator::generateStaticAssertions() const
9455 {
9456 std::string staticAssertions;
9457 for ( auto const & feature : m_features )
9458 {
9459 staticAssertions += generateStaticAssertions( feature.second.requireData, feature.first );
9460 }
9461 for ( auto const & extIt : m_extensionsByNumber )
9462 {
9463 staticAssertions += generateStaticAssertions( extIt.second->second.requireData, extIt.second->first );
9464 }
9465 return staticAssertions;
9466 }
9467
generateStaticAssertions(std::vector<RequireData> const & requireData,std::string const & title) const9468 std::string VulkanHppGenerator::generateStaticAssertions( std::vector<RequireData> const & requireData, std::string const & title ) const
9469 {
9470 std::string str;
9471 for ( auto const & require : requireData )
9472 {
9473 for ( auto const & type : require.types )
9474 {
9475 auto handleIt = m_handles.find( type );
9476 if ( handleIt != m_handles.end() )
9477 {
9478 std::string const assertionTemplate = R"(
9479 VULKAN_HPP_STATIC_ASSERT( sizeof( VULKAN_HPP_NAMESPACE::${className} ) == sizeof( Vk${className} ), "handle and wrapper have different size!" );
9480 VULKAN_HPP_STATIC_ASSERT( std::is_nothrow_move_constructible<VULKAN_HPP_NAMESPACE::${className}>::value, "${className} is not nothrow_move_constructible!" );
9481 )";
9482 str += replaceWithMap( assertionTemplate, { { "className", stripPrefix( handleIt->first, "Vk" ) } } );
9483 }
9484 else
9485 {
9486 auto structIt = m_structures.find( type );
9487 if ( structIt != m_structures.end() )
9488 {
9489 std::string const assertionTemplate = R"(
9490 VULKAN_HPP_STATIC_ASSERT( sizeof( VULKAN_HPP_NAMESPACE::${structureType} ) == sizeof( Vk${structureType} ), "struct and wrapper have different size!" );
9491 VULKAN_HPP_STATIC_ASSERT( std::is_standard_layout<VULKAN_HPP_NAMESPACE::${structureType}>::value, "struct wrapper is not a standard layout!" );
9492 VULKAN_HPP_STATIC_ASSERT( std::is_nothrow_move_constructible<VULKAN_HPP_NAMESPACE::${structureType}>::value, "${structureType} is not nothrow_move_constructible!" );
9493 )";
9494 str += replaceWithMap( assertionTemplate, { { "structureType", stripPrefix( structIt->first, "Vk" ) } } );
9495 }
9496 }
9497 }
9498 }
9499 return addTitleAndProtection( title, str );
9500 }
9501
generateStruct(std::pair<std::string,StructureData> const & structure,std::set<std::string> & listedStructs) const9502 std::string VulkanHppGenerator::generateStruct( std::pair<std::string, StructureData> const & structure, std::set<std::string> & listedStructs ) const
9503 {
9504 assert( listedStructs.find( structure.first ) == listedStructs.end() );
9505
9506 std::string str;
9507 for ( auto const & member : structure.second.members )
9508 {
9509 auto structIt = m_structures.find( member.type.type );
9510 if ( ( structIt != m_structures.end() ) && ( structure.first != member.type.type ) && ( listedStructs.find( member.type.type ) == listedStructs.end() ) )
9511 {
9512 str += generateStruct( *structIt, listedStructs );
9513 }
9514 }
9515
9516 if ( !structure.second.subStruct.empty() )
9517 {
9518 auto structureIt = m_structures.find( structure.second.subStruct );
9519 if ( ( structureIt != m_structures.end() ) && ( listedStructs.find( structureIt->first ) == listedStructs.end() ) )
9520 {
9521 str += generateStruct( *structureIt, listedStructs );
9522 }
9523 }
9524
9525 if ( structure.second.isUnion )
9526 {
9527 str += generateUnion( structure );
9528 }
9529 else
9530 {
9531 str += generateStructure( structure );
9532 }
9533
9534 listedStructs.insert( structure.first );
9535 return str;
9536 }
9537
generateStructCompareOperators(std::pair<std::string,StructureData> const & structData) const9538 std::string VulkanHppGenerator::generateStructCompareOperators( std::pair<std::string, StructureData> const & structData ) const
9539 {
9540 static const std::set<std::string> simpleTypes = { "char", "double", "DWORD", "float", "HANDLE", "HINSTANCE", "HMONITOR",
9541 "HWND", "int", "int8_t", "int16_t", "int32_t", "int64_t", "LPCWSTR",
9542 "size_t", "uint8_t", "uint16_t", "uint32_t", "uint64_t" };
9543 // two structs are compared by comparing each of the elements
9544 std::string compareMembers, spaceshipMembers;
9545 std::string intro = "";
9546 bool nonDefaultCompare = false;
9547 std::string spaceshipOrdering = containsFloatingPoints( structData.second.members ) ? "std::partial_ordering" : "std::strong_ordering";
9548 for ( size_t i = 0; i < structData.second.members.size(); i++ )
9549 {
9550 MemberData const & member = structData.second.members[i];
9551 auto typeIt = m_types.find( member.type.type );
9552 assert( typeIt != m_types.end() );
9553 if ( ( typeIt->second.category == TypeCategory::Requires ) && member.type.postfix.empty() && ( simpleTypes.find( member.type.type ) == simpleTypes.end() ) )
9554 {
9555 nonDefaultCompare = true;
9556 // this type might support operator==() or operator<=>()... that is, use memcmp
9557 compareMembers += intro + "( memcmp( &" + member.name + ", &rhs." + member.name + ", sizeof( " + member.type.type + " ) ) == 0 )";
9558
9559 static const std::string spaceshipMemberTemplate =
9560 R"( if ( auto cmp = memcmp( &${name}, &rhs.${name}, sizeof( ${type} ) ); cmp != 0 )
9561 return ( cmp < 0 ) ? ${ordering}::less : ${ordering}::greater;
9562 )";
9563 spaceshipMembers +=
9564 replaceWithMap( spaceshipMemberTemplate, { { "name", member.name }, { "ordering", spaceshipOrdering }, { "type", member.type.type } } );
9565 }
9566 else if ( member.type.type == "char" && !member.len.empty() )
9567 {
9568 // compare null-terminated strings
9569 nonDefaultCompare = true;
9570 assert( member.len.size() < 3 );
9571 if ( member.len.size() == 1 )
9572 {
9573 assert( member.len[0] == "null-terminated" );
9574 compareMembers += intro + "( ( " + member.name + " == rhs." + member.name + " ) || ( strcmp( " + member.name + ", rhs." + member.name + " ) == 0 ) )";
9575
9576 static const std::string spaceshipMemberTemplate =
9577 R"( if ( ${name} != rhs.${name} )
9578 if ( auto cmp = strcmp( ${name}, rhs.${name} ); cmp != 0 )
9579 return ( cmp < 0 ) ? ${ordering}::less : ${ordering}::greater;
9580 )";
9581 spaceshipMembers += replaceWithMap( spaceshipMemberTemplate, { { "name", member.name }, { "ordering", spaceshipOrdering } } );
9582 }
9583 else
9584 {
9585 assert( member.len[1] == "null-terminated" );
9586 assert( ( member.type.prefix == "const" ) && ( member.type.postfix == "* const *" ) );
9587 static const std::string compareMemberTemplate =
9588 R"(std::equal( ${name}, ${name} + ${count}, rhs.${name}, []( char const * left, char const * right ) { return ( left == right ) || ( strcmp( left, right ) == 0 ); } ))";
9589 compareMembers += intro + replaceWithMap( compareMemberTemplate, { { "count", member.len[0] }, { "name", member.name } } );
9590
9591 static const std::string spaceshipMemberTemplate = R"( for ( size_t i = 0; i < ${count}; ++i )
9592 {
9593 if ( ${name}[i] != rhs.${name}[i] )
9594 if ( auto cmp = strcmp( ${name}[i], rhs.${name}[i] ); cmp != 0 )
9595 return cmp < 0 ? ${ordering}::less : ${ordering}::greater;
9596 }
9597 )";
9598 spaceshipMembers +=
9599 replaceWithMap( spaceshipMemberTemplate, { { "count", member.len[0] }, { "name", member.name }, { "ordering", spaceshipOrdering } } );
9600 }
9601 }
9602 else
9603 {
9604 // for all others, we use the operator== of that type
9605 compareMembers += intro + "( " + member.name + " == rhs." + member.name + " )";
9606 spaceshipMembers += " if ( auto cmp = " + member.name + " <=> rhs." + member.name + "; cmp != 0 ) return cmp;\n";
9607 }
9608 intro = "\n && ";
9609 }
9610
9611 std::string structName = stripPrefix( structData.first, "Vk" );
9612
9613 std::string compareBody, spaceshipOperator, spaceshipOperatorIf, spaceshipOperatorElse, spaceshipOperatorEndif;
9614 if ( nonDefaultCompare )
9615 {
9616 compareBody = " return " + compareMembers + ";";
9617
9618 if ( !containsFuncPointer( structData.first ) )
9619 {
9620 static const std::string spaceshipOperatorTemplate =
9621 R"( ${ordering} operator<=>( ${name} const & rhs ) const VULKAN_HPP_NOEXCEPT
9622 {
9623 ${spaceshipMembers}
9624 return ${ordering}::equivalent;
9625 })";
9626 spaceshipOperatorIf = "#if defined(VULKAN_HPP_HAS_SPACESHIP_OPERATOR)";
9627 spaceshipOperator =
9628 replaceWithMap( spaceshipOperatorTemplate, { { "name", structName }, { "ordering", spaceshipOrdering }, { "spaceshipMembers", spaceshipMembers } } );
9629 spaceshipOperatorElse = "#endif\n";
9630 spaceshipOperatorEndif = "";
9631 }
9632 }
9633 else
9634 {
9635 // use reflection only if VULKAN_HPP_USE_REFLECT is defined
9636 static const std::string compareBodyTemplate = R"(#if defined( VULKAN_HPP_USE_REFLECT )
9637 return this->reflect() == rhs.reflect();
9638 #else
9639 return ${compareMembers};
9640 #endif)";
9641 compareBody = replaceWithMap( compareBodyTemplate, { { "compareMembers", compareMembers } } );
9642
9643 if ( !containsFuncPointer( structData.first ) )
9644 {
9645 spaceshipOperatorIf = "#if defined(VULKAN_HPP_HAS_SPACESHIP_OPERATOR)";
9646 spaceshipOperator = "auto operator<=>( " + structName + " const & ) const = default;";
9647 spaceshipOperatorElse = "#else";
9648 spaceshipOperatorEndif = "#endif\n";
9649 }
9650 }
9651
9652 static const std::string compareTemplate = R"(
9653 ${spaceshipOperatorIf}
9654 ${spaceshipOperator}
9655 ${spaceshipOperatorElse}
9656 bool operator==( ${name} const & rhs ) const VULKAN_HPP_NOEXCEPT
9657 {
9658 ${compareBody}
9659 }
9660
9661 bool operator!=( ${name} const & rhs ) const VULKAN_HPP_NOEXCEPT
9662 {
9663 return !operator==( rhs );
9664 }
9665 ${spaceshipOperatorEndif})";
9666
9667 return replaceWithMap( compareTemplate,
9668 { { "name", structName },
9669 { "compareBody", compareBody },
9670 { "spaceshipOperator", spaceshipOperator },
9671 { "spaceshipOperatorElse", spaceshipOperatorElse },
9672 { "spaceshipOperatorEndif", spaceshipOperatorEndif },
9673 { "spaceshipOperatorIf", spaceshipOperatorIf } } );
9674 }
9675
generateStructConstructors(std::pair<std::string,StructureData> const & structData) const9676 std::string VulkanHppGenerator::generateStructConstructors( std::pair<std::string, StructureData> const & structData ) const
9677 {
9678 // the constructor with all the elements as arguments, with defaults
9679 // and the simple copy constructor from the corresponding vulkan structure
9680 static const std::string constructors = R"(${constexpr}${structName}(${arguments}) VULKAN_HPP_NOEXCEPT
9681 ${initializers}
9682 {}
9683
9684 ${constexpr}${structName}( ${structName} const & rhs ) VULKAN_HPP_NOEXCEPT = default;
9685
9686 ${structName}( Vk${structName} const & rhs ) VULKAN_HPP_NOEXCEPT
9687 : ${structName}( *reinterpret_cast<${structName} const *>( &rhs ) )
9688 {}
9689 )";
9690
9691 std::string arguments, initializers;
9692 bool listedArgument = false;
9693 bool firstArgument = true;
9694 for ( auto const & member : structData.second.members )
9695 {
9696 // gather the arguments
9697 std::string argument = generateStructConstructorArgument( listedArgument, member, true );
9698 if ( !argument.empty() )
9699 {
9700 listedArgument = true;
9701 arguments += argument;
9702 }
9703
9704 // gather the initializers; skip members with exactly one legal value
9705 if ( member.value.empty() )
9706 {
9707 initializers += std::string( firstArgument ? ": " : ", " ) + member.name + "( " + member.name + "_ )";
9708 firstArgument = false;
9709 }
9710 }
9711 auto pNextIt = std::find_if( structData.second.members.begin(), structData.second.members.end(), []( MemberData const & md ) { return md.name == "pNext"; } );
9712 if ( pNextIt != structData.second.members.end() )
9713 {
9714 // add pNext as a last optional argument to the constructor
9715 arguments += std::string( listedArgument ? ", " : "" ) + pNextIt->type.compose( "VULKAN_HPP_NAMESPACE" ) + " pNext_ = nullptr";
9716 }
9717
9718 std::string str = replaceWithMap( constructors,
9719 { { "arguments", arguments },
9720 { "constexpr", generateConstexprString( structData.first ) },
9721 { "initializers", initializers },
9722 { "structName", stripPrefix( structData.first, "Vk" ) } } );
9723
9724 str += generateStructConstructorsEnhanced( structData );
9725 return str;
9726 }
9727
generateStructConstructorsEnhanced(std::pair<std::string,StructureData> const & structData) const9728 std::string VulkanHppGenerator::generateStructConstructorsEnhanced( std::pair<std::string, StructureData> const & structData ) const
9729 {
9730 if ( std::find_if( structData.second.members.begin(),
9731 structData.second.members.end(),
9732 [this, &structData]( MemberData const & md ) { return hasLen( structData.second.members, md ); } ) != structData.second.members.end() )
9733 {
9734 // map from len-members to all the array members using that len
9735 std::map<std::vector<MemberData>::const_iterator, std::vector<std::vector<MemberData>::const_iterator>> lenIts;
9736 for ( auto mit = structData.second.members.begin(); mit != structData.second.members.end(); ++mit )
9737 {
9738 if ( hasLen( structData.second.members, *mit ) )
9739 {
9740 std::string lenName = ( mit->len.front() == "codeSize / 4" ) ? "codeSize" : mit->len.front();
9741 auto lenIt = findStructMemberIt( lenName, structData.second.members );
9742 assert( lenIt != mit );
9743 lenIts[lenIt].push_back( mit );
9744 }
9745 }
9746
9747 std::string arguments, initializers;
9748 bool listedArgument = false;
9749 bool firstArgument = true;
9750 bool arrayListed = false;
9751 std::string templateHeader, sizeChecks;
9752 for ( auto mit = structData.second.members.begin(); mit != structData.second.members.end(); ++mit )
9753 {
9754 // gather the initializers
9755 if ( mit->name == "pNext" ) // for pNext, we just get the initializer... the argument is added at the end
9756 {
9757 initializers += std::string( firstArgument ? ":" : "," ) + " pNext( pNext_ )";
9758 firstArgument = false;
9759 }
9760 else if ( mit->value.empty() ) // skip constant members
9761 {
9762 auto litit = lenIts.find( mit );
9763 if ( litit != lenIts.end() )
9764 {
9765 // len arguments just have an initalizer, from the ArrayProxyNoTemporaries size
9766 initializers +=
9767 ( firstArgument ? ": " : ", " ) + mit->name + "( " + generateLenInitializer( mit, litit, structData.second.mutualExclusiveLens ) + " )";
9768 sizeChecks += generateSizeCheck( litit->second, stripPrefix( structData.first, "Vk" ), structData.second.mutualExclusiveLens );
9769 }
9770 else if ( hasLen( structData.second.members, *mit ) )
9771 {
9772 assert( mit->name.starts_with( "p" ) );
9773 std::string argumentName = startLowerCase( stripPrefix( mit->name, "p" ) ) + "_";
9774
9775 assert( mit->type.postfix.ends_with( "*" ) );
9776 std::string argumentType = trimEnd( stripPostfix( mit->type.compose( "VULKAN_HPP_NAMESPACE" ), "*" ) );
9777 if ( ( mit->type.type == "void" ) && ( argumentType.find( '*' ) == std::string::npos ) )
9778 {
9779 // the argument after stripping one pointer is just void
9780 assert( templateHeader.empty() );
9781 templateHeader = " template <typename T>\n";
9782
9783 size_t pos = argumentType.find( "void" );
9784 assert( pos != std::string::npos );
9785 argumentType.replace( pos, strlen( "void" ), "T" );
9786 }
9787
9788 arguments += listedArgument ? ", " : "";
9789 arguments += "VULKAN_HPP_NAMESPACE::ArrayProxyNoTemporaries<" + argumentType + "> const & " + argumentName;
9790 if ( arrayListed )
9791 {
9792 arguments += " = {}";
9793 }
9794 listedArgument = true;
9795 arrayListed = true;
9796
9797 initializers += ( firstArgument ? ": " : ", " ) + mit->name + "( " + argumentName + ".data() )";
9798 }
9799 else
9800 {
9801 std::string argument = generateStructConstructorArgument( listedArgument, *mit, arrayListed );
9802 if ( !argument.empty() )
9803 {
9804 listedArgument = true;
9805 arguments += argument;
9806 }
9807 initializers += ( firstArgument ? ": " : ", " ) + mit->name + "( " + mit->name + "_ )";
9808 }
9809 firstArgument = false;
9810 }
9811 }
9812
9813 auto pNextIt =
9814 std::find_if( structData.second.members.begin(), structData.second.members.end(), []( MemberData const & md ) { return md.name == "pNext"; } );
9815 if ( pNextIt != structData.second.members.end() )
9816 {
9817 // add pNext as a last optional argument to the constructor
9818 arguments += std::string( listedArgument ? ", " : "" ) + pNextIt->type.compose( "VULKAN_HPP_NAMESPACE" ) + " pNext_ = nullptr";
9819 }
9820
9821 static const std::string constructorTemplate = R"(
9822 #if !defined( VULKAN_HPP_DISABLE_ENHANCED_MODE )
9823 ${templateHeader} ${structName}( ${arguments} )
9824 ${initializers}
9825 {${sizeChecks}}
9826 #endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
9827 )";
9828
9829 return replaceWithMap( constructorTemplate,
9830 { { "arguments", arguments },
9831 { "initializers", initializers },
9832 { "sizeChecks", sizeChecks },
9833 { "structName", stripPrefix( structData.first, "Vk" ) },
9834 { "templateHeader", templateHeader } } );
9835 }
9836 return "";
9837 }
9838
generateStructConstructorArgument(bool listedArgument,MemberData const & memberData,bool withDefault) const9839 std::string VulkanHppGenerator::generateStructConstructorArgument( bool listedArgument, MemberData const & memberData, bool withDefault ) const
9840 {
9841 // skip members 'pNext' and members with a specified value, as they are never explicitly set
9842 std::string str;
9843 if ( ( memberData.name != "pNext" ) && memberData.value.empty() )
9844 {
9845 str += ( listedArgument ? ( ", " ) : "" );
9846 if ( memberData.arraySizes.empty() )
9847 {
9848 str += memberData.type.compose( "VULKAN_HPP_NAMESPACE" ) + " ";
9849 }
9850 else
9851 {
9852 str += generateStandardArray( memberData.type.compose( "VULKAN_HPP_NAMESPACE" ), memberData.arraySizes ) + " const & ";
9853 }
9854 str += memberData.name + "_";
9855
9856 if ( withDefault )
9857 {
9858 str += " = ";
9859 auto enumIt = m_enums.find( memberData.type.type );
9860 if ( enumIt != m_enums.end() && memberData.type.postfix.empty() )
9861 {
9862 str += generateEnumInitializer( memberData.type, memberData.arraySizes, enumIt->second.values, enumIt->second.isBitmask );
9863 }
9864 else
9865 {
9866 assert( memberData.value.empty() );
9867 // all the rest can be initialized with just {}
9868 str += "{}";
9869 }
9870 }
9871 }
9872 return str;
9873 }
9874
generateStructHashStructure(std::pair<std::string,StructureData> const & structure,std::set<std::string> & listedStructs) const9875 std::string VulkanHppGenerator::generateStructHashStructure( std::pair<std::string, StructureData> const & structure,
9876 std::set<std::string> & listedStructs ) const
9877 {
9878 assert( listedStructs.find( structure.first ) == listedStructs.end() );
9879
9880 std::string str;
9881 for ( auto const & member : structure.second.members )
9882 {
9883 auto structIt = m_structures.find( member.type.type );
9884 if ( ( structIt != m_structures.end() ) && ( structure.first != member.type.type ) && ( listedStructs.find( member.type.type ) == listedStructs.end() ) )
9885 {
9886 str += generateStructHashStructure( *structIt, listedStructs );
9887 }
9888 }
9889
9890 if ( !containsUnion( structure.first ) )
9891 {
9892 static const std::string hashTemplate = R"(
9893 ${enter}template <> struct hash<VULKAN_HPP_NAMESPACE::${structureType}>
9894 {
9895 std::size_t operator()(VULKAN_HPP_NAMESPACE::${structureType} const & ${structureName}) const VULKAN_HPP_NOEXCEPT
9896 {
9897 std::size_t seed = 0;
9898 ${hashSum}
9899 return seed;
9900 }
9901 };
9902 ${leave})";
9903
9904 auto [enter, leave] =
9905 generateProtection( m_structureAliasesInverse.find( structure.first ) == m_structureAliasesInverse.end() ? getProtectFromType( structure.first ) : "" );
9906
9907 std::string structureType = stripPrefix( structure.first, "Vk" );
9908 std::string structureName = startLowerCase( structureType );
9909 str += replaceWithMap( hashTemplate,
9910 { { "enter", enter },
9911 { "hashSum", generateStructHashSum( structureName, structure.second.members ) },
9912 { "leave", leave },
9913 { "structureName", structureName },
9914 { "structureType", structureType } } );
9915 }
9916
9917 listedStructs.insert( structure.first );
9918 return str;
9919 }
9920
generateStructHashStructures() const9921 std::string VulkanHppGenerator::generateStructHashStructures() const
9922 {
9923 const std::string hashesTemplate = R"(
9924 #if 14 <= VULKAN_HPP_CPP_VERSION
9925 //======================================
9926 //=== HASH structures for structures ===
9927 //======================================
9928
9929 # if !defined( VULKAN_HPP_HASH_COMBINE )
9930 # define VULKAN_HPP_HASH_COMBINE( seed, value ) \
9931 seed ^= std::hash<std::decay<decltype( value )>::type>{}( value ) + 0x9e3779b9 + ( seed << 6 ) + ( seed >> 2 )
9932 # endif
9933
9934 ${hashes}
9935 #endif // 14 <= VULKAN_HPP_CPP_VERSION
9936 )";
9937
9938 // Note reordering structs or handles by features and extensions is not possible!
9939 std::set<std::string> listedStructs;
9940 std::string hashes;
9941 for ( auto const & structure : m_structures )
9942 {
9943 if ( listedStructs.find( structure.first ) == listedStructs.end() )
9944 {
9945 hashes += generateStructHashStructure( structure, listedStructs );
9946 }
9947 }
9948 return replaceWithMap( hashesTemplate, { { "hashes", hashes } } );
9949 }
9950
generateStructHashSum(std::string const & structName,std::vector<MemberData> const & members) const9951 std::string VulkanHppGenerator::generateStructHashSum( std::string const & structName, std::vector<MemberData> const & members ) const
9952 {
9953 std::string hashSum;
9954 for ( auto const & member : members )
9955 {
9956 if ( !member.arraySizes.empty() )
9957 {
9958 assert( member.arraySizes.size() < 3 );
9959 hashSum += " for ( size_t i = 0; i < " + member.arraySizes[0] + "; ++i )\n";
9960 hashSum += " {\n";
9961 if ( member.arraySizes.size() == 1 )
9962 {
9963 hashSum += " VULKAN_HPP_HASH_COMBINE( seed, " + structName + "." + member.name + "[i] );\n";
9964 }
9965 else
9966 {
9967 hashSum += " for ( size_t j=0; j < " + member.arraySizes[1] + "; ++j )\n";
9968 hashSum += " {\n";
9969 hashSum += " VULKAN_HPP_HASH_COMBINE( seed, " + structName + "." + member.name + "[i][j] );\n";
9970 hashSum += " }\n";
9971 }
9972 hashSum += " }\n";
9973 }
9974 else if ( member.type.type == "char" && !member.len.empty() )
9975 {
9976 assert( member.len.size() < 3 );
9977 if ( member.len.size() == 1 )
9978 {
9979 assert( member.len[0] == "null-terminated" );
9980 hashSum += " for ( const char* p = " + structName + "." + member.name + "; *p != '\\0'; ++p )\n";
9981 hashSum += " {\n";
9982 hashSum += " VULKAN_HPP_HASH_COMBINE( seed, *p );\n";
9983 hashSum += " }\n";
9984 }
9985 else
9986 {
9987 assert( member.len[1] == "null-terminated" );
9988 hashSum += " for ( size_t i = 0; i < " + structName + "." + member.len[0] + "; ++i )\n";
9989 hashSum += " {\n";
9990 hashSum += " for ( const char* p = " + structName + "." + member.name + "[i]; *p != '\\0'; ++p )\n";
9991 hashSum += " {\n";
9992 hashSum += " VULKAN_HPP_HASH_COMBINE( seed, *p );\n";
9993 hashSum += " }\n";
9994 hashSum += " }\n";
9995 }
9996 }
9997 else
9998 {
9999 hashSum += " VULKAN_HPP_HASH_COMBINE( seed, " + structName + "." + member.name + " );\n";
10000 }
10001 }
10002 assert( !hashSum.empty() );
10003 return hashSum.substr( 0, hashSum.size() - 1 );
10004 }
10005
generateStructs() const10006 std::string VulkanHppGenerator::generateStructs() const
10007 {
10008 const std::string structsTemplate = R"(
10009 //===============
10010 //=== STRUCTS ===
10011 //===============
10012
10013 ${structs}
10014 )";
10015
10016 // Note reordering structs or handles by features and extensions is not possible!
10017 std::set<std::string> listedStructs;
10018 std::string structs;
10019 for ( auto const & structure : m_structures )
10020 {
10021 if ( listedStructs.find( structure.first ) == listedStructs.end() )
10022 {
10023 structs += generateStruct( structure, listedStructs );
10024 }
10025 }
10026 return replaceWithMap( structsTemplate, { { "structs", structs } } );
10027 }
10028
generateStructure(std::pair<std::string,StructureData> const & structure) const10029 std::string VulkanHppGenerator::generateStructure( std::pair<std::string, StructureData> const & structure ) const
10030 {
10031 auto [enter, leave] =
10032 generateProtection( m_structureAliasesInverse.find( structure.first ) == m_structureAliasesInverse.end() ? getProtectFromType( structure.first ) : "" );
10033
10034 std::string str = "\n" + enter;
10035
10036 static const std::string constructorsTemplate = R"(
10037 #if !defined( VULKAN_HPP_NO_STRUCT_CONSTRUCTORS )
10038 ${constructors}
10039 ${subConstructors}
10040 ${structName} & operator=( ${structName} const & rhs ) VULKAN_HPP_NOEXCEPT = default;
10041 #endif /*VULKAN_HPP_NO_STRUCT_CONSTRUCTORS*/
10042
10043 ${structName} & operator=( Vk${structName} const & rhs ) VULKAN_HPP_NOEXCEPT
10044 {
10045 *this = *reinterpret_cast<VULKAN_HPP_NAMESPACE::${structName} const *>( &rhs );
10046 return *this;
10047 }
10048 )";
10049
10050 std::string constructorsAndSetters = replaceWithMap( constructorsTemplate,
10051 { { "constructors", generateStructConstructors( structure ) },
10052 { "structName", stripPrefix( structure.first, "Vk" ) },
10053 { "subConstructors", generateStructSubConstructor( structure ) } } );
10054
10055 if ( !structure.second.returnedOnly )
10056 {
10057 // only structs that are not returnedOnly get setters!
10058 constructorsAndSetters += "\n#if !defined( VULKAN_HPP_NO_STRUCT_SETTERS )";
10059 for ( size_t i = 0; i < structure.second.members.size(); i++ )
10060 {
10061 constructorsAndSetters += generateStructSetter( stripPrefix( structure.first, "Vk" ), structure.second.members, i );
10062 }
10063 constructorsAndSetters += "#endif /*VULKAN_HPP_NO_STRUCT_SETTERS*/\n";
10064 }
10065
10066 std::string structureType = stripPrefix( structure.first, "Vk" );
10067 // the member variables
10068 std::string members, memberNames, memberTypes, sTypeValue;
10069 std::tie( members, memberNames, memberTypes, sTypeValue ) = generateStructMembers( structure );
10070
10071 // reflect is meaningfull for structs only, filter out unions
10072 std::string reflect;
10073 if ( !structure.second.isUnion )
10074 {
10075 // use reflection only if VULKAN_HPP_USE_REFLECT is defined
10076 static const std::string reflectTemplate = R"(
10077 #if defined( VULKAN_HPP_USE_REFLECT )
10078 #if 14 <= VULKAN_HPP_CPP_VERSION
10079 auto
10080 #else
10081 std::tuple<${memberTypes}>
10082 #endif
10083 reflect() const VULKAN_HPP_NOEXCEPT
10084 {
10085 return std::tie( ${memberNames} );
10086 }
10087 #endif
10088 )";
10089
10090 reflect = replaceWithMap( reflectTemplate, { { "memberNames", memberNames }, { "memberTypes", memberTypes } } );
10091 }
10092
10093 // operator==() and operator!=()
10094 // only structs without a union as a member can have a meaningfull == and != operation; we filter them out
10095 std::string compareOperators;
10096 if ( !containsUnion( structure.first ) )
10097 {
10098 compareOperators += generateStructCompareOperators( structure );
10099 }
10100
10101 static const std::string structureTemplate = R"( struct ${structureType}
10102 {
10103 using NativeType = Vk${structureType};
10104
10105 ${allowDuplicate}
10106 ${typeValue}
10107 ${constructorsAndSetters}
10108
10109 operator Vk${structureType} const &() const VULKAN_HPP_NOEXCEPT
10110 {
10111 return *reinterpret_cast<const Vk${structureType}*>( this );
10112 }
10113
10114 operator Vk${structureType} &() VULKAN_HPP_NOEXCEPT
10115 {
10116 return *reinterpret_cast<Vk${structureType}*>( this );
10117 }
10118 ${reflect}
10119 ${compareOperators}
10120 public:
10121 ${members}
10122 };
10123 )";
10124
10125 std::string allowDuplicate, typeValue;
10126 if ( !sTypeValue.empty() )
10127 {
10128 allowDuplicate = std::string( " static const bool allowDuplicate = " ) + ( structure.second.allowDuplicate ? "true;" : "false;" );
10129 typeValue = " static VULKAN_HPP_CONST_OR_CONSTEXPR StructureType structureType = StructureType::" + sTypeValue + ";\n";
10130 }
10131 str += replaceWithMap( structureTemplate,
10132 { { "allowDuplicate", allowDuplicate },
10133 { "constructorsAndSetters", constructorsAndSetters },
10134 { "compareOperators", compareOperators },
10135 { "members", members },
10136 { "reflect", reflect },
10137 { "structureType", structureType },
10138 { "typeValue", typeValue } } );
10139
10140 if ( !sTypeValue.empty() )
10141 {
10142 std::string cppTypeTemplate = R"(
10143 template <>
10144 struct CppType<StructureType, StructureType::${sTypeValue}>
10145 {
10146 using Type = ${structureType};
10147 };
10148 )";
10149 str += replaceWithMap( cppTypeTemplate, { { "sTypeValue", sTypeValue }, { "structureType", structureType } } );
10150 }
10151
10152 auto aliasIt = m_structureAliasesInverse.find( structure.first );
10153 if ( aliasIt != m_structureAliasesInverse.end() )
10154 {
10155 for ( std::string const & alias : aliasIt->second )
10156 {
10157 str += " using " + stripPrefix( alias, "Vk" ) + " = " + structureType + ";\n";
10158 }
10159 }
10160
10161 str += leave;
10162 return str;
10163 }
10164
generateStructExtendsStructs() const10165 std::string VulkanHppGenerator::generateStructExtendsStructs() const
10166 {
10167 const std::string structExtendsTemplate = R"(
10168 //=======================
10169 //=== STRUCTS EXTENDS ===
10170 //=======================
10171
10172 ${structExtends})";
10173
10174 std::string structExtends;
10175 std::set<std::string> listedStructs;
10176 for ( auto const & feature : m_features )
10177 {
10178 structExtends += generateStructExtendsStructs( feature.second.requireData, listedStructs, feature.first );
10179 }
10180 for ( auto const & extIt : m_extensionsByNumber )
10181 {
10182 structExtends += generateStructExtendsStructs( extIt.second->second.requireData, listedStructs, extIt.second->first );
10183 }
10184
10185 return replaceWithMap( structExtendsTemplate, { { "structExtends", structExtends } } );
10186 }
10187
generateStructExtendsStructs(std::vector<RequireData> const & requireData,std::set<std::string> & listedStructs,std::string const & title) const10188 std::string VulkanHppGenerator::generateStructExtendsStructs( std::vector<RequireData> const & requireData,
10189 std::set<std::string> & listedStructs,
10190 std::string const & title ) const
10191 {
10192 std::string str;
10193 for ( auto const & require : requireData )
10194 {
10195 for ( auto const & type : require.types )
10196 {
10197 auto structIt = m_structures.find( type );
10198 if ( structIt != m_structures.end() )
10199 {
10200 assert( listedStructs.find( type ) == listedStructs.end() );
10201 listedStructs.insert( type );
10202
10203 auto [enter, leave] = generateProtection( getProtectFromTitle( title ) );
10204
10205 // append all allowed structure chains
10206 for ( auto extendName : structIt->second.structExtends )
10207 {
10208 std::map<std::string, StructureData>::const_iterator itExtend = m_structures.find( extendName );
10209 if ( itExtend == m_structures.end() )
10210 {
10211 // look if the extendName acutally is an alias of some other structure
10212 auto aliasIt = m_structureAliases.find( extendName );
10213 if ( aliasIt != m_structureAliases.end() )
10214 {
10215 itExtend = m_structures.find( aliasIt->second.alias );
10216 assert( itExtend != m_structures.end() );
10217 }
10218 }
10219
10220 auto [subEnter, subLeave] = generateProtection(
10221 m_structureAliasesInverse.find( itExtend->first ) == m_structureAliasesInverse.end() ? getProtectFromType( itExtend->first ) : "" );
10222
10223 if ( enter != subEnter )
10224 {
10225 str += subEnter;
10226 }
10227
10228 str += " template <> struct StructExtends<" + stripPrefix( structIt->first, "Vk" ) + ", " + stripPrefix( extendName, "Vk" ) +
10229 ">{ enum { value = true }; };\n";
10230
10231 if ( leave != subLeave )
10232 {
10233 str += subLeave;
10234 }
10235 }
10236 }
10237 }
10238 }
10239 return addTitleAndProtection( title, str );
10240 }
10241
generateStructForwardDeclarations() const10242 std::string VulkanHppGenerator::generateStructForwardDeclarations() const
10243 {
10244 const std::string fowardDeclarationsTemplate = R"(
10245 //===================================
10246 //=== STRUCT forward declarations ===
10247 //===================================
10248
10249 ${forwardDeclarations}
10250 )";
10251
10252 std::string forwardDeclarations;
10253 for ( auto const & feature : m_features )
10254 {
10255 forwardDeclarations += generateStructForwardDeclarations( feature.second.requireData, feature.first );
10256 }
10257 for ( auto const & extIt : m_extensionsByNumber )
10258 {
10259 forwardDeclarations += generateStructForwardDeclarations( extIt.second->second.requireData, extIt.second->first );
10260 }
10261
10262 return replaceWithMap( fowardDeclarationsTemplate, { { "forwardDeclarations", forwardDeclarations } } );
10263 }
10264
generateStructForwardDeclarations(std::vector<RequireData> const & requireData,std::string const & title) const10265 std::string VulkanHppGenerator::generateStructForwardDeclarations( std::vector<RequireData> const & requireData, std::string const & title ) const
10266 {
10267 std::string str;
10268 for ( auto const & require : requireData )
10269 {
10270 for ( auto const & type : require.types )
10271 {
10272 auto structIt = m_structures.find( type );
10273 if ( structIt != m_structures.end() )
10274 {
10275 std::string structureType = stripPrefix( structIt->first, "Vk" );
10276 str += ( structIt->second.isUnion ? " union " : " struct " ) + structureType + ";\n";
10277 auto inverseIt = m_structureAliasesInverse.find( type );
10278 if ( inverseIt != m_structureAliasesInverse.end() )
10279 {
10280 for ( auto alias : inverseIt->second )
10281 {
10282 str += " using " + stripPrefix( alias, "Vk" ) + " = " + structureType + ";\n";
10283 }
10284 }
10285 }
10286 }
10287 }
10288 return addTitleAndProtection( title, str );
10289 }
10290
10291 std::tuple<std::string, std::string, std::string, std::string>
generateStructMembers(std::pair<std::string,StructureData> const & structData) const10292 VulkanHppGenerator::generateStructMembers( std::pair<std::string, StructureData> const & structData ) const
10293 {
10294 std::string members, memberNames, memberTypes, sTypeValue;
10295 for ( auto const & member : structData.second.members )
10296 {
10297 members += " ";
10298 std::string type;
10299 if ( !member.bitCount.empty() && member.type.type.starts_with( "Vk" ) )
10300 {
10301 assert( member.type.prefix.empty() && member.type.postfix.empty() ); // never encounterd a different case
10302 type = member.type.type;
10303 }
10304 else if ( member.arraySizes.empty() )
10305 {
10306 type = member.type.compose( "VULKAN_HPP_NAMESPACE" );
10307 }
10308 else
10309 {
10310 assert( member.type.prefix.empty() && member.type.postfix.empty() );
10311 type = generateStandardArrayWrapper( member.type.compose( "VULKAN_HPP_NAMESPACE" ), member.arraySizes );
10312 }
10313 members += type + " " + member.name;
10314 if ( !member.value.empty() )
10315 {
10316 // special handling for members with legal value: use it as the default
10317 members += " = ";
10318 if ( member.type.type == "uint32_t" )
10319 {
10320 members += member.value;
10321 }
10322 else
10323 {
10324 auto enumIt = m_enums.find( member.type.type );
10325 assert( enumIt != m_enums.end() );
10326 std::string enumValue = member.value;
10327 auto valueIt = std::find_if(
10328 enumIt->second.values.begin(), enumIt->second.values.end(), [&enumValue]( EnumValueData const & evd ) { return enumValue == evd.name; } );
10329 assert( valueIt != enumIt->second.values.end() );
10330 std::string valueName = generateEnumValueName( enumIt->first, valueIt->name, enumIt->second.isBitmask, m_tags );
10331 members += stripPrefix( member.type.type, "Vk" ) + "::" + valueName;
10332 if ( member.name == "sType" )
10333 {
10334 sTypeValue = valueName;
10335 }
10336 }
10337 }
10338 else
10339 {
10340 // as we don't have any meaningful default initialization values, everything can be initialized by just '{}'
10341 // !
10342 assert( member.arraySizes.empty() || member.bitCount.empty() );
10343 if ( !member.bitCount.empty() )
10344 {
10345 members += " : " + member.bitCount; // except for bitfield members, where no default member initializatin
10346 // is supported (up to C++20)
10347 }
10348 else
10349 {
10350 members += " = ";
10351 auto enumIt = m_enums.find( member.type.type );
10352 if ( member.arraySizes.empty() && ( enumIt != m_enums.end() ) && member.type.postfix.empty() )
10353 {
10354 members += generateEnumInitializer( member.type, member.arraySizes, enumIt->second.values, enumIt->second.isBitmask );
10355 }
10356 else
10357 {
10358 members += "{}";
10359 }
10360 }
10361 }
10362 members += ";\n";
10363
10364 memberNames += member.name + ", ";
10365 memberTypes += type + " const &, ";
10366 }
10367 return std::make_tuple( members, stripPostfix( memberNames, ", " ), stripPostfix( memberTypes, ", " ), sTypeValue );
10368 }
10369
generateStructSetter(std::string const & structureName,std::vector<MemberData> const & memberData,size_t index) const10370 std::string VulkanHppGenerator::generateStructSetter( std::string const & structureName, std::vector<MemberData> const & memberData, size_t index ) const
10371 {
10372 std::string str;
10373 MemberData const & member = memberData[index];
10374 if ( member.type.type != "VkStructureType" ) // filter out StructureType, which is supposed to be immutable !
10375 {
10376 static const std::string templateString = R"(
10377 ${constexpr}${structureName} & set${MemberName}( ${memberType} ${reference}${memberName}_ ) VULKAN_HPP_NOEXCEPT
10378 {
10379 ${assignment};
10380 return *this;
10381 }
10382 )";
10383
10384 std::string memberType = member.arraySizes.empty() ? member.type.compose( "VULKAN_HPP_NAMESPACE" )
10385 : generateStandardArray( member.type.compose( "VULKAN_HPP_NAMESPACE" ), member.arraySizes );
10386 bool isReinterpretation = !member.bitCount.empty() && member.type.type.starts_with( "Vk" );
10387 std::string assignment;
10388 if ( isReinterpretation )
10389 {
10390 assignment = member.name + " = " + "*reinterpret_cast<" + member.type.type + "*>(&" + member.name + "_)";
10391 }
10392 else
10393 {
10394 assignment = member.name + " = " + member.name + "_";
10395 }
10396
10397 str +=
10398 replaceWithMap( templateString,
10399 { { "assignment", assignment },
10400 { "constexpr", isReinterpretation ? "" : "VULKAN_HPP_CONSTEXPR_14 " },
10401 { "memberName", member.name },
10402 { "MemberName", startUpperCase( member.name ) },
10403 { "memberType", memberType },
10404 { "reference", ( member.type.postfix.empty() && ( m_structures.find( member.type.type ) != m_structures.end() ) ) ? "const & " : "" },
10405 { "structureName", structureName } } );
10406
10407 if ( hasLen( memberData, member ) )
10408 {
10409 assert( member.name.front() == 'p' );
10410 std::string arrayName = startLowerCase( stripPrefix( member.name, "p" ) );
10411
10412 std::string lenName, lenValue;
10413 if ( member.len[0] == "codeSize / 4" )
10414 {
10415 lenName = "codeSize";
10416 lenValue = arrayName + "_.size() * 4";
10417 }
10418 else
10419 {
10420 lenName = member.len[0];
10421 lenValue = arrayName + "_.size()";
10422 }
10423
10424 assert( memberType.back() == '*' );
10425 memberType = trimEnd( stripPostfix( memberType, "*" ) );
10426
10427 std::string templateHeader;
10428 if ( ( member.type.type == "void" ) && ( memberType.find( '*' ) == std::string::npos ) )
10429 {
10430 assert( templateHeader.empty() );
10431 templateHeader = "template <typename T>\n ";
10432
10433 size_t pos = memberType.find( "void" );
10434 assert( pos != std::string::npos );
10435 memberType.replace( pos, strlen( "void" ), "T" );
10436
10437 lenValue += " * sizeof(T)";
10438 }
10439
10440 auto lenMember = findStructMemberIt( lenName, memberData );
10441 assert( lenMember != memberData.end() && lenMember->type.prefix.empty() && lenMember->type.postfix.empty() );
10442 if ( lenMember->type.type != "size_t" )
10443 {
10444 lenValue = "static_cast<" + lenMember->type.type + ">( " + lenValue + " )";
10445 }
10446
10447 static const std::string setArrayTemplate = R"(
10448 #if !defined( VULKAN_HPP_DISABLE_ENHANCED_MODE )
10449 ${templateHeader}${structureName} & set${ArrayName}( VULKAN_HPP_NAMESPACE::ArrayProxyNoTemporaries<${memberType}> const & ${arrayName}_ ) VULKAN_HPP_NOEXCEPT
10450 {
10451 ${lenName} = ${lenValue};
10452 ${memberName} = ${arrayName}_.data();
10453 return *this;
10454 }
10455 #endif /*VULKAN_HPP_DISABLE_ENHANCED_MODE*/
10456 )";
10457
10458 str += replaceWithMap( setArrayTemplate,
10459 { { "arrayName", arrayName },
10460 { "ArrayName", startUpperCase( arrayName ) },
10461 { "lenName", lenName },
10462 { "lenValue", lenValue },
10463 { "memberName", member.name },
10464 { "memberType", memberType },
10465 { "structureName", structureName },
10466 { "templateHeader", templateHeader } } );
10467 }
10468 }
10469 return str;
10470 }
10471
generateStructSubConstructor(std::pair<std::string,StructureData> const & structData) const10472 std::string VulkanHppGenerator::generateStructSubConstructor( std::pair<std::string, StructureData> const & structData ) const
10473 {
10474 if ( !structData.second.subStruct.empty() )
10475 {
10476 auto const & subStruct = m_structures.find( structData.second.subStruct );
10477 assert( subStruct != m_structures.end() );
10478
10479 std::string subStructArgumentName = startLowerCase( stripPrefix( subStruct->first, "Vk" ) );
10480
10481 std::string subCopies;
10482 bool firstArgument = true;
10483 for ( size_t i = 0; i < subStruct->second.members.size(); i++ )
10484 {
10485 assert( structData.second.members[i].arraySizes.empty() );
10486 static const std::string subCopiesTemplate =
10487 R"( ${separator} ${structMemberName}( ${subStructArgumentName}.${subStructMemberName} )
10488 )";
10489 subCopies += replaceWithMap( subCopiesTemplate,
10490 { { "separator", firstArgument ? ":" : "," },
10491 { "structMemberName", structData.second.members[i].name },
10492 { "subStructMemberName", subStruct->second.members[i].name },
10493 { "subStructArgumentName", subStructArgumentName } } );
10494 firstArgument = false;
10495 }
10496
10497 std::string subArguments;
10498 bool listedArgument = true;
10499 for ( size_t i = subStruct->second.members.size(); i < structData.second.members.size(); i++ )
10500 {
10501 std::string argument = generateStructConstructorArgument( listedArgument, structData.second.members[i], true );
10502 if ( !argument.empty() )
10503 {
10504 listedArgument = true;
10505 subArguments += argument;
10506 }
10507
10508 assert( structData.second.members[i].arraySizes.empty() );
10509 static const std::string subCopiesTemplate = R"( , ${memberName}( ${memberName}_ )
10510 )";
10511 subCopies += replaceWithMap( subCopiesTemplate, { { "memberName", structData.second.members[i].name } } );
10512 }
10513
10514 static const std::string subStructConstructorTemplate = R"(
10515 explicit ${structName}( ${subStructName} const & ${subStructArgumentName}${subArguments} )
10516 ${subCopies} {}
10517 )";
10518 return replaceWithMap( subStructConstructorTemplate,
10519 { { "structName", stripPrefix( structData.first, "Vk" ) },
10520 { "subArguments", subArguments },
10521 { "subCopies", subCopies },
10522 { "subStructArgumentName", subStructArgumentName },
10523 { "subStructName", stripPrefix( subStruct->first, "Vk" ) } } );
10524 }
10525 return "";
10526 }
10527
generateSuccessCheck(std::vector<std::string> const & successCodes) const10528 std::string VulkanHppGenerator::generateSuccessCheck( std::vector<std::string> const & successCodes ) const
10529 {
10530 assert( !successCodes.empty() );
10531 std::string successCheck = "result == " + generateSuccessCode( successCodes[0], m_tags );
10532 if ( 1 < successCodes.size() )
10533 {
10534 successCheck = "( " + successCheck + " )";
10535 for ( size_t i = 1; i < successCodes.size(); ++i )
10536 {
10537 successCheck += "|| ( result == " + generateSuccessCode( successCodes[i], m_tags ) + " )";
10538 }
10539 }
10540 return successCheck;
10541 }
10542
generateSuccessCodeList(std::vector<std::string> const & successCodes,bool enumerating) const10543 std::string VulkanHppGenerator::generateSuccessCodeList( std::vector<std::string> const & successCodes, bool enumerating ) const
10544 {
10545 std::string successCodeList;
10546 if ( ( 1 < successCodes.size() ) && !enumerating )
10547 {
10548 successCodeList = ", { " + generateSuccessCode( successCodes[0], m_tags );
10549 for ( size_t i = 1; i < successCodes.size(); ++i )
10550 {
10551 successCodeList += ", " + generateSuccessCode( successCodes[i], m_tags );
10552 }
10553 successCodeList += " }";
10554 }
10555 return successCodeList;
10556 }
10557
generateThrowResultException() const10558 std::string VulkanHppGenerator::generateThrowResultException() const
10559 {
10560 auto enumIt = m_enums.find( "VkResult" );
10561
10562 std::string cases;
10563 for ( auto const & value : enumIt->second.values )
10564 {
10565 if ( value.name.starts_with( "VK_ERROR" ) )
10566 {
10567 auto [enter, leave] = generateProtection( getProtect( value ) );
10568 std::string valueName = generateEnumValueName( enumIt->first, value.name, false, m_tags );
10569 cases += enter + " case Result::" + valueName + ": throw " + stripPrefix( valueName, "eError" ) + "Error( message );\n" + leave;
10570 }
10571 }
10572 cases.pop_back(); // remove last newline
10573
10574 const std::string throwTemplate = R"(
10575 namespace
10576 {
10577 [[noreturn]] void throwResultException( Result result, char const * message )
10578 {
10579 switch ( result )
10580 {
10581 ${cases}
10582 default: throw SystemError( make_error_code( result ) );
10583 }
10584 }
10585 })";
10586 return replaceWithMap( throwTemplate, { { "cases", cases } } );
10587 }
10588
generateTypenameCheck(std::vector<size_t> const & returnParams,std::map<size_t,VectorParamData> const & vectorParams,bool definition,std::vector<std::string> const & dataTypes,CommandFlavourFlags flavourFlags) const10589 std::string VulkanHppGenerator::generateTypenameCheck( std::vector<size_t> const & returnParams,
10590 std::map<size_t, VectorParamData> const & vectorParams,
10591 bool definition,
10592 std::vector<std::string> const & dataTypes,
10593 CommandFlavourFlags flavourFlags ) const
10594 {
10595 std::string typenameCheck, enableIf;
10596 if ( !( flavourFlags & CommandFlavourFlagBits::singular ) && ( flavourFlags & CommandFlavourFlagBits::withAllocator ) )
10597 {
10598 for ( size_t i = 0; i < returnParams.size(); ++i )
10599 {
10600 if ( vectorParams.find( returnParams[i] ) != vectorParams.end() )
10601 {
10602 std::string elementType = ( flavourFlags & CommandFlavourFlagBits::chained ) ? "StructureChain" : stripPrefix( dataTypes[i], "VULKAN_HPP_NAMESPACE::" );
10603 std::string extendedElementType = elementType;
10604 if ( flavourFlags & CommandFlavourFlagBits::unique )
10605 {
10606 extendedElementType = "UniqueHandle<" + elementType + ", Dispatch>";
10607 }
10608 std::string index = std::to_string( i );
10609 if ( definition )
10610 {
10611 typenameCheck += ", typename B" + index;
10612 }
10613 else
10614 {
10615 typenameCheck += ", typename B" + index + " = " + startUpperCase( elementType ) + "Allocator";
10616 }
10617 enableIf += enableIf.empty() ? ", typename std::enable_if<" : " && ";
10618 enableIf += "std::is_same<typename B" + index + "::value_type, " + extendedElementType + ">::value";
10619 }
10620 }
10621 assert( !typenameCheck.empty() );
10622 if ( !typenameCheck.empty() )
10623 {
10624 typenameCheck += enableIf + ", int>::type";
10625 if ( !definition )
10626 {
10627 typenameCheck += " = 0";
10628 }
10629 }
10630 }
10631 return typenameCheck;
10632 }
10633
generateUnion(std::pair<std::string,StructureData> const & structure) const10634 std::string VulkanHppGenerator::generateUnion( std::pair<std::string, StructureData> const & structure ) const
10635 {
10636 auto [enter, leave] =
10637 generateProtection( m_structureAliasesInverse.find( structure.first ) == m_structureAliasesInverse.end() ? getProtectFromType( structure.first ) : "" );
10638 std::string unionName = stripPrefix( structure.first, "Vk" );
10639
10640 bool firstMember = true;
10641 std::set<TypeInfo> listedTypes; // create just one constructor per different type !
10642 std::string constructors;
10643 for ( auto memberIt = structure.second.members.begin(); memberIt != structure.second.members.end(); ++memberIt )
10644 {
10645 if ( listedTypes.insert( memberIt->type ).second )
10646 {
10647 // VkBool32 is aliased to uint32_t. Don't create a VkBool32 constructor if the union also contains a
10648 // uint32_t constructor.
10649 if ( memberIt->type.type == "VkBool32" )
10650 {
10651 if ( findStructMemberItByType( "uint32_t", structure.second.members ) != structure.second.members.end() )
10652 {
10653 continue;
10654 }
10655 }
10656
10657 bool multipleType =
10658 ( std::find_if( std::next( memberIt ),
10659 structure.second.members.end(),
10660 [memberIt]( MemberData const & member ) { return member.type == memberIt->type; } ) != structure.second.members.end() );
10661 std::string memberType = ( memberIt->arraySizes.empty() )
10662 ? memberIt->type.compose( "VULKAN_HPP_NAMESPACE" )
10663 : ( "const " + generateStandardArray( memberIt->type.compose( "VULKAN_HPP_NAMESPACE" ), memberIt->arraySizes ) + "&" );
10664
10665 // In a majority of cases this can be constexpr in C++11 as well, however, determining when exactly
10666 // that is the case is a lot more involved and probably not worth it.
10667 static const std::string constructorTemplate = R"(
10668 VULKAN_HPP_CONSTEXPR_14 ${unionName}( ${memberType} ${argumentName}_${defaultAssignment} )
10669 : ${memberName}( ${argumentName}_ )
10670 {})";
10671
10672 constructors += ( firstMember ? "" : "\n" ) + replaceWithMap( constructorTemplate,
10673 { { "argumentName", multipleType ? generateName( memberIt->type ) : memberIt->name },
10674 { "defaultAssignment", firstMember ? " = {}" : "" },
10675 { "memberName", memberIt->name },
10676 { "memberType", memberType },
10677 { "unionName", stripPrefix( structure.first, "Vk" ) } } );
10678 firstMember = false;
10679
10680 if ( !memberIt->arraySizes.empty() )
10681 {
10682 assert( !multipleType );
10683 assert( memberIt->arraySizes.size() == 1 );
10684 int size = std::stoi( memberIt->arraySizes[0] );
10685 assert( std::to_string( size ) == memberIt->arraySizes[0] );
10686 std::string arguments, callArguments;
10687 bool firstArgument = true;
10688 for ( int i = 0; i < size; i++ )
10689 {
10690 if ( !firstArgument )
10691 {
10692 arguments += ", ";
10693 callArguments += ", ";
10694 }
10695 std::string argumentIndex = std::to_string( i );
10696 arguments += memberIt->type.type + " " + memberIt->name + "_" + argumentIndex;
10697 callArguments += memberIt->name + "_" + argumentIndex;
10698 firstArgument = false;
10699 }
10700
10701 static const std::string constructorBySequenceTemplate = R"(
10702 VULKAN_HPP_CONSTEXPR ${unionName}( ${arguments} )
10703 : ${memberName}{ { { ${callArguments} } } }
10704 {})";
10705
10706 constructors += "\n" + replaceWithMap( constructorBySequenceTemplate,
10707 { { "arguments", arguments },
10708 { "callArguments", callArguments },
10709 { "memberName", memberIt->name },
10710 { "unionName", stripPrefix( structure.first, "Vk" ) } } );
10711 }
10712 }
10713 }
10714
10715 // one setter per union element
10716 std::string setters;
10717 for ( size_t i = 0; i < structure.second.members.size(); i++ )
10718 {
10719 setters += generateStructSetter( stripPrefix( structure.first, "Vk" ), structure.second.members, i );
10720 }
10721 // filter out leading and trailing newline
10722 setters = setters.substr( 1, setters.length() - 2 );
10723
10724 // the union member variables
10725 std::string members;
10726 // if there's at least one Vk... type in this union, check for unrestricted unions support
10727 bool needsUnrestrictedUnions =
10728 ( std::find_if( structure.second.members.begin(),
10729 structure.second.members.end(),
10730 []( MemberData const & member ) { return member.type.type.starts_with( "Vk" ); } ) != structure.second.members.end() );
10731 if ( needsUnrestrictedUnions )
10732 {
10733 members += "#ifdef VULKAN_HPP_HAS_UNRESTRICTED_UNIONS\n";
10734 }
10735 for ( auto const & member : structure.second.members )
10736 {
10737 static const std::string memberTemplate = R"( ${memberType} ${memberName};
10738 )";
10739 members +=
10740 replaceWithMap( memberTemplate,
10741 { { "memberName", member.name },
10742 { "memberType",
10743 member.arraySizes.empty() ? member.type.compose( "VULKAN_HPP_NAMESPACE" )
10744 : generateStandardArrayWrapper( member.type.compose( "VULKAN_HPP_NAMESPACE" ), member.arraySizes ) } } );
10745 }
10746 if ( needsUnrestrictedUnions )
10747 {
10748 members += "#else\n";
10749 for ( auto const & member : structure.second.members )
10750 {
10751 static const std::string memberTemplate = R"( ${memberType} ${memberName}${arraySizes};
10752 )";
10753 members += replaceWithMap(
10754 memberTemplate,
10755 { { "arraySizes", generateCArraySizes( member.arraySizes ) }, { "memberName", member.name }, { "memberType", member.type.compose( "" ) } } );
10756 }
10757 members += "#endif /*VULKAN_HPP_HAS_UNRESTRICTED_UNIONS*/\n";
10758 }
10759
10760 static const std::string unionTemplate = R"(
10761 ${enter} union ${unionName}
10762 {
10763 using NativeType = Vk${unionName};
10764 #if !defined( VULKAN_HPP_NO_UNION_CONSTRUCTORS )
10765 ${constructors}
10766 #endif /*VULKAN_HPP_NO_UNION_CONSTRUCTORS*/
10767
10768 #if !defined( VULKAN_HPP_NO_UNION_SETTERS )
10769 ${setters}
10770 #endif /*VULKAN_HPP_NO_UNION_SETTERS*/
10771
10772 operator Vk${unionName} const &() const
10773 {
10774 return *reinterpret_cast<const Vk${unionName}*>( this );
10775 }
10776
10777 operator Vk${unionName} &()
10778 {
10779 return *reinterpret_cast<Vk${unionName}*>( this );
10780 }
10781
10782 ${members}
10783 };
10784 ${leave})";
10785
10786 return replaceWithMap(
10787 unionTemplate,
10788 { { "constructors", constructors }, { "enter", enter }, { "leave", leave }, { "members", members }, { "setters", setters }, { "unionName", unionName } } );
10789 }
10790
generateUniqueTypes(std::string const & parentType,std::set<std::string> const & childrenTypes) const10791 std::string VulkanHppGenerator::generateUniqueTypes( std::string const & parentType, std::set<std::string> const & childrenTypes ) const
10792 {
10793 std::string childrenTraits;
10794 for ( auto const & childType : childrenTypes )
10795 {
10796 auto handleIt = m_handles.find( childType );
10797 assert( handleIt != m_handles.end() );
10798
10799 std::string type = stripPrefix( childType, "Vk" );
10800
10801 auto [enter, leave] = generateProtection( handleIt->second.alias.empty() ? getProtectFromType( handleIt->first ) : "" );
10802
10803 std::string aliasHandle;
10804 if ( !handleIt->second.alias.empty() )
10805 {
10806 static const std::string aliasHandleTemplate =
10807 R"( using Unique${aliasType} = UniqueHandle<${type}, VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>;
10808 )";
10809
10810 aliasHandle += replaceWithMap( aliasHandleTemplate, { { "aliasType", stripPrefix( handleIt->second.alias, "Vk" ) }, { "type", type } } );
10811 }
10812
10813 static const std::string traitsTemplate = R"(${enter} template <typename Dispatch>
10814 class UniqueHandleTraits<${type}, Dispatch>
10815 {
10816 public:
10817 using deleter = ${deleterType}${deleterAction}<${deleterParent}${deleterPool}, Dispatch>;
10818 };
10819 using Unique${type} = UniqueHandle<${type}, VULKAN_HPP_DEFAULT_DISPATCHER_TYPE>;
10820 ${aliasHandle}${leave})";
10821
10822 childrenTraits += replaceWithMap( traitsTemplate,
10823 { { "aliasHandle", aliasHandle },
10824 { "deleterAction", ( handleIt->second.deleteCommand.substr( 2, 4 ) == "Free" ) ? "Free" : "Destroy" },
10825 { "deleterParent", parentType.empty() ? "NoParent" : stripPrefix( parentType, "Vk" ) },
10826 { "deleterPool", handleIt->second.deletePool.empty() ? "" : ", " + stripPrefix( handleIt->second.deletePool, "Vk" ) },
10827 { "deleterType", handleIt->second.deletePool.empty() ? "Object" : "Pool" },
10828 { "enter", enter },
10829 { "leave", leave },
10830 { "type", type } } );
10831 }
10832
10833 static const std::string uniqueTypeTemplate = R"(
10834 #ifndef VULKAN_HPP_NO_SMART_HANDLE
10835 ${parentClass}${childrenTraits}#endif /*VULKAN_HPP_NO_SMART_HANDLE*/
10836 )";
10837
10838 return replaceWithMap(
10839 uniqueTypeTemplate,
10840 { { "childrenTraits", childrenTraits }, { "parentClass", parentType.empty() ? "" : ( " class " + stripPrefix( parentType, "Vk" ) + ";\n" ) } } );
10841 }
10842
generateVectorSizeCheck(std::string const & name,CommandData const & commandData,size_t initialSkipCount,std::map<size_t,std::vector<size_t>> const & countToVectorMap,std::set<size_t> const & skippedParams,bool onlyThrows) const10843 std::string VulkanHppGenerator::generateVectorSizeCheck( std::string const & name,
10844 CommandData const & commandData,
10845 size_t initialSkipCount,
10846 std::map<size_t, std::vector<size_t>> const & countToVectorMap,
10847 std::set<size_t> const & skippedParams,
10848 bool onlyThrows ) const
10849 {
10850 std::string const assertTemplate = " VULKAN_HPP_ASSERT( ${zeroSizeCheck}${firstVectorName}.size() == ${secondVectorName}.size() );";
10851 std::string const assertTemplateVoid =
10852 " VULKAN_HPP_ASSERT( ${zeroSizeCheck}${firstVectorName}.size() * sizeof( ${firstDataType} ) == ${secondVectorName}.size() * sizeof( ${secondDataType} ) );";
10853 std::string const assertTemplateByLen = " VULKAN_HPP_ASSERT( ${vectorName}.size() == ${sizeValue} );";
10854 std::string const throwTemplate =
10855 R"#( if ( ${zeroSizeCheck}${firstVectorName}.size() != ${secondVectorName}.size() )
10856 {
10857 throw LogicError( VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${firstVectorName}.size() != ${secondVectorName}.size()" );
10858 })#";
10859 std::string const throwTemplateVoid =
10860 R"#( if ( ${zeroSizeCheck}${firstVectorName}.size() * sizeof( ${firstDataType} ) != ${secondVectorName}.size() * sizeof( ${secondDataType} ) )
10861 {
10862 throw LogicError( VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${firstVectorName}.size() * sizeof( ${firstDataType} ) != ${secondVectorName}.size() * sizeof( ${secondDataType} )" );
10863 })#";
10864 std::string const throwTemplateByLen = R"#( if ( ${vectorName}.size() != ${sizeValue} )
10865 {
10866 throw LogicError( VULKAN_HPP_NAMESPACE_STRING "::${className}::${commandName}: ${vectorName}.size() != ${sizeValue}" );
10867 })#";
10868
10869 std::string className = stripPrefix( commandData.params[initialSkipCount - 1].type.type, "Vk" );
10870 std::string commandName = generateCommandName( name, commandData.params, initialSkipCount, m_tags );
10871
10872 std::string assertions, throws;
10873 for ( auto const & cvm : countToVectorMap )
10874 {
10875 size_t defaultStartIndex = determineDefaultStartIndex( commandData.params, skippedParams );
10876 std::string firstVectorName = startLowerCase( stripPrefix( commandData.params[cvm.second[0]].name, "p" ) );
10877
10878 if ( cvm.second.size() == 1 )
10879 {
10880 assert( isLenByStructMember( commandData.params[cvm.second[0]].len, commandData.params[cvm.first] ) );
10881
10882 std::vector<std::string> lenParts = tokenize( commandData.params[cvm.second[0]].len, "->" );
10883 assert( lenParts.size() == 2 );
10884 std::string sizeValue = startLowerCase( stripPrefix( lenParts[0], "p" ) ) + "." + lenParts[1];
10885 assertions += replaceWithMap( assertTemplateByLen, { { "sizeValue", sizeValue }, { "vectorName", firstVectorName } } );
10886 throws += replaceWithMap( throwTemplateByLen,
10887 { { "className", className }, { "commandName", commandName }, { "sizeValue", sizeValue }, { "vectorName", firstVectorName } } );
10888 }
10889 else
10890 {
10891 for ( size_t i = 1; i < cvm.second.size(); i++ )
10892 {
10893 std::string secondVectorName = startLowerCase( stripPrefix( commandData.params[cvm.second[i]].name, "p" ) );
10894 bool withZeroSizeCheck = commandData.params[cvm.second[i]].optional && ( defaultStartIndex <= cvm.second[i] );
10895 if ( commandData.params[cvm.second[0]].type.type == "void" )
10896 {
10897 assert( commandData.params[cvm.second[i]].type.type == "void" );
10898 std::string firstDataType = stripPrefix( commandData.params[cvm.second[0]].name, "p" ) + "Type";
10899 std::string secondDataType = stripPrefix( commandData.params[cvm.second[i]].name, "p" ) + "Type";
10900 assertions += replaceWithMap( assertTemplateVoid,
10901 { { "firstDataType", firstDataType },
10902 { "firstVectorName", firstVectorName },
10903 { "secondDataType", secondDataType },
10904 { "secondVectorName", secondVectorName },
10905 { "zeroSizeCheck", withZeroSizeCheck ? ( secondVectorName + ".empty() || " ) : "" } } );
10906 throws += replaceWithMap( throwTemplateVoid,
10907 { { "firstDataType", firstDataType },
10908 { "firstVectorName", firstVectorName },
10909 { "className", className },
10910 { "commandName", commandName },
10911 { "secondDataType", secondDataType },
10912 { "secondVectorName", secondVectorName },
10913 { "zeroSizeCheck", withZeroSizeCheck ? ( "!" + secondVectorName + ".empty() && " ) : "" } } );
10914 }
10915 else
10916 {
10917 assertions += replaceWithMap( assertTemplate,
10918 { { "firstVectorName", firstVectorName },
10919 { "secondVectorName", secondVectorName },
10920 { "zeroSizeCheck", withZeroSizeCheck ? ( secondVectorName + ".empty() || " ) : "" } } );
10921 throws += replaceWithMap( throwTemplate,
10922 { { "firstVectorName", firstVectorName },
10923 { "className", className },
10924 { "commandName", commandName },
10925 { "secondVectorName", secondVectorName },
10926 { "zeroSizeCheck", withZeroSizeCheck ? ( "!" + secondVectorName + ".empty() && " ) : "" } } );
10927 }
10928 if ( i + 1 < cvm.second.size() )
10929 {
10930 assertions += "\n";
10931 throws += "\n";
10932 }
10933 }
10934 }
10935 }
10936
10937 std::string const sizeCheckTemplate =
10938 R"(#ifdef VULKAN_HPP_NO_EXCEPTIONS
10939 ${assertions}
10940 #else
10941 ${throws}
10942 #endif /*VULKAN_HPP_NO_EXCEPTIONS*/)";
10943
10944 return onlyThrows ? throws : replaceWithMap( sizeCheckTemplate, { { "assertions", assertions }, { "throws", throws } } );
10945 }
10946
getParentTypeAndName(std::pair<std::string,HandleData> const & handle) const10947 std::pair<std::string, std::string> VulkanHppGenerator::getParentTypeAndName( std::pair<std::string, HandleData> const & handle ) const
10948 {
10949 std::string parentType, parentName;
10950 if ( handle.first == "VkInstance" )
10951 {
10952 parentType = "Context";
10953 parentName = "context";
10954 }
10955 else
10956 {
10957 bool skip = skipLeadingGrandParent( handle );
10958 assert( !handle.second.constructorIts.empty() && ( ( skip ? 1u : 0u ) < handle.second.constructorIts.front()->second.params.size() ) );
10959 auto const & param = handle.second.constructorIts.front()->second.params[skip ? 1 : 0];
10960 assert( isHandleType( param.type.type ) && param.type.isValue() );
10961 parentType = stripPrefix( param.type.type, "Vk" );
10962 parentName = param.name;
10963 }
10964 return std::make_pair( parentType, parentName );
10965 }
10966
getPlatform(std::string const & title) const10967 std::string VulkanHppGenerator::getPlatform( std::string const & title ) const
10968 {
10969 if ( m_features.find( title ) == m_features.end() )
10970 {
10971 auto extensionIt = m_extensions.find( title );
10972 assert( extensionIt != m_extensions.end() );
10973 return extensionIt->second.platform;
10974 }
10975 return "";
10976 }
10977
getPoolTypeAndName(std::string const & type) const10978 std::pair<std::string, std::string> VulkanHppGenerator::getPoolTypeAndName( std::string const & type ) const
10979 {
10980 auto structIt = m_structures.find( type );
10981 assert( structIt != m_structures.end() );
10982 auto memberIt = std::find_if(
10983 structIt->second.members.begin(), structIt->second.members.end(), []( MemberData const & md ) { return md.name.find( "Pool" ) != std::string::npos; } );
10984 assert( memberIt != structIt->second.members.end() );
10985 assert( std::find_if( std::next( memberIt ),
10986 structIt->second.members.end(),
10987 []( MemberData const & md ) { return md.name.find( "Pool" ) != std::string::npos; } ) == structIt->second.members.end() );
10988 return std::make_pair( memberIt->type.type, memberIt->name );
10989 }
10990
getProtect(EnumValueData const & evd) const10991 std::string VulkanHppGenerator::getProtect( EnumValueData const & evd ) const
10992 {
10993 assert( evd.protect.empty() || ( evd.protect == getProtectFromTitle( evd.extension ) ) );
10994 return evd.protect.empty() ? getProtectFromTitle( evd.extension ) : evd.protect;
10995 }
10996
getProtectFromPlatform(std::string const & platform) const10997 std::string VulkanHppGenerator::getProtectFromPlatform( std::string const & platform ) const
10998 {
10999 auto platformIt = m_platforms.find( platform );
11000 return ( platformIt != m_platforms.end() ) ? platformIt->second.protect : "";
11001 }
11002
getProtectFromTitle(std::string const & title) const11003 std::string VulkanHppGenerator::getProtectFromTitle( std::string const & title ) const
11004 {
11005 if ( m_features.find( title ) == m_features.end() )
11006 {
11007 auto extensionIt = m_extensions.find( title );
11008 return ( extensionIt != m_extensions.end() ) ? getProtectFromPlatform( extensionIt->second.platform ) : "";
11009 }
11010 return "";
11011 }
11012
getProtectFromType(std::string const & type) const11013 std::string VulkanHppGenerator::getProtectFromType( std::string const & type ) const
11014 {
11015 auto typeIt = m_types.find( type );
11016 assert( typeIt != m_types.end() );
11017 return getProtectFromTitle( typeIt->second.referencedIn );
11018 }
11019
getVectorSize(std::vector<ParamData> const & params,std::map<size_t,VectorParamData> const & vectorParams,size_t returnParam,std::string const & returnParamType,std::set<size_t> const & templatedParams) const11020 std::string VulkanHppGenerator::getVectorSize( std::vector<ParamData> const & params,
11021 std::map<size_t, VectorParamData> const & vectorParams,
11022 size_t returnParam,
11023 std::string const & returnParamType,
11024 std::set<size_t> const & templatedParams ) const
11025 {
11026 std::string vectorSize;
11027 std::vector<std::string> lenParts = tokenize( params[returnParam].len, "->" );
11028 switch ( lenParts.size() )
11029 {
11030 case 1:
11031 {
11032 std::string const & len = lenParts[0];
11033 size_t lenIdx =
11034 std::distance( params.begin(), std::find_if( params.begin(), params.end(), [&len]( ParamData const & pd ) { return pd.name == len; } ) );
11035 assert( lenIdx < params.size() );
11036 // look for the len, not being the len of the return param, but of an other vector param
11037 auto lenVectorParamIt =
11038 std::find_if( vectorParams.begin(),
11039 vectorParams.end(),
11040 [&lenIdx, &returnParam]( auto const & vpi ) { return ( vpi.first != returnParam ) && ( vpi.second.lenParam == lenIdx ); } );
11041 if ( lenVectorParamIt == vectorParams.end() )
11042 {
11043 vectorSize = lenParts[0];
11044 if ( templatedParams.find( returnParam ) != templatedParams.end() )
11045 {
11046 vectorSize += " / sizeof( " + returnParamType + " )";
11047 }
11048 }
11049 else
11050 {
11051 assert( templatedParams.find( returnParam ) == templatedParams.end() );
11052 vectorSize = startLowerCase( stripPrefix( params[lenVectorParamIt->first].name, "p" ) ) + ".size()";
11053 }
11054 }
11055 break;
11056 case 2:
11057 assert( vectorParams.find( returnParam ) != vectorParams.end() );
11058 vectorSize = startLowerCase( stripPrefix( lenParts[0], "p" ) ) + "." + lenParts[1];
11059 break;
11060 default: assert( false ); break;
11061 }
11062 assert( !vectorSize.empty() );
11063 return vectorSize;
11064 }
11065
hasLen(std::vector<MemberData> const & members,MemberData const & md) const11066 bool VulkanHppGenerator::hasLen( std::vector<MemberData> const & members, MemberData const & md ) const
11067 {
11068 if ( !md.len.empty() && !( md.len[0] == "null-terminated" ) && ( ( altLens.find( md.len[0] ) == altLens.end() ) || ( md.len[0] == "codeSize / 4" ) ) )
11069 {
11070 auto lenIt = findStructMemberIt( md.len.front(), members );
11071 return ( lenIt == members.end() ) || lenIt->type.isValue();
11072 }
11073 return false;
11074 }
11075
hasParentHandle(std::string const & handle,std::string const & parent) const11076 bool VulkanHppGenerator::hasParentHandle( std::string const & handle, std::string const & parent ) const
11077 {
11078 std::string candidate = handle;
11079 while ( !candidate.empty() )
11080 {
11081 auto const & handleIt = m_handles.find( candidate );
11082 assert( handleIt != m_handles.end() );
11083 if ( handleIt->second.parent == parent )
11084 {
11085 return true;
11086 }
11087 else
11088 {
11089 candidate = handleIt->second.parent;
11090 }
11091 }
11092 return false;
11093 }
11094
isDeviceCommand(CommandData const & commandData) const11095 bool VulkanHppGenerator::isDeviceCommand( CommandData const & commandData ) const
11096 {
11097 return !commandData.handle.empty() && !commandData.params.empty() && ( m_handles.find( commandData.params[0].type.type ) != m_handles.end() ) &&
11098 ( commandData.params[0].type.type != "VkInstance" ) && ( commandData.params[0].type.type != "VkPhysicalDevice" );
11099 }
11100
isHandleType(std::string const & type) const11101 bool VulkanHppGenerator::isHandleType( std::string const & type ) const
11102 {
11103 if ( type.starts_with( "Vk" ) )
11104 {
11105 auto it = m_handles.find( type );
11106 if ( it == m_handles.end() )
11107 {
11108 it = std::find_if( m_handles.begin(), m_handles.end(), [&type]( std::pair<std::string, HandleData> const & hd ) { return hd.second.alias == type; } );
11109 }
11110 return ( it != m_handles.end() );
11111 }
11112 return false;
11113 }
11114
isLenByStructMember(std::string const & name,std::vector<ParamData> const & params) const11115 bool VulkanHppGenerator::isLenByStructMember( std::string const & name, std::vector<ParamData> const & params ) const
11116 {
11117 // check if name specifies a member of a struct
11118 std::vector<std::string> nameParts = tokenize( name, "->" );
11119 if ( nameParts.size() == 1 )
11120 {
11121 // older versions of vk.xml used the notation parameter::member
11122 nameParts = tokenize( name, "::" );
11123 }
11124 if ( nameParts.size() == 2 )
11125 {
11126 auto paramIt = std::find_if( params.begin(), params.end(), [&n = nameParts[0]]( ParamData const & pd ) { return pd.name == n; } );
11127 if ( paramIt != params.end() )
11128 {
11129 #if !defined( NDEBUG )
11130 auto structureIt = m_structures.find( paramIt->type.type );
11131 assert( structureIt != m_structures.end() );
11132 assert( isStructMember( nameParts[1], structureIt->second.members ) );
11133 #endif
11134 return true;
11135 }
11136 }
11137 return false;
11138 }
11139
isLenByStructMember(std::string const & name,ParamData const & param) const11140 bool VulkanHppGenerator::isLenByStructMember( std::string const & name, ParamData const & param ) const
11141 {
11142 // check if name specifies a member of a struct
11143 std::vector<std::string> nameParts = tokenize( name, "->" );
11144 if ( nameParts.size() == 1 )
11145 {
11146 // older versions of vk.xml used the notation parameter::member
11147 nameParts = tokenize( name, "::" );
11148 }
11149 if ( ( nameParts.size() == 2 ) && ( nameParts[0] == param.name ) )
11150 {
11151 #if !defined( NDEBUG )
11152 auto structureIt = m_structures.find( param.type.type );
11153 assert( structureIt != m_structures.end() );
11154 assert( isStructMember( nameParts[1], structureIt->second.members ) );
11155 #endif
11156 return true;
11157 }
11158 return false;
11159 }
11160
isMultiSuccessCodeConstructor(std::vector<std::map<std::string,CommandData>::const_iterator> const & constructorIts) const11161 bool VulkanHppGenerator::isMultiSuccessCodeConstructor( std::vector<std::map<std::string, CommandData>::const_iterator> const & constructorIts ) const
11162 {
11163 bool ok = !constructorIts.empty();
11164 if ( ok )
11165 {
11166 auto constructorIt = constructorIts.begin();
11167 ok = ( 2 < ( *constructorIt )->second.successCodes.size() ) ||
11168 ( ( ( *constructorIt )->second.successCodes.size() == 2 ) && ( ( *constructorIt )->second.successCodes[1] != "VK_INCOMPLETE" ) );
11169 #if !defined( NDEBUG )
11170 for ( constructorIt = std::next( constructorIt ); constructorIt != constructorIts.end(); ++constructorIt )
11171 {
11172 assert( ok == ( 2 < ( *constructorIt )->second.successCodes.size() ) ||
11173 ( ( ( *constructorIt )->second.successCodes.size() == 2 ) && ( ( *constructorIt )->second.successCodes[1] != "VK_INCOMPLETE" ) ) );
11174 }
11175 #endif
11176 }
11177 return ok;
11178 }
11179
isParam(std::string const & name,std::vector<ParamData> const & params) const11180 bool VulkanHppGenerator::isParam( std::string const & name, std::vector<ParamData> const & params ) const
11181 {
11182 return std::find_if( params.begin(), params.end(), [&name]( ParamData const & pd ) { return pd.name == name; } ) != params.end();
11183 }
11184
isStructMember(std::string const & name,std::vector<MemberData> const & memberData) const11185 bool VulkanHppGenerator::isStructMember( std::string const & name, std::vector<MemberData> const & memberData ) const
11186 {
11187 return findStructMemberIt( name, memberData ) != memberData.end();
11188 }
11189
isStructureChainAnchor(std::string const & type) const11190 bool VulkanHppGenerator::isStructureChainAnchor( std::string const & type ) const
11191 {
11192 if ( type.starts_with( "Vk" ) )
11193 {
11194 auto it = m_structures.find( type );
11195 if ( it == m_structures.end() )
11196 {
11197 auto aliasIt = m_structureAliases.find( type );
11198 if ( aliasIt != m_structureAliases.end() )
11199 {
11200 it = m_structures.find( aliasIt->second.alias );
11201 }
11202 }
11203 if ( it != m_structures.end() )
11204 {
11205 return m_extendedStructs.find( it->first ) != m_extendedStructs.end();
11206 }
11207 }
11208 return false;
11209 }
11210
needsVectorSizeCheck(std::vector<ParamData> const & params,std::map<size_t,VectorParamData> const & vectorParams,std::vector<size_t> const & returnParams,std::set<size_t> const & singularParams) const11211 std::pair<bool, std::map<size_t, std::vector<size_t>>> VulkanHppGenerator::needsVectorSizeCheck( std::vector<ParamData> const & params,
11212 std::map<size_t, VectorParamData> const & vectorParams,
11213 std::vector<size_t> const & returnParams,
11214 std::set<size_t> const & singularParams ) const
11215 {
11216 std::map<size_t, std::vector<size_t>> countToVectorMap;
11217 for ( auto const & vpi : vectorParams )
11218 {
11219 if ( ( vpi.second.lenParam != INVALID_INDEX ) && ( std::find( returnParams.begin(), returnParams.end(), vpi.first ) == returnParams.end() ) &&
11220 ( ( singularParams.find( vpi.second.lenParam ) == singularParams.end() ) ||
11221 isLenByStructMember( params[vpi.first].len, params[vpi.second.lenParam] ) ) )
11222 {
11223 countToVectorMap[vpi.second.lenParam].push_back( vpi.first );
11224 }
11225 }
11226 return std::make_pair( std::find_if( countToVectorMap.begin(),
11227 countToVectorMap.end(),
11228 [this, ¶ms]( auto const & cvm ) {
11229 return ( 1 < cvm.second.size() ) || isLenByStructMember( params[cvm.second[0]].len, params[cvm.first] );
11230 } ) != countToVectorMap.end(),
11231 countToVectorMap );
11232 }
11233
readCommands(tinyxml2::XMLElement const * element)11234 void VulkanHppGenerator::readCommands( tinyxml2::XMLElement const * element )
11235 {
11236 int line = element->GetLineNum();
11237 checkAttributes( line, getAttributes( element ), {}, { { "comment", {} } } );
11238
11239 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11240 checkElements( line, children, { { "command", false } } );
11241 for ( auto child : children )
11242 {
11243 assert( child->Value() == std::string( "command" ) );
11244 readCommandsCommand( child );
11245 }
11246 }
11247
readCommandsCommand(tinyxml2::XMLElement const * element)11248 void VulkanHppGenerator::readCommandsCommand( tinyxml2::XMLElement const * element )
11249 {
11250 int line = element->GetLineNum();
11251 std::map<std::string, std::string> attributes = getAttributes( element );
11252 if ( attributes.find( "alias" ) != attributes.end() )
11253 {
11254 // for command aliases, create a copy of the aliased command
11255 checkAttributes( line,
11256 attributes,
11257 {},
11258 {
11259 { "alias", {} },
11260 { "name", {} },
11261 } );
11262 checkElements( line, getChildElements( element ), {} );
11263
11264 std::string alias, name;
11265 for ( auto const & attribute : attributes )
11266 {
11267 if ( attribute.first == "alias" )
11268 {
11269 alias = attribute.second;
11270 }
11271 else if ( attribute.first == "name" )
11272 {
11273 name = attribute.second;
11274 checkForError( name.starts_with( "vk" ), line, "name <" + name + "> should begin with <vk>" );
11275 }
11276 }
11277
11278 auto commandIt = m_commands.find( alias );
11279 checkForError( commandIt != m_commands.end(), line, "missing command <" + alias + ">" );
11280 CommandData commandData = commandIt->second;
11281 commandData.alias = alias;
11282 commandData.xmlLine = line;
11283 addCommand( name, commandData );
11284 }
11285 else
11286 {
11287 checkAttributes( line,
11288 attributes,
11289 {},
11290 { { "cmdbufferlevel", { "primary", "secondary" } },
11291 { "comment", {} },
11292 { "errorcodes", {} },
11293 { "queues", { "compute", "decode", "encode", "graphics", "opticalflow", "sparse_binding", "transfer" } },
11294 { "renderpass", { "both", "inside", "outside" } },
11295 { "successcodes", {} },
11296 { "tasks", { "action", "indirection", "state", "synchronization" } },
11297 { "videocoding", { "both", "inside", "outside" } } } );
11298
11299 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11300 checkElements( line, children, { { "param", false }, { "proto", true } }, { "implicitexternsyncparams" } );
11301
11302 CommandData commandData( line );
11303 for ( auto const & attribute : attributes )
11304 {
11305 if ( attribute.first == "errorcodes" )
11306 {
11307 commandData.errorCodes = tokenize( attribute.second, "," );
11308 // errorCodes are checked in checkCorrectness after complete reading
11309 }
11310 else if ( attribute.first == "successcodes" )
11311 {
11312 commandData.successCodes = tokenize( attribute.second, "," );
11313 // successCodes are checked in checkCorrectness after complete reading
11314 }
11315 }
11316
11317 std::string name;
11318 for ( auto child : children )
11319 {
11320 std::string value = child->Value();
11321 if ( value == "param" )
11322 {
11323 std::pair<bool, ParamData> result = readCommandsCommandParam( child, commandData.params );
11324 if ( result.first )
11325 {
11326 commandData.params.push_back( result.second );
11327 }
11328 }
11329 else if ( value == "proto" )
11330 {
11331 std::tie( name, commandData.returnType ) = readCommandsCommandProto( child );
11332 }
11333 }
11334 assert( !name.empty() );
11335 checkForError( ( commandData.returnType == "VkResult" ) || commandData.errorCodes.empty(),
11336 line,
11337 "command <" + name + "> does not return a VkResult but specifies errorcodes" );
11338 checkForError( ( commandData.returnType == "VkResult" ) || commandData.successCodes.empty(),
11339 line,
11340 "command <" + name + "> does not return a VkResult but specifies successcodes" );
11341 for ( auto const & param : commandData.params )
11342 {
11343 checkForError( param.stride.empty() || isParam( param.stride, commandData.params ),
11344 param.xmlLine,
11345 "attribute <stride> holds an unknown value <" + param.stride + ">" );
11346 }
11347
11348 addCommand( name, commandData );
11349 }
11350 }
11351
readCommandsCommandParam(tinyxml2::XMLElement const * element,std::vector<ParamData> const & params)11352 std::pair<bool, VulkanHppGenerator::ParamData> VulkanHppGenerator::readCommandsCommandParam( tinyxml2::XMLElement const * element,
11353 std::vector<ParamData> const & params )
11354 {
11355 int line = element->GetLineNum();
11356 std::map<std::string, std::string> attributes = getAttributes( element );
11357 checkAttributes( line,
11358 attributes,
11359 {},
11360 { { "altlen", {} },
11361 { "api", { "vulkan", "vulkansc" } },
11362 { "externsync", {} },
11363 { "len", {} },
11364 { "noautovalidity", { "true" } },
11365 { "objecttype", { "objectType" } },
11366 { "optional", { "false", "true" } },
11367 { "stride", {} },
11368 { "validstructs", {} } } );
11369
11370 ParamData paramData( line );
11371 for ( auto attribute : attributes )
11372 {
11373 if ( attribute.first == "altlen" )
11374 {
11375 assert( paramData.len.empty() );
11376 paramData.len = attribute.second;
11377 checkForError( altLens.find( paramData.len ) != altLens.end(), line, "attribute <altlen> holds unknown value <" + paramData.len + ">" );
11378 }
11379 else if ( attribute.first == "api" )
11380 {
11381 if ( attribute.second == "vulkansc" )
11382 {
11383 return std::make_pair( false, paramData ); // skip stuff marked as "vulkansc" !
11384 }
11385 assert( attribute.second == "vulkan" );
11386 }
11387 else if ( attribute.first == "len" )
11388 {
11389 if ( paramData.len.empty() )
11390 {
11391 checkForError( ( attribute.second == "null-terminated" ) || isParam( attribute.second, params ) || isLenByStructMember( attribute.second, params ),
11392 line,
11393 "attribute <len> holds an unknown value <" + attribute.second + ">" );
11394 paramData.len = attribute.second;
11395 }
11396 }
11397 else if ( attribute.first == "stride" )
11398 {
11399 paramData.stride = attribute.second;
11400 }
11401 else if ( attribute.first == "optional" )
11402 {
11403 paramData.optional = ( attribute.second == "true" );
11404 }
11405 else if ( attribute.first == "validstructs" )
11406 {
11407 std::vector<std::string> validStructs = tokenize( attribute.second, "," );
11408 for ( auto const & vs : validStructs )
11409 {
11410 checkForError( m_structures.find( vs ) != m_structures.end(), line, "unknown struct <" + vs + "> listed in attribute <validstructs>" );
11411 }
11412 }
11413 }
11414
11415 NameData nameData;
11416 std::tie( nameData, paramData.type ) = readNameAndType( element );
11417
11418 checkForError( m_types.find( paramData.type.type ) != m_types.end(), line, "unknown type <" + paramData.type.type + ">" );
11419 checkForError( paramData.type.prefix.empty() || ( paramData.type.prefix == "const" ) || ( paramData.type.prefix == "const struct" ) ||
11420 ( paramData.type.prefix == "struct" ),
11421 line,
11422 "unexpected type prefix <" + paramData.type.prefix + ">" );
11423 checkForError( paramData.type.postfix.empty() || ( paramData.type.postfix == "*" ) || ( paramData.type.postfix == "**" ) ||
11424 ( paramData.type.postfix == "* const *" ),
11425 line,
11426 "unexpected type postfix <" + paramData.type.postfix + ">" );
11427 checkForError( std::find_if( params.begin(), params.end(), [&name = nameData.name]( ParamData const & pd ) { return pd.name == name; } ) == params.end(),
11428 line,
11429 "command param <" + nameData.name + "> already used" );
11430 paramData.name = nameData.name;
11431 paramData.arraySizes = nameData.arraySizes;
11432
11433 return std::make_pair( true, paramData );
11434 }
11435
readCommandsCommandProto(tinyxml2::XMLElement const * element)11436 std::pair<std::string, std::string> VulkanHppGenerator::readCommandsCommandProto( tinyxml2::XMLElement const * element )
11437 {
11438 int line = element->GetLineNum();
11439 checkAttributes( line, getAttributes( element ), {}, {} );
11440
11441 auto [nameData, typeInfo] = readNameAndType( element );
11442
11443 checkForError( nameData.name.starts_with( "vk" ), line, "name <" + nameData.name + "> does not begin with <vk>" );
11444 checkForError( nameData.arraySizes.empty(), line, "name <" + nameData.name + "> with unsupported arraySizes" );
11445 checkForError( m_types.find( typeInfo.type ) != m_types.end(), line, "unknown type <" + typeInfo.type + ">" );
11446 checkForError( typeInfo.prefix.empty(), line, "unexpected type prefix <" + typeInfo.prefix + ">" );
11447 checkForError( typeInfo.postfix.empty(), line, "unexpected type postfix <" + typeInfo.postfix + ">" );
11448 checkForError( m_commands.find( nameData.name ) == m_commands.end(), line, "command <" + nameData.name + "> already specified" );
11449
11450 return std::make_pair( nameData.name, typeInfo.type );
11451 }
11452
readEnums(tinyxml2::XMLElement const * element)11453 void VulkanHppGenerator::readEnums( tinyxml2::XMLElement const * element )
11454 {
11455 int line = element->GetLineNum();
11456 std::map<std::string, std::string> attributes = getAttributes( element );
11457 checkAttributes( line, attributes, { { "name", {} } }, { { "bitwidth", { "64" } }, { "comment", {} }, { "type", { "bitmask", "enum" } } } );
11458 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11459
11460 std::string bitwidth, name, type;
11461 for ( auto const & attribute : attributes )
11462 {
11463 if ( attribute.first == "bitwidth" )
11464 {
11465 bitwidth = attribute.second;
11466 }
11467 else if ( attribute.first == "name" )
11468 {
11469 name = attribute.second;
11470 }
11471 else if ( attribute.first == "type" )
11472 {
11473 type = attribute.second;
11474 }
11475 }
11476 assert( !name.empty() );
11477
11478 if ( name == "API Constants" )
11479 {
11480 checkElements( line, children, { { "enum", false } }, {} );
11481 for ( auto const & child : children )
11482 {
11483 readEnumsConstant( child );
11484 }
11485 }
11486 else
11487 {
11488 checkElements( line, children, {}, { "comment", "enum", "unused" } );
11489 checkForError( !type.empty(), line, "enum without type" );
11490
11491 // get the EnumData entry in enum map
11492 std::map<std::string, EnumData>::iterator enumIt = m_enums.find( name );
11493 if ( enumIt == m_enums.end() )
11494 {
11495 enumIt =
11496 std::find_if( m_enums.begin(), m_enums.end(), [&name]( std::pair<std::string, EnumData> const & enumData ) { return enumData.second.alias == name; } );
11497 }
11498 checkForError( enumIt != m_enums.end(), line, "enum <" + name + "> is not listed as enum in the types section" );
11499 checkForError( enumIt->second.values.empty(), line, "enum <" + name + "> already holds values" );
11500
11501 // mark it as a bitmask, if it is one
11502 bool bitmask = ( type == "bitmask" );
11503 if ( bitmask )
11504 {
11505 checkForError( name.find( "FlagBits" ) != std::string::npos, line, "bitmask <" + name + "> does not contain <FlagBits>" );
11506 }
11507 enumIt->second.isBitmask = bitmask;
11508 enumIt->second.bitwidth = bitwidth;
11509
11510 // read the names of the enum values
11511 for ( auto child : children )
11512 {
11513 std::string value = child->Value();
11514 if ( value == "comment" )
11515 {
11516 readComment( child );
11517 }
11518 else if ( value == "enum" )
11519 {
11520 readEnumsEnum( child, enumIt );
11521 }
11522 }
11523 }
11524 }
11525
readEnumsConstant(tinyxml2::XMLElement const * element)11526 void VulkanHppGenerator::readEnumsConstant( tinyxml2::XMLElement const * element )
11527 {
11528 int line = element->GetLineNum();
11529 std::map<std::string, std::string> attributes = getAttributes( element );
11530 checkAttributes( line, attributes, { { "name", {} } }, { { "alias", {} }, { "comment", {} }, { "type", {} }, { "value", {} } } );
11531 checkElements( line, getChildElements( element ), {} );
11532
11533 std::string alias, name, value;
11534 for ( auto const & attribute : attributes )
11535 {
11536 if ( attribute.first == "alias" )
11537 {
11538 checkForError( m_constants.find( attribute.second ) != m_constants.end(), line, "unknown enum constant alias <" + attribute.second + ">" );
11539 alias = attribute.second;
11540 }
11541 else if ( attribute.first == "name" )
11542 {
11543 checkForError( m_constants.find( attribute.second ) == m_constants.end(), line, "already specified enum constant <" + attribute.second + ">" );
11544 name = attribute.second;
11545 }
11546 else if ( attribute.first == "value" )
11547 {
11548 checkForError( !attribute.second.empty(), line, "value of enum constant is empty" );
11549 value = attribute.second;
11550 }
11551 }
11552 checkForError( alias.empty() != value.empty(), line, "for enum <" + name + "> either alias or value need to be specified" );
11553 m_constants[name] = alias.empty() ? value : m_constants[alias];
11554 }
11555
readEnumsEnum(tinyxml2::XMLElement const * element,std::map<std::string,EnumData>::iterator enumIt)11556 void VulkanHppGenerator::readEnumsEnum( tinyxml2::XMLElement const * element, std::map<std::string, EnumData>::iterator enumIt )
11557 {
11558 int line = element->GetLineNum();
11559 std::map<std::string, std::string> attributes = getAttributes( element );
11560 if ( attributes.find( "alias" ) != attributes.end() )
11561 {
11562 checkAttributes( line, attributes, { { "alias", {} }, { "name", {} } }, { { "api", { "vulkan", "vulkansc" } }, { "comment", {} } } );
11563 checkElements( line, getChildElements( element ), {} );
11564
11565 std::string alias, bitpos, name, value;
11566 for ( auto const & attribute : attributes )
11567 {
11568 if ( attribute.first == "alias" )
11569 {
11570 alias = attribute.second;
11571 }
11572 else if ( attribute.first == "api" )
11573 {
11574 if ( attribute.second == "vulkansc" )
11575 {
11576 return; // skip stuff marked as "vulkansc" !
11577 }
11578 assert( attribute.second == "vulkan" );
11579 }
11580 else if ( attribute.first == "name" )
11581 {
11582 name = attribute.second;
11583 }
11584 }
11585 assert( !name.empty() );
11586
11587 enumIt->second.addEnumAlias( line, name, alias );
11588 }
11589 else
11590 {
11591 checkAttributes( line, attributes, { { "name", {} } }, { { "bitpos", {} }, { "comment", {} }, { "value", {} } } );
11592 checkElements( line, getChildElements( element ), {} );
11593
11594 std::string alias, bitpos, name, protect, value;
11595 for ( auto const & attribute : attributes )
11596 {
11597 if ( attribute.first == "bitpos" )
11598 {
11599 bitpos = attribute.second;
11600 }
11601 else if ( attribute.first == "name" )
11602 {
11603 name = attribute.second;
11604 }
11605 else if ( attribute.first == "value" )
11606 {
11607 value = attribute.second;
11608 }
11609 }
11610
11611 std::string prefix = generateEnumSuffixes( enumIt->first, enumIt->second.isBitmask, m_tags ).first;
11612 checkForError( name.starts_with( prefix ), line, "encountered enum value <" + name + "> that does not begin with expected prefix <" + prefix + ">" );
11613
11614 checkForError( bitpos.empty() ^ value.empty(), line, "invalid set of attributes for enum <" + name + ">" );
11615 enumIt->second.addEnumValue( line, name, protect, !bitpos.empty(), "" );
11616 }
11617 }
11618
readComment(tinyxml2::XMLElement const * element)11619 std::string VulkanHppGenerator::readComment( tinyxml2::XMLElement const * element )
11620 {
11621 int line = element->GetLineNum();
11622 checkAttributes( line, getAttributes( element ), {}, {} );
11623 checkElements( line, getChildElements( element ), {} );
11624
11625 return element->GetText();
11626 }
11627
readExtensions(tinyxml2::XMLElement const * element)11628 void VulkanHppGenerator::readExtensions( tinyxml2::XMLElement const * element )
11629 {
11630 int line = element->GetLineNum();
11631 checkAttributes( line, getAttributes( element ), { { "comment", {} } }, {} );
11632 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11633 checkElements( line, children, { { "extension", false } } );
11634
11635 for ( auto child : children )
11636 {
11637 assert( child->Value() == std::string( "extension" ) );
11638 readExtensionsExtension( child );
11639 }
11640 }
11641
readExtensionsExtension(tinyxml2::XMLElement const * element)11642 void VulkanHppGenerator::readExtensionsExtension( tinyxml2::XMLElement const * element )
11643 {
11644 int line = element->GetLineNum();
11645 std::map<std::string, std::string> attributes = getAttributes( element );
11646 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11647
11648 checkAttributes( line,
11649 attributes,
11650 { { "name", {} }, { "number", {} }, { "supported", { "disabled", "vulkan", "vulkansc" } } },
11651 { { "author", {} },
11652 { "comment", {} },
11653 { "contact", {} },
11654 { "depends", {} },
11655 { "deprecatedby", {} },
11656 { "obsoletedby", {} },
11657 { "platform", {} },
11658 { "promotedto", {} },
11659 { "provisional", { "true" } },
11660 { "requires", {} },
11661 { "requiresCore", {} },
11662 { "sortorder", { "1" } },
11663 { "specialuse", { "cadsupport", "d3demulation", "debugging", "devtools", "glemulation" } },
11664 { "type", { "device", "instance" } } } );
11665 checkElements( line, children, { { "require", false } } );
11666
11667 std::string deprecatedBy, name, number, obsoletedBy, platform, promotedTo;
11668 std::vector<std::string> depends;
11669 bool supported = false;
11670 for ( auto const & attribute : attributes )
11671 {
11672 if ( attribute.first == "deprecatedby" )
11673 {
11674 deprecatedBy = attribute.second;
11675 }
11676 else if ( attribute.first == "name" )
11677 {
11678 name = attribute.second;
11679 checkForError( m_extensions.find( name ) == m_extensions.end(), line, "already encountered extension <" + name + ">" );
11680 }
11681 else if ( attribute.first == "number" )
11682 {
11683 number = attribute.second;
11684 }
11685 else if ( attribute.first == "obsoletedby" )
11686 {
11687 obsoletedBy = attribute.second;
11688 }
11689 else if ( attribute.first == "platform" )
11690 {
11691 platform = attribute.second;
11692 checkForError( m_platforms.find( platform ) != m_platforms.end(), line, "unknown platform <" + platform + ">" );
11693 }
11694 else if ( attribute.first == "promotedto" )
11695 {
11696 promotedTo = attribute.second;
11697 }
11698 else if ( attribute.first == "provisional" )
11699 {
11700 if ( platform.empty() )
11701 {
11702 // for now, having the attribute provisional="true" implies attribute platform="provisional" to get
11703 // stuff protected by VK_ENABLE_BETA_EXTENSIONS
11704 platform = "provisional";
11705 }
11706 checkForError( platform == "provisional",
11707 line,
11708 "while attribute <provisional> is set to \"true\", attribute <platform> is not set to \"provisional\" but to \"" + platform + "\"" );
11709 }
11710 else if ( ( attribute.first == "depends" ) || ( attribute.first == "requires" ) )
11711 {
11712 // we don't care about the logical implications of ',' and '+' here, we're just interested to get the depends strings
11713 depends = tokenizeAny( attribute.second, ",+" );
11714 }
11715 else if ( attribute.first == "requiresCore" )
11716 {
11717 std::string const & requiresCore = attribute.second;
11718 checkForError( std::find_if( m_features.begin(),
11719 m_features.end(),
11720 [&requiresCore]( std::pair<std::string, FeatureData> const & feature )
11721 { return feature.second.number == requiresCore; } ) != m_features.end(),
11722 line,
11723 "unknown feature number <" + attribute.second + ">" );
11724 }
11725 else if ( attribute.first == "supported" )
11726 {
11727 std::vector<std::string> api = tokenize( attribute.second, "," );
11728 supported = ( std::find( api.begin(), api.end(), "vulkan" ) != api.end() );
11729 }
11730 }
11731
11732 auto extensionIt = m_extensions.end();
11733 if ( supported )
11734 {
11735 extensionIt = m_extensions.insert( std::make_pair( name, ExtensionData( line, deprecatedBy, number, obsoletedBy, platform, promotedTo ) ) ).first;
11736 for ( auto const & d : depends )
11737 {
11738 checkForError( extensionIt->second.depends.insert( d ).second, line, "required depends <" + d + "> already listed" );
11739 }
11740
11741 // extract the tag from the name, which is supposed to look like VK_<tag>_<other>
11742 size_t tagStart = name.find( '_' );
11743 checkForError( tagStart != std::string::npos, line, "name <" + name + "> is missing an underscore '_'" );
11744 size_t tagEnd = name.find( '_', tagStart + 1 );
11745 checkForError( tagEnd != std::string::npos, line, "name <" + name + "> is missing an underscore '_'" );
11746 std::string tag = name.substr( tagStart + 1, tagEnd - tagStart - 1 );
11747 checkForError( m_tags.find( tag ) != m_tags.end(), line, "name <" + name + "> is using an unknown tag <" + tag + ">" );
11748 }
11749
11750 for ( auto child : children )
11751 {
11752 assert( child->Value() == std::string( "require" ) );
11753 if ( supported )
11754 {
11755 readExtensionsExtensionRequire( child, extensionIt );
11756 }
11757 else
11758 {
11759 readExtensionsExtensionRequireSkipped( child );
11760 }
11761 }
11762 }
11763
readExtensionsExtensionRequire(tinyxml2::XMLElement const * element,std::map<std::string,ExtensionData>::iterator extensionIt)11764 void VulkanHppGenerator::readExtensionsExtensionRequire( tinyxml2::XMLElement const * element, std::map<std::string, ExtensionData>::iterator extensionIt )
11765 {
11766 int line = element->GetLineNum();
11767 std::map<std::string, std::string> attributes = getAttributes( element );
11768 checkAttributes( line, attributes, {}, { { "depends", {} }, { "extension", {} }, { "feature", {} } } );
11769 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11770 checkElements( line, children, {}, { "command", "comment", "enum", "type" } );
11771
11772 std::vector<std::string> depends;
11773 for ( auto const & attribute : attributes )
11774 {
11775 if ( ( attribute.first == "depends" ) || ( attribute.first == "extension" ) )
11776 {
11777 assert( depends.empty() );
11778 depends = tokenizeAny( attribute.second, ",+" );
11779 for ( auto const & d : depends )
11780 {
11781 checkForError( std::find_if( extensionIt->second.requireData.begin(),
11782 extensionIt->second.requireData.end(),
11783 [&d]( RequireData const & rd ) { return std::find( rd.depends.begin(), rd.depends.end(), d ) != rd.depends.end(); } ) ==
11784 extensionIt->second.requireData.end(),
11785 line,
11786 "required extension <" + d + "> already listed" );
11787 }
11788 }
11789 else
11790 {
11791 assert( attribute.first == "feature" );
11792 if ( m_features.find( attribute.second ) != m_features.end() )
11793 {
11794 assert( depends.empty() );
11795 depends.push_back( attribute.second );
11796 }
11797 else
11798 {
11799 checkForError( m_skippedFeatures.find( attribute.second ) != m_skippedFeatures.end(), line, "unknown feature <" + attribute.second + ">" );
11800 readExtensionsExtensionRequireSkipped( element );
11801 return;
11802 }
11803 }
11804 }
11805
11806 RequireData requireData( line, depends );
11807 bool requireDataEmpty = true;
11808 for ( auto child : children )
11809 {
11810 std::string value = child->Value();
11811 if ( value == "command" )
11812 {
11813 readExtensionsExtensionRequireCommand( child, extensionIt->first, requireData );
11814 requireDataEmpty = false;
11815 }
11816 else if ( value == "comment" )
11817 {
11818 readComment( child );
11819 }
11820 else if ( value == "enum" )
11821 {
11822 readRequireEnum( child, extensionIt->first );
11823 }
11824 else if ( value == "type" )
11825 {
11826 readExtensionsExtensionRequireType( child, extensionIt->first, requireData );
11827 requireDataEmpty = false;
11828 }
11829 }
11830 if ( !requireDataEmpty )
11831 {
11832 extensionIt->second.requireData.push_back( requireData );
11833 }
11834 }
11835
readExtensionsExtensionRequireCommand(tinyxml2::XMLElement const * element,std::string const & extensionName,RequireData & requireData)11836 void VulkanHppGenerator::readExtensionsExtensionRequireCommand( tinyxml2::XMLElement const * element,
11837 std::string const & extensionName,
11838 RequireData & requireData )
11839 {
11840 int line = element->GetLineNum();
11841 std::map<std::string, std::string> attributes = getAttributes( element );
11842 checkAttributes( line, attributes, { { "name", {} } }, { { "comment", {} } } );
11843 checkElements( line, getChildElements( element ), {} );
11844
11845 std::string name;
11846 for ( auto const & attribute : attributes )
11847 {
11848 if ( attribute.first == "name" )
11849 {
11850 name = attribute.second;
11851 }
11852 }
11853 assert( !name.empty() );
11854
11855 // mark this command be part of this extension
11856 auto commandIt = m_commands.find( name );
11857 checkForError(
11858 commandIt != m_commands.end(), line, "command <" + name + "> marked as required in extension <" + extensionName + "> was not listed before as a command!" );
11859 if ( commandIt->second.referencedIn.empty() )
11860 {
11861 commandIt->second.referencedIn = extensionName;
11862 }
11863 else
11864 {
11865 checkForError( getPlatform( commandIt->second.referencedIn ) == getPlatform( extensionName ),
11866 line,
11867 "command <" + name + "> is referenced in extensions <" + commandIt->second.referencedIn + "> and <" + extensionName +
11868 "> and thus protected by different platforms <" + getPlatform( commandIt->second.referencedIn ) + "> and <" +
11869 getPlatform( extensionName ) + ">!" );
11870 }
11871 assert( std::find( requireData.commands.begin(), requireData.commands.end(), name ) == requireData.commands.end() );
11872 requireData.commands.push_back( name );
11873 }
11874
readExtensionsExtensionRequireSkipped(tinyxml2::XMLElement const * element)11875 void VulkanHppGenerator::readExtensionsExtensionRequireSkipped( tinyxml2::XMLElement const * element )
11876 {
11877 int line = element->GetLineNum();
11878 std::map<std::string, std::string> attributes = getAttributes( element );
11879 checkAttributes( line, attributes, {}, { { "comment", {} }, { "depends", {} }, { "extension", {} }, { "feature", {} } } );
11880 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11881 checkElements( line, children, {}, { "command", "comment", "enum", "type" } );
11882
11883 for ( auto child : children )
11884 {
11885 std::string value = child->Value();
11886 if ( value == "command" )
11887 {
11888 readRequireCommandSkipped( child );
11889 }
11890 else if ( value == "type" )
11891 {
11892 readRequireTypeSkipped( child );
11893 }
11894 }
11895 }
11896
readExtensionsExtensionRequireType(tinyxml2::XMLElement const * element,std::string const & extensionName,RequireData & requireData)11897 void VulkanHppGenerator::readExtensionsExtensionRequireType( tinyxml2::XMLElement const * element,
11898 std::string const & extensionName,
11899 RequireData & requireData )
11900 {
11901 int line = element->GetLineNum();
11902 std::map<std::string, std::string> attributes = getAttributes( element );
11903 checkAttributes( line, attributes, { { "name", {} } }, { { "comment", {} } } );
11904 checkElements( line, getChildElements( element ), {} );
11905
11906 std::string name;
11907 for ( auto const & attribute : attributes )
11908 {
11909 if ( attribute.first == "name" )
11910 {
11911 name = attribute.second;
11912 }
11913 }
11914 assert( !name.empty() );
11915
11916 auto typeIt = m_types.find( name );
11917 checkForError( typeIt != m_types.end(), line, "failed to find required type <" + name + ">" );
11918 if ( typeIt->second.referencedIn.empty() )
11919 {
11920 typeIt->second.referencedIn = extensionName;
11921 assert( std::find( requireData.types.begin(), requireData.types.end(), name ) == requireData.types.end() );
11922 requireData.types.push_back( name );
11923 }
11924 else
11925 {
11926 checkForError( getPlatform( typeIt->second.referencedIn ) == getPlatform( extensionName ),
11927 line,
11928 "type <" + name + "> is referenced in extensions <" + typeIt->second.referencedIn + "> and <" + extensionName +
11929 "> and thus protected by different platforms <" + getPlatform( typeIt->second.referencedIn ) + "> and <" + getPlatform( extensionName ) +
11930 ">!" );
11931 }
11932 }
11933
readFeature(tinyxml2::XMLElement const * element)11934 void VulkanHppGenerator::readFeature( tinyxml2::XMLElement const * element )
11935 {
11936 int line = element->GetLineNum();
11937 std::map<std::string, std::string> attributes = getAttributes( element );
11938 checkAttributes( line, attributes, { { "api", { "vulkan", "vulkansc" } }, { "comment", {} }, { "name", {} }, { "number", {} } }, {} );
11939 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
11940 checkElements( line, children, { { "require", false } }, { "remove" } );
11941
11942 std::string name, number, modifiedNumber;
11943 for ( auto const & attribute : attributes )
11944 {
11945 if ( attribute.first == "name" )
11946 {
11947 name = attribute.second;
11948 }
11949 else if ( attribute.first == "number" )
11950 {
11951 number = attribute.second;
11952 modifiedNumber = number;
11953 std::replace( modifiedNumber.begin(), modifiedNumber.end(), '.', '_' );
11954 }
11955 }
11956 assert( !name.empty() && !number.empty() );
11957
11958 auto attributeIt = attributes.find( "api" );
11959 assert( attributeIt != attributes.end() );
11960 std::vector<std::string> api = tokenize( attributeIt->second, "," );
11961 if ( std::find( api.begin(), api.end(), "vulkan" ) != api.end() )
11962 {
11963 checkForError( name == "VK_VERSION_" + modifiedNumber, line, "unexpected formatting of name <" + name + ">" );
11964 checkForError( m_features.find( name ) == m_features.end(), line, "already specified feature <" + name + ">" );
11965 assert( m_skippedFeatures.find( name ) == m_skippedFeatures.end() );
11966
11967 auto featureIt = m_features.insert( std::make_pair( name, number ) ).first;
11968 for ( auto child : children )
11969 {
11970 std::string value = child->Value();
11971 if ( value == "remove" )
11972 {
11973 checkForError( false, line, "unsupported child <remove>: should be filtered by attribute <api>" );
11974 }
11975 else if ( value == "require" )
11976 {
11977 readFeatureRequire( child, featureIt );
11978 }
11979 }
11980 }
11981 else
11982 {
11983 // skip this feature
11984 checkForError( name == "VKSC_VERSION_" + modifiedNumber, line, "unexpected formatting of name <" + name + ">" );
11985 checkForError( m_skippedFeatures.insert( name ).second, line, "already specified skipped feature <" + name + ">" );
11986 assert( m_features.find( name ) == m_features.end() );
11987
11988 for ( auto child : children )
11989 {
11990 std::string value = child->Value();
11991 if ( value == "require" )
11992 {
11993 readFeatureRequireSkipped( child );
11994 }
11995 }
11996 }
11997 }
11998
readFeatureRequire(tinyxml2::XMLElement const * element,std::map<std::string,FeatureData>::iterator featureIt)11999 void VulkanHppGenerator::readFeatureRequire( tinyxml2::XMLElement const * element, std::map<std::string, FeatureData>::iterator featureIt )
12000 {
12001 int line = element->GetLineNum();
12002 checkAttributes( line, getAttributes( element ), {}, { { "comment", {} } } );
12003 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12004 checkElements( line, children, {}, { "command", "comment", "enum", "type" } );
12005
12006 RequireData requireData( line, { "" } );
12007 bool requireDataEmpty = true;
12008 for ( auto child : children )
12009 {
12010 std::string value = child->Value();
12011 if ( value == "command" )
12012 {
12013 readFeatureRequireCommand( child, featureIt, requireData );
12014 requireDataEmpty = false;
12015 }
12016 else if ( value == "comment" )
12017 {
12018 readComment( child );
12019 }
12020 else if ( value == "enum" )
12021 {
12022 readRequireEnum( child, "" );
12023 }
12024 else if ( value == "type" )
12025 {
12026 readFeatureRequireType( child, featureIt, requireData );
12027 requireDataEmpty = false;
12028 }
12029 }
12030 if ( !requireDataEmpty )
12031 {
12032 featureIt->second.requireData.push_back( requireData );
12033 }
12034 }
12035
readFeatureRequireCommandSkipped(tinyxml2::XMLElement const * element)12036 void VulkanHppGenerator::readFeatureRequireCommandSkipped( tinyxml2::XMLElement const * element )
12037 {
12038 int line = element->GetLineNum();
12039 std::map<std::string, std::string> attributes = getAttributes( element );
12040 checkAttributes( line, attributes, {}, { { "name", {} } } );
12041
12042 std::string name = attributes.find( "name" )->second;
12043
12044 auto commandIt = m_commands.find( name );
12045 checkForError( commandIt != m_commands.end(), line, "unknown required command <" + name + ">" );
12046 checkForError( commandIt->second.referencedIn.empty(), line, "command <" + name + "> already listed with feature <" + commandIt->second.referencedIn + ">" );
12047
12048 m_commands.erase( commandIt );
12049 }
12050
readFeatureRequireCommand(tinyxml2::XMLElement const * element,std::map<std::string,FeatureData>::iterator featureIt,RequireData & requireData)12051 void VulkanHppGenerator::readFeatureRequireCommand( tinyxml2::XMLElement const * element,
12052 std::map<std::string, FeatureData>::iterator featureIt,
12053 RequireData & requireData )
12054 {
12055 int line = element->GetLineNum();
12056 std::map<std::string, std::string> attributes = getAttributes( element );
12057 checkAttributes( line, attributes, {}, { { "name", {} } } );
12058
12059 std::string name = attributes.find( "name" )->second;
12060
12061 auto commandIt = m_commands.find( name );
12062 checkForError( commandIt != m_commands.end(), line, "feature <" + featureIt->first + "> requires unknown command <" + name + ">" );
12063 checkForError( commandIt->second.referencedIn.empty(), line, "command <" + name + "> already listed with feature <" + commandIt->second.referencedIn + ">" );
12064
12065 commandIt->second.referencedIn = featureIt->first;
12066
12067 assert( std::find( requireData.commands.begin(), requireData.commands.end(), name ) == requireData.commands.end() );
12068 requireData.commands.push_back( name );
12069 }
12070
readFeatureRequireSkipped(tinyxml2::XMLElement const * element)12071 void VulkanHppGenerator::readFeatureRequireSkipped( tinyxml2::XMLElement const * element )
12072 {
12073 int line = element->GetLineNum();
12074 checkAttributes( line, getAttributes( element ), {}, { { "comment", {} } } );
12075 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12076 checkElements( line, children, {}, { "command", "comment", "enum", "type" } );
12077
12078 for ( auto child : children )
12079 {
12080 std::string value = child->Value();
12081 if ( value == "command" )
12082 {
12083 readFeatureRequireCommandSkipped( child );
12084 }
12085 else if ( value == "enum" )
12086 {
12087 readRequireEnumSkipped( child );
12088 }
12089 else if ( value == "type" )
12090 {
12091 readRequireTypeSkipped( child );
12092 }
12093 }
12094 }
12095
readFeatureRequireType(tinyxml2::XMLElement const * element,std::map<std::string,FeatureData>::iterator featureIt,RequireData & requireData)12096 void VulkanHppGenerator::readFeatureRequireType( tinyxml2::XMLElement const * element,
12097 std::map<std::string, FeatureData>::iterator featureIt,
12098 RequireData & requireData )
12099 {
12100 int line = element->GetLineNum();
12101 std::map<std::string, std::string> attributes = getAttributes( element );
12102 checkAttributes( line, attributes, {}, { { "comment", {} }, { "name", {} } } );
12103 checkElements( line, getChildElements( element ), {} );
12104
12105 std::string name = attributes.find( "name" )->second;
12106 auto requireTypeIt = std::find_if( requireData.types.begin(), requireData.types.end(), [&name]( std::string const & type ) { return type == name; } );
12107 checkForError( requireTypeIt == requireData.types.end(), line, "type <" + name + "> already listed for this feature!" );
12108
12109 // some types are in fact includes (like vk_platform) or defines (like VK_API_VERSION)
12110 if ( ( m_defines.find( name ) == m_defines.end() ) && ( m_includes.find( name ) == m_includes.end() ) )
12111 {
12112 auto typeIt = m_types.find( name );
12113 checkForError( typeIt != m_types.end(), line, "feature <" + featureIt->first + "> requires unknown type <" + name + ">" );
12114 checkForError( typeIt->second.referencedIn.empty() || ( typeIt->second.referencedIn == featureIt->first ),
12115 line,
12116 "type <" + name + "> already listed on feature <" + typeIt->second.referencedIn + ">" );
12117 typeIt->second.referencedIn = featureIt->first;
12118
12119 requireData.types.push_back( name );
12120 }
12121 }
12122
readFormats(tinyxml2::XMLElement const * element)12123 void VulkanHppGenerator::readFormats( tinyxml2::XMLElement const * element )
12124 {
12125 int line = element->GetLineNum();
12126 checkAttributes( line, getAttributes( element ), {}, {} );
12127 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12128 checkElements( line, children, { { "format", false } } );
12129
12130 for ( auto child : children )
12131 {
12132 readFormatsFormat( child );
12133 }
12134 }
12135
readFormatsFormat(tinyxml2::XMLElement const * element)12136 void VulkanHppGenerator::readFormatsFormat( tinyxml2::XMLElement const * element )
12137 {
12138 int line = element->GetLineNum();
12139 std::map<std::string, std::string> attributes = getAttributes( element );
12140 checkAttributes( line,
12141 attributes,
12142 { { "blockSize", { "1", "2", "3", "4", "5", "6", "8", "12", "16", "24", "32" } },
12143 { "class", {} },
12144 { "name", {} },
12145 { "texelsPerBlock", { "1", "16", "20", "25", "30", "36", "40", "48", "50", "60", "64", "80", "100", "120", "144" } } },
12146 { { "blockExtent", { "1", "2", "4", "5", "6", "8", "10", "12" } },
12147 { "chroma", { "420", "422", "444" } },
12148 { "compressed", { "ASTC HDR", "ASTC LDR", "BC", "EAC", "ETC", "ETC2", "PVRTC" } },
12149 { "packed", { "8", "16", "32" } } } );
12150 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12151 checkElements( line, children, { { "component", false } }, { "plane", "spirvimageformat" } );
12152
12153 FormatData format( line );
12154 std::string name;
12155 for ( auto const & attribute : attributes )
12156 {
12157 if ( attribute.first == "blockExtent" )
12158 {
12159 checkForError( tokenize( attribute.second, "," ).size() == 3, line, "unexpected number of elements in attribute <blockExtent>" );
12160 format.blockExtent = attribute.second;
12161 }
12162 if ( attribute.first == "blockSize" )
12163 {
12164 format.blockSize = attribute.second;
12165 }
12166 else if ( attribute.first == "chroma" )
12167 {
12168 format.chroma = attribute.second;
12169 }
12170 else if ( attribute.first == "class" )
12171 {
12172 format.classAttribute = attribute.second;
12173 }
12174 else if ( attribute.first == "compressed" )
12175 {
12176 format.compressed = attribute.second;
12177 }
12178 else if ( attribute.first == "name" )
12179 {
12180 name = attribute.second;
12181 }
12182 else if ( attribute.first == "packed" )
12183 {
12184 format.packed = attribute.second;
12185 }
12186 else if ( attribute.first == "texelsPerBlock" )
12187 {
12188 format.texelsPerBlock = attribute.second;
12189 }
12190 }
12191
12192 auto formatIt = m_enums.find( "VkFormat" );
12193 assert( formatIt != m_enums.end() );
12194
12195 checkForError( std::find_if( formatIt->second.values.begin(),
12196 formatIt->second.values.end(),
12197 [&name]( EnumValueData const & evd ) { return evd.name == name; } ) != formatIt->second.values.end() ||
12198 ( formatIt->second.aliases.find( name ) != formatIt->second.aliases.end() ),
12199 line,
12200 "encountered unknown format <" + name + ">" );
12201 auto [it, inserted] = m_formats.insert( std::make_pair( name, format ) );
12202 checkForError( inserted, line, "format <" + name + "> already specified on line " + std::to_string( it->second.xmlLine ) );
12203
12204 for ( auto child : children )
12205 {
12206 std::string value = child->Value();
12207 if ( value == "component" )
12208 {
12209 readFormatsFormatComponent( child, it->second );
12210 }
12211 else if ( value == "plane" )
12212 {
12213 readFormatsFormatPlane( child, it->second );
12214 }
12215 else if ( value == "spirvimageformat" )
12216 {
12217 readFormatsFormatSPIRVImageFormat( child, it->second );
12218 }
12219 }
12220
12221 if ( it->second.components.front().bits == "compressed" )
12222 {
12223 for ( auto componentIt = std::next( it->second.components.begin() ); componentIt != it->second.components.end(); ++componentIt )
12224 {
12225 checkForError( componentIt->bits == "compressed", line, "component is expected to be marked as compressed in attribute <bits>" );
12226 }
12227 }
12228 if ( !it->second.components.front().planeIndex.empty() )
12229 {
12230 for ( auto componentIt = std::next( it->second.components.begin() ); componentIt != it->second.components.end(); ++componentIt )
12231 {
12232 checkForError( !componentIt->planeIndex.empty(), line, "component is expected to have a planeIndex" );
12233 }
12234 size_t planeCount = 1 + std::stoi( it->second.components.back().planeIndex );
12235 checkForError( it->second.planes.size() == planeCount, line, "number of planes does not fit to largest planeIndex of the components" );
12236 }
12237 }
12238
readFormatsFormatComponent(tinyxml2::XMLElement const * element,FormatData & formatData)12239 void VulkanHppGenerator::readFormatsFormatComponent( tinyxml2::XMLElement const * element, FormatData & formatData )
12240 {
12241 int line = element->GetLineNum();
12242 std::map<std::string, std::string> attributes = getAttributes( element );
12243 checkAttributes( line,
12244 attributes,
12245 { { "bits", { "1", "2", "4", "5", "6", "8", "9", "10", "11", "12", "16", "24", "32", "64", "compressed" } },
12246 { "name", {} },
12247 { "numericFormat", { "SFLOAT", "SINT", "SNORM", "SRGB", "SSCALED", "UFLOAT", "UINT", "UNORM", "USCALED" } } },
12248 { { "planeIndex", { "0", "1", "2" } } } );
12249 checkElements( line, getChildElements( element ), {} );
12250
12251 formatData.components.emplace_back( line );
12252 ComponentData & component = formatData.components.back();
12253 for ( auto const & attribute : attributes )
12254 {
12255 if ( attribute.first == "bits" )
12256 {
12257 checkForError(
12258 ( attribute.second != "compressed" ) || !formatData.compressed.empty(), line, "component of a not compressed format is marked as compressed" );
12259 component.bits = attribute.second;
12260 }
12261 else if ( attribute.first == "name" )
12262 {
12263 component.name = attribute.second;
12264 }
12265 else if ( attribute.first == "numericFormat" )
12266 {
12267 component.numericFormat = attribute.second;
12268 }
12269 else if ( attribute.first == "planeIndex" )
12270 {
12271 component.planeIndex = attribute.second;
12272 }
12273 }
12274 }
12275
readFormatsFormatPlane(tinyxml2::XMLElement const * element,FormatData & formatData)12276 void VulkanHppGenerator::readFormatsFormatPlane( tinyxml2::XMLElement const * element, FormatData & formatData )
12277 {
12278 int line = element->GetLineNum();
12279 std::map<std::string, std::string> attributes = getAttributes( element );
12280 checkAttributes(
12281 line, attributes, { { "compatible", {} }, { "index", { "0", "1", "2" } }, { "heightDivisor", { "1", "2" } }, { "widthDivisor", { "1", "2" } } }, {} );
12282 checkElements( line, getChildElements( element ), {} );
12283
12284 formatData.planes.emplace_back( line );
12285 PlaneData & plane = formatData.planes.back();
12286 for ( auto const & attribute : attributes )
12287 {
12288 if ( attribute.first == "compatible" )
12289 {
12290 plane.compatible = attribute.second;
12291 auto formatIt = m_enums.find( "VkFormat" );
12292 assert( formatIt != m_enums.end() );
12293 checkForError( std::find_if( formatIt->second.values.begin(),
12294 formatIt->second.values.end(),
12295 [&plane]( EnumValueData const & evd ) { return evd.name == plane.compatible; } ) != formatIt->second.values.end(),
12296 line,
12297 "encountered unknown format <" + plane.compatible + ">" );
12298 }
12299 else if ( attribute.first == "index" )
12300 {
12301 size_t index = std::stoi( attribute.second );
12302 checkForError( index + 1 == formatData.planes.size(), line, "unexpected index <" + attribute.second + ">" );
12303 }
12304 else if ( attribute.first == "heightDivisor" )
12305 {
12306 plane.heightDivisor = attribute.second;
12307 }
12308 else if ( attribute.first == "widthDivisor" )
12309 {
12310 plane.widthDivisor = attribute.second;
12311 }
12312 }
12313 }
12314
readFormatsFormatSPIRVImageFormat(tinyxml2::XMLElement const * element,FormatData & formatData)12315 void VulkanHppGenerator::readFormatsFormatSPIRVImageFormat( tinyxml2::XMLElement const * element, FormatData & formatData )
12316 {
12317 int line = element->GetLineNum();
12318 std::map<std::string, std::string> attributes = getAttributes( element );
12319 checkAttributes( line, attributes, { { "name", {} } }, {} );
12320 checkElements( line, getChildElements( element ), {} );
12321
12322 for ( auto const & attribute : attributes )
12323 {
12324 assert( attribute.first == "name" );
12325 checkForError( formatData.spirvImageFormat.empty(), line, "spirvimageformat <" + attribute.second + "> already specified" );
12326 formatData.spirvImageFormat = attribute.second;
12327 }
12328 }
12329
readNameAndType(tinyxml2::XMLElement const * element)12330 std::pair<VulkanHppGenerator::NameData, VulkanHppGenerator::TypeInfo> VulkanHppGenerator::readNameAndType( tinyxml2::XMLElement const * element )
12331 {
12332 int line = element->GetLineNum();
12333 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12334 checkElements( line, children, { { "name", true } }, { { "enum" }, { "type" } } );
12335
12336 NameData nameData;
12337 TypeInfo typeInfo;
12338 for ( auto child : children )
12339 {
12340 line = child->GetLineNum();
12341 checkAttributes( line, getAttributes( child ), {}, {} );
12342 checkElements( line, getChildElements( child ), {} );
12343
12344 std::string value = child->Value();
12345 if ( value == "enum" )
12346 {
12347 nameData.arraySizes.push_back( child->GetText() );
12348 checkForError( child->PreviousSibling() && ( strcmp( child->PreviousSibling()->Value(), "[" ) == 0 ) && child->NextSibling() &&
12349 ( strcmp( child->NextSibling()->Value(), "]" ) == 0 ),
12350 line,
12351 std::string( "array specifiation is ill-formatted: <" ) + nameData.arraySizes.back() + ">" );
12352 checkForError(
12353 m_constants.find( nameData.arraySizes.back() ) != m_constants.end(), line, "using unknown enum value <" + nameData.arraySizes.back() + ">" );
12354 }
12355 else if ( value == "name" )
12356 {
12357 nameData.name = child->GetText();
12358 std::string bitCount;
12359 std::tie( nameData.arraySizes, bitCount ) = readModifiers( child->NextSibling() );
12360 checkForError( bitCount.empty(), line, "name <" + nameData.name + "> with unsupported bitCount <" + bitCount + ">" );
12361 }
12362 else if ( value == "type" )
12363 {
12364 typeInfo = readTypeInfo( child );
12365 }
12366 }
12367 return std::make_pair( nameData, typeInfo );
12368 }
12369
readPlatforms(tinyxml2::XMLElement const * element)12370 void VulkanHppGenerator::readPlatforms( tinyxml2::XMLElement const * element )
12371 {
12372 int line = element->GetLineNum();
12373 checkAttributes( line, getAttributes( element ), { { "comment", {} } }, {} );
12374 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12375 checkElements( line, children, { { "platform", false } } );
12376
12377 for ( auto child : children )
12378 {
12379 readPlatformsPlatform( child );
12380 }
12381 }
12382
readPlatformsPlatform(tinyxml2::XMLElement const * element)12383 void VulkanHppGenerator::readPlatformsPlatform( tinyxml2::XMLElement const * element )
12384 {
12385 int line = element->GetLineNum();
12386 std::map<std::string, std::string> attributes = getAttributes( element );
12387 checkAttributes( line, attributes, { { "comment", {} }, { "name", {} }, { "protect", {} } }, {} );
12388 checkElements( line, getChildElements( element ), {} );
12389
12390 std::string name, protect;
12391 for ( auto const & attribute : attributes )
12392 {
12393 if ( attribute.first == "name" )
12394 {
12395 name = attribute.second;
12396 checkForError( !name.empty(), line, "attribute <name> is empty" );
12397 }
12398 else if ( attribute.first == "protect" )
12399 {
12400 protect = attribute.second;
12401 checkForError( !protect.empty(), line, "attribute <protect> is empty" );
12402 }
12403 }
12404 assert( !name.empty() && !protect.empty() );
12405
12406 checkForError( std::find_if( m_platforms.begin(),
12407 m_platforms.end(),
12408 [&protect]( std::pair<std::string, PlatformData> const & p ) { return p.second.protect == protect; } ) == m_platforms.end(),
12409 line,
12410 "platform protect <" + protect + "> already specified" );
12411 checkForError( m_platforms.insert( std::make_pair( name, PlatformData( protect ) ) ).second, line, "platform name <" + name + "> already specified" );
12412 }
12413
readRegistry(tinyxml2::XMLElement const * element)12414 void VulkanHppGenerator::readRegistry( tinyxml2::XMLElement const * element )
12415 {
12416 int line = element->GetLineNum();
12417 checkAttributes( line, getAttributes( element ), {}, {} );
12418
12419 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12420 checkElements( line,
12421 children,
12422 { { "commands", true },
12423 { "comment", false },
12424 { "enums", false },
12425 { "extensions", true },
12426 { "feature", false },
12427 { "platforms", true },
12428 { "spirvcapabilities", true },
12429 { "spirvextensions", true },
12430 { "tags", true },
12431 { "types", true } },
12432 { "formats" } );
12433 for ( auto child : children )
12434 {
12435 const std::string value = child->Value();
12436 if ( value == "commands" )
12437 {
12438 readCommands( child );
12439 }
12440 else if ( value == "comment" )
12441 {
12442 std::string comment = readComment( child );
12443 if ( comment.find( "\nCopyright" ) == 0 )
12444 {
12445 setVulkanLicenseHeader( child->GetLineNum(), comment );
12446 }
12447 }
12448 else if ( value == "enums" )
12449 {
12450 readEnums( child );
12451 }
12452 else if ( value == "extensions" )
12453 {
12454 readExtensions( child );
12455 }
12456 else if ( value == "feature" )
12457 {
12458 readFeature( child );
12459 }
12460 else if ( value == "formats" )
12461 {
12462 readFormats( child );
12463 }
12464 else if ( value == "platforms" )
12465 {
12466 readPlatforms( child );
12467 }
12468 else if ( value == "spirvcapabilities" )
12469 {
12470 readSPIRVCapabilities( child );
12471 }
12472 else if ( value == "spirvextensions" )
12473 {
12474 readSPIRVExtensions( child );
12475 }
12476 else if ( value == "tags" )
12477 {
12478 readTags( child );
12479 }
12480 else if ( value == "types" )
12481 {
12482 readTypes( child );
12483 }
12484 }
12485 }
12486
readRequireCommandSkipped(tinyxml2::XMLElement const * element)12487 void VulkanHppGenerator::readRequireCommandSkipped( tinyxml2::XMLElement const * element )
12488 {
12489 int line = element->GetLineNum();
12490 std::map<std::string, std::string> attributes = getAttributes( element );
12491 checkAttributes( line, attributes, { { "name", {} } }, { { "comment", {} } } );
12492 checkElements( line, getChildElements( element ), {} );
12493
12494 std::string name = attributes.find( "name" )->second;
12495
12496 // some commands might be skipped by multiple extensions!
12497 auto commandIt = m_commands.find( name );
12498 if ( commandIt != m_commands.end() )
12499 {
12500 checkForError( m_skippedCommands.insert( name ).second, line, "to be skipped command <" + name + "> is already marked as skipped" );
12501 m_commands.erase( commandIt );
12502 }
12503 else
12504 {
12505 checkForError( m_skippedCommands.find( name ) != m_skippedCommands.end(),
12506 line,
12507 "to be skipped command <" + name + "> is neither listed as command nor as skipped command" );
12508 }
12509 }
12510
readRequireEnum(tinyxml2::XMLElement const * element,std::string const & extensionName)12511 void VulkanHppGenerator::readRequireEnum( tinyxml2::XMLElement const * element, std::string const & extensionName )
12512 {
12513 int line = element->GetLineNum();
12514 std::map<std::string, std::string> attributes = getAttributes( element );
12515 if ( attributes.find( "alias" ) != attributes.end() )
12516 {
12517 checkAttributes( line, attributes, { { "alias", {} }, { "name", {} } }, { { "api", { "vulkan", "vulkansc" } }, { "comment", {} }, { "extends", {} } } );
12518 checkElements( line, getChildElements( element ), {} );
12519
12520 std::string alias, bitpos, name, extends, extnumber, offset, value;
12521 for ( auto const & attribute : attributes )
12522 {
12523 if ( attribute.first == "alias" )
12524 {
12525 alias = attribute.second;
12526 }
12527 if ( attribute.first == "api" )
12528 {
12529 if ( attribute.second == "vulkansc" )
12530 {
12531 return; // skip stuff marked as "vulkansc" !
12532 }
12533 assert( attribute.second == "vulkan" );
12534 }
12535 else if ( attribute.first == "extends" )
12536 {
12537 extends = attribute.second;
12538 }
12539 else if ( attribute.first == "name" )
12540 {
12541 name = attribute.second;
12542 }
12543 }
12544
12545 if ( !extends.empty() )
12546 {
12547 auto enumIt = m_enums.find( extends );
12548 checkForError( enumIt != m_enums.end(), line, "feature extends unknown enum <" + extends + ">" );
12549
12550 // add this enum name to the list of aliases
12551 enumIt->second.addEnumAlias( line, name, alias );
12552 }
12553 }
12554 else
12555 {
12556 checkAttributes( line,
12557 attributes,
12558 { { "name", {} } },
12559 { { "api", { "vulkan", "vulkansc" } },
12560 { "bitpos", {} },
12561 { "comment", {} },
12562 { "extends", {} },
12563 { "dir", { "-" } },
12564 { "extnumber", {} },
12565 { "offset", {} },
12566 { "protect", { "VK_ENABLE_BETA_EXTENSIONS" } },
12567 { "value", {} } } );
12568 checkElements( line, getChildElements( element ), {} );
12569
12570 std::string bitpos, name, extends, offset, protect, value;
12571 for ( auto const & attribute : attributes )
12572 {
12573 if ( attribute.first == "api" )
12574 {
12575 if ( attribute.second == "vulkansc" )
12576 {
12577 return; // skip stuff marked as "vulkansc" !
12578 }
12579 assert( attribute.second == "vulkan" );
12580 }
12581 else if ( attribute.first == "bitpos" )
12582 {
12583 bitpos = attribute.second;
12584 }
12585 else if ( attribute.first == "extends" )
12586 {
12587 extends = attribute.second;
12588 }
12589 else if ( attribute.first == "name" )
12590 {
12591 name = attribute.second;
12592 }
12593 else if ( attribute.first == "offset" )
12594 {
12595 offset = attribute.second;
12596 }
12597 else if ( attribute.first == "protect" )
12598 {
12599 protect = attribute.second;
12600 }
12601 else if ( attribute.first == "value" )
12602 {
12603 value = attribute.second;
12604 }
12605 }
12606
12607 if ( !extends.empty() )
12608 {
12609 auto enumIt = m_enums.find( extends );
12610 if ( enumIt == m_enums.end() )
12611 {
12612 // need to re-add a previously removed enum !!
12613 enumIt = m_skippedEnums.find( extends );
12614 checkForError( enumIt != m_skippedEnums.end(), line, "feature extends unknown enum <" + extends + ">" );
12615 enumIt = m_enums.insert( *enumIt ).first;
12616
12617 auto typeIt = m_skippedTypes.find( extends );
12618 assert( ( m_types.find( extends ) == m_types.end() ) || ( typeIt != m_skippedTypes.end() ) );
12619 typeIt->second.referencedIn = extensionName;
12620 m_types[extends] = typeIt->second;
12621 m_skippedTypes.erase( typeIt );
12622 }
12623
12624 // add this enum name to the list of values
12625 checkForError( bitpos.empty() + offset.empty() + value.empty() == 2,
12626 line,
12627 "exactly one out of bitpos = <" + bitpos + ">, offset = <" + offset + ">, and value = <" + value + "> are supposed to be empty" );
12628 enumIt->second.addEnumValue( element->GetLineNum(), name, protect, !bitpos.empty(), extensionName );
12629 }
12630 else if ( value.empty() )
12631 {
12632 checkForError( m_constants.find( name ) != m_constants.end(), line, "unknown required enum <" + name + ">" );
12633 }
12634 }
12635 }
12636
readRequireEnumSkipped(tinyxml2::XMLElement const * element)12637 void VulkanHppGenerator::readRequireEnumSkipped( tinyxml2::XMLElement const * element )
12638 {
12639 int line = element->GetLineNum();
12640 std::map<std::string, std::string> attributes = getAttributes( element );
12641 checkAttributes( line,
12642 attributes,
12643 { { "name", {} } },
12644 { { "alias", {} },
12645 { "bitpos", {} },
12646 { "comment", {} },
12647 { "extends", {} },
12648 { "dir", { "-" } },
12649 { "extnumber", {} },
12650 { "offset", {} },
12651 { "protect", {} },
12652 { "value", {} } } );
12653 checkElements( line, getChildElements( element ), {} );
12654
12655 std::string extends, name;
12656 for ( auto const & attribute : attributes )
12657 {
12658 if ( attribute.first == "extends" )
12659 {
12660 extends = attribute.second;
12661 }
12662 else if ( attribute.first == "name" )
12663 {
12664 name = attribute.second;
12665 }
12666 }
12667 assert( !name.empty() );
12668
12669 if ( extends == "VkResult" )
12670 {
12671 // check that the to be skipped enum value is not already listed
12672 auto enumIt = m_enums.find( extends );
12673 assert( enumIt != m_enums.end() );
12674 auto valueIt =
12675 std::find_if( enumIt->second.values.begin(), enumIt->second.values.end(), [&name]( EnumValueData const & evd ) { return evd.name == name; } );
12676 checkForError( valueIt == enumIt->second.values.end(),
12677 line,
12678 "to be skipped enum value <" + name + "> extending enum <" + extends + "> is regularly specified for that enum" );
12679
12680 // look for all the errorCodes (and successCodes) and remove this enum value!
12681 for ( auto & command : m_commands )
12682 {
12683 auto errorCodeIt = std::find( command.second.errorCodes.begin(), command.second.errorCodes.end(), name );
12684 if ( errorCodeIt != command.second.errorCodes.end() )
12685 {
12686 command.second.errorCodes.erase( errorCodeIt );
12687 }
12688 assert( std::find( command.second.successCodes.begin(), command.second.successCodes.end(), name ) == command.second.successCodes.end() );
12689 }
12690 }
12691 }
12692
readRequireTypeSkipped(tinyxml2::XMLElement const * element)12693 void VulkanHppGenerator::readRequireTypeSkipped( tinyxml2::XMLElement const * element )
12694 {
12695 int line = element->GetLineNum();
12696 std::map<std::string, std::string> attributes = getAttributes( element );
12697 checkAttributes( line, attributes, { { "name", {} } }, { { "comment", {} } } );
12698 checkElements( line, getChildElements( element ), {} );
12699
12700 std::string name = attributes.find( "name" )->second;
12701
12702 // some types are not really types, but defines
12703 auto typeIt = m_types.find( name );
12704 if ( typeIt != m_types.end() )
12705 {
12706 assert( typeIt->second.referencedIn.empty() );
12707 assert( m_skippedTypes.find( name ) == m_skippedTypes.end() );
12708
12709 switch ( typeIt->second.category )
12710 {
12711 case TypeCategory::Bitmask:
12712 assert( m_bitmasks.find( name ) != m_bitmasks.end() );
12713 m_bitmasks.erase( name );
12714 break;
12715 case TypeCategory::Enum:
12716 {
12717 auto enumIt = m_enums.find( name );
12718 assert( enumIt != m_enums.end() );
12719 assert( m_skippedEnums.find( name ) == m_skippedEnums.end() );
12720 m_skippedEnums[name] = enumIt->second;
12721 m_enums.erase( enumIt );
12722 }
12723 break;
12724 case TypeCategory::FuncPointer:
12725 assert( m_funcPointers.find( name ) != m_funcPointers.end() );
12726 m_funcPointers.erase( name );
12727 break;
12728 case TypeCategory::Handle:
12729 assert( m_handles.find( name ) != m_handles.end() );
12730 m_handles.erase( name );
12731 break;
12732 case TypeCategory::Struct:
12733 assert( m_structures.find( name ) != m_structures.end() );
12734 m_structures.erase( name );
12735 break;
12736 default: assert( false ); break;
12737 }
12738
12739 m_skippedTypes[name] = typeIt->second;
12740 m_types.erase( typeIt );
12741 }
12742 }
12743
readSPIRVCapabilities(tinyxml2::XMLElement const * element)12744 void VulkanHppGenerator::readSPIRVCapabilities( tinyxml2::XMLElement const * element )
12745 {
12746 int line = element->GetLineNum();
12747 std::map<std::string, std::string> attributes = getAttributes( element );
12748 checkAttributes( line, attributes, { { "comment", {} } }, {} );
12749 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12750 checkElements( line, children, {}, { "spirvcapability" } );
12751
12752 for ( auto child : children )
12753 {
12754 assert( child->Value() == std::string( "spirvcapability" ) );
12755 readSPIRVCapabilitiesSPIRVCapability( child );
12756 }
12757 }
12758
readSPIRVCapabilitiesSPIRVCapability(tinyxml2::XMLElement const * element)12759 void VulkanHppGenerator::readSPIRVCapabilitiesSPIRVCapability( tinyxml2::XMLElement const * element )
12760 {
12761 int line = element->GetLineNum();
12762 std::map<std::string, std::string> attributes = getAttributes( element );
12763 checkAttributes( line, attributes, { { "name", {} } }, {} );
12764 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12765 checkElements( line, children, {}, { "enable" } );
12766
12767 for ( auto child : children )
12768 {
12769 assert( child->Value() == std::string( "enable" ) );
12770 readSPIRVCapabilitiesSPIRVCapabilityEnable( child );
12771 }
12772 }
12773
readSPIRVCapabilitiesSPIRVCapabilityEnable(tinyxml2::XMLElement const * element)12774 void VulkanHppGenerator::readSPIRVCapabilitiesSPIRVCapabilityEnable( tinyxml2::XMLElement const * element )
12775 {
12776 int line = element->GetLineNum();
12777 std::map<std::string, std::string> attributes = getAttributes( element );
12778 checkElements( line, getChildElements( element ), {}, {} );
12779
12780 if ( attributes.find( "extension" ) != attributes.end() )
12781 {
12782 readSPIRVCapabilitiesSPIRVCapabilityEnableExtension( line, attributes );
12783 }
12784 else if ( attributes.find( "property" ) != attributes.end() )
12785 {
12786 readSPIRVCapabilitiesSPIRVCapabilityEnableProperty( line, attributes );
12787 }
12788 else if ( attributes.find( "struct" ) != attributes.end() )
12789 {
12790 readSPIRVCapabilitiesSPIRVCapabilityEnableStruct( line, attributes );
12791 }
12792 else if ( attributes.find( "version" ) != attributes.end() )
12793 {
12794 readSPIRVCapabilitiesSPIRVCapabilityEnableVersion( line, attributes );
12795 }
12796 else
12797 {
12798 checkForError( false, line, "unknown set of attributes specified for SPIR-V capability" );
12799 }
12800 }
12801
readSPIRVCapabilitiesSPIRVCapabilityEnableExtension(int xmlLine,std::map<std::string,std::string> const & attributes)12802 void VulkanHppGenerator::readSPIRVCapabilitiesSPIRVCapabilityEnableExtension( int xmlLine, std::map<std::string, std::string> const & attributes )
12803 {
12804 checkAttributes( xmlLine, attributes, { { "extension", {} } }, {} );
12805
12806 checkForError( attributes.size() == 1, xmlLine, "unexpected attributes in addition to <extension> specified for SPIR-V capability" );
12807 for ( auto const & attribute : attributes )
12808 {
12809 assert( attribute.first == "extension" );
12810 checkForError(
12811 m_extensions.find( attribute.second ) != m_extensions.end(), xmlLine, "unknown extension <" + attribute.second + "> specified for SPIR-V capability" );
12812 }
12813 }
12814
readSPIRVCapabilitiesSPIRVCapabilityEnableProperty(int xmlLine,std::map<std::string,std::string> const & attributes)12815 void VulkanHppGenerator::readSPIRVCapabilitiesSPIRVCapabilityEnableProperty( int xmlLine, std::map<std::string, std::string> const & attributes )
12816 {
12817 checkAttributes( xmlLine, attributes, { { "member", {} }, { "property", {} }, { "requires", {} }, { "value", {} } }, {} );
12818
12819 std::string member, property, value;
12820 for ( auto const & attribute : attributes )
12821 {
12822 if ( attribute.first == "member" )
12823 {
12824 member = attribute.second;
12825 }
12826 else if ( attribute.first == "property" )
12827 {
12828 property = attribute.second;
12829 }
12830 if ( attribute.first == "requires" )
12831 {
12832 std::vector<std::string> requiresAttribute = tokenize( attribute.second, "," );
12833 for ( auto const & r : requiresAttribute )
12834 {
12835 checkForError( ( m_features.find( r ) != m_features.end() ) || ( m_extensions.find( r ) != m_extensions.end() ),
12836 xmlLine,
12837 "unknown requires <" + r + "> specified for SPIR-V capability" );
12838 }
12839 }
12840 else if ( attribute.first == "value" )
12841 {
12842 value = attribute.second;
12843 }
12844 }
12845 assert( !member.empty() && !property.empty() && !value.empty() );
12846
12847 auto propertyIt = m_structures.find( property );
12848 checkForError( propertyIt != m_structures.end(), xmlLine, "unknown property <" + property + "> specified for SPIR-V capability" );
12849 auto memberIt = findStructMemberIt( member, propertyIt->second.members );
12850 checkForError( memberIt != propertyIt->second.members.end(), xmlLine, "unknown member <" + member + "> specified for SPIR-V capability" );
12851 if ( memberIt->type.type == "VkBool32" )
12852 {
12853 checkForError( ( value == "VK_FALSE" ) || ( value == "VK_TRUE" ),
12854 xmlLine,
12855 "unknown value <" + value + "> for boolean member <" + member + "> specified for SPIR-V capability" );
12856 }
12857 else
12858 {
12859 auto bitmaskIt = m_bitmasks.find( memberIt->type.type );
12860 checkForError( bitmaskIt != m_bitmasks.end(), xmlLine, "attribute member = <" + member + "> specified for SPIR-V capability is not a bitmask" );
12861 assert( !bitmaskIt->second.requirements.empty() );
12862 auto enumIt = m_enums.find( bitmaskIt->second.requirements );
12863 checkForError( enumIt != m_enums.end(),
12864 xmlLine,
12865 "attribute member = <" + member + "> specified for SPIR-V capability requires an unknown enum <" + bitmaskIt->second.requirements + ">" );
12866 auto valueIt =
12867 std::find_if( enumIt->second.values.begin(), enumIt->second.values.end(), [&value]( EnumValueData const & evd ) { return evd.name == value; } );
12868 checkForError( valueIt != enumIt->second.values.end(), xmlLine, "unknown attribute value = <" + value + "> specified for SPIR-V capability" );
12869 }
12870 }
12871
readSPIRVCapabilitiesSPIRVCapabilityEnableStruct(int xmlLine,std::map<std::string,std::string> const & attributes)12872 void VulkanHppGenerator::readSPIRVCapabilitiesSPIRVCapabilityEnableStruct( int xmlLine, std::map<std::string, std::string> const & attributes )
12873 {
12874 checkAttributes( xmlLine, attributes, { { "feature", {} }, { "struct", {} } }, { { "alias", {} }, { "requires", {} } } );
12875
12876 for ( auto const & attribute : attributes )
12877 {
12878 if ( attribute.first == "requires" )
12879 {
12880 std::vector<std::string> requiresAttribute = tokenize( attribute.second, "," );
12881 for ( auto const & r : requiresAttribute )
12882 {
12883 checkForError( ( m_features.find( r ) != m_features.end() ) || ( m_extensions.find( r ) != m_extensions.end() ),
12884 xmlLine,
12885 "unknown requires <" + r + "> specified for SPIR-V capability" );
12886 }
12887 }
12888 else if ( attribute.first == "struct" )
12889 {
12890 checkForError( ( m_structures.find( attribute.second ) != m_structures.end() ) ||
12891 ( m_structureAliases.find( attribute.second ) != m_structureAliases.end() ),
12892 xmlLine,
12893 "unknown structure <" + attribute.second + "> specified for SPIR-V capability" );
12894 checkForError( attributes.find( "feature" ) != attributes.end(),
12895 xmlLine,
12896 "missing feature attribute for SPIR-V capability specified with struct <" + attribute.second + ">" );
12897 }
12898 else
12899 {
12900 assert( ( attribute.first == "alias" ) || ( attribute.first == "feature" ) );
12901 }
12902 }
12903 }
12904
readSPIRVCapabilitiesSPIRVCapabilityEnableVersion(int xmlLine,std::map<std::string,std::string> const & attributes)12905 void VulkanHppGenerator::readSPIRVCapabilitiesSPIRVCapabilityEnableVersion( int xmlLine, std::map<std::string, std::string> const & attributes )
12906 {
12907 checkAttributes( xmlLine, attributes, { { "version", {} } }, {} );
12908
12909 checkForError( attributes.size() == 1, xmlLine, "unexpected attributes in addition to <version> specified for SPIR-V capability" );
12910 for ( auto const & attribute : attributes )
12911 {
12912 assert( attribute.first == "version" );
12913 std::string feature = attribute.second;
12914 if ( feature.starts_with( "VK_API_" ) )
12915 {
12916 feature.erase( 3, 4 ); // remove "API_" from the version -> VK_VERSION_x_y
12917 }
12918 checkForError( feature.starts_with( "VK_VERSION_" ), xmlLine, "unknown version <" + attribute.second + "> specified for SPIR-V capability" );
12919 checkForError( m_features.find( feature ) != m_features.end(), xmlLine, "unknown version <" + attribute.second + "> specified for SPIR-V capability" );
12920 }
12921 }
12922
readSPIRVExtensions(tinyxml2::XMLElement const * element)12923 void VulkanHppGenerator::readSPIRVExtensions( tinyxml2::XMLElement const * element )
12924 {
12925 int line = element->GetLineNum();
12926 std::map<std::string, std::string> attributes = getAttributes( element );
12927 checkAttributes( line, attributes, { { "comment", {} } }, {} );
12928 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12929 checkElements( line, children, {}, { "spirvextension" } );
12930
12931 for ( auto child : children )
12932 {
12933 assert( child->Value() == std::string( "spirvextension" ) );
12934 readSPIRVExtensionsExtension( child );
12935 }
12936 }
12937
readSPIRVExtensionsExtension(tinyxml2::XMLElement const * element)12938 void VulkanHppGenerator::readSPIRVExtensionsExtension( tinyxml2::XMLElement const * element )
12939 {
12940 int line = element->GetLineNum();
12941 std::map<std::string, std::string> attributes = getAttributes( element );
12942 checkAttributes( line, attributes, { { "name", {} } }, {} );
12943 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12944 checkElements( line, children, {}, { "enable" } );
12945
12946 for ( auto child : children )
12947 {
12948 assert( child->Value() == std::string( "enable" ) );
12949 readSPIRVExtensionsExtensionEnable( child );
12950 }
12951 }
12952
readSPIRVExtensionsExtensionEnable(tinyxml2::XMLElement const * element)12953 void VulkanHppGenerator::readSPIRVExtensionsExtensionEnable( tinyxml2::XMLElement const * element )
12954 {
12955 int line = element->GetLineNum();
12956 std::map<std::string, std::string> attributes = getAttributes( element );
12957 checkAttributes( line, attributes, {}, { { "extension", {} }, { "version", {} } } );
12958 checkElements( line, getChildElements( element ), {}, {} );
12959
12960 checkForError( !attributes.empty(), line, "no version or extension specified for SPIR-V extension" );
12961 for ( auto const & attribute : attributes )
12962 {
12963 if ( attribute.first == "extension" )
12964 {
12965 checkForError(
12966 m_extensions.find( attribute.second ) != m_extensions.end(), line, "unknown extension <" + attribute.second + "> specified for SPIR-V extension" );
12967 }
12968 else
12969 {
12970 assert( attribute.first == "version" );
12971 std::string feature = attribute.second;
12972 if ( feature.starts_with( "VK_API_" ) )
12973 {
12974 feature.erase( 3, 4 ); // remove "API_" from the version -> VK_VERSION_x_y
12975 }
12976 checkForError( feature.starts_with( "VK_VERSION_" ), line, "unknown version <" + attribute.second + "> specified for SPIR-V extension" );
12977 checkForError( m_features.find( feature ) != m_features.end(), line, "unknown version <" + attribute.second + "> specified for SPIR-V extension" );
12978 }
12979 }
12980 }
12981
readTags(tinyxml2::XMLElement const * element)12982 void VulkanHppGenerator::readTags( tinyxml2::XMLElement const * element )
12983 {
12984 int line = element->GetLineNum();
12985 checkAttributes( line, getAttributes( element ), { { "comment", {} } }, {} );
12986 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
12987 checkElements( line, children, { { "tag", false } } );
12988
12989 for ( auto child : children )
12990 {
12991 readTagsTag( child );
12992 }
12993 }
12994
readTagsTag(tinyxml2::XMLElement const * element)12995 void VulkanHppGenerator::readTagsTag( tinyxml2::XMLElement const * element )
12996 {
12997 int line = element->GetLineNum();
12998 std::map<std::string, std::string> attributes = getAttributes( element );
12999 checkAttributes( line, attributes, { { "author", {} }, { "contact", {} }, { "name", {} } }, {} );
13000 checkElements( line, getChildElements( element ), {} );
13001
13002 for ( auto const & attribute : attributes )
13003 {
13004 if ( attribute.first == "name" )
13005 {
13006 checkForError( m_tags.find( attribute.second ) == m_tags.end(), line, "tag named <" + attribute.second + "> has already been specified" );
13007 m_tags.insert( attribute.second );
13008 }
13009 else
13010 {
13011 checkForError( ( attribute.first == "author" ) || ( attribute.first == "contact" ), line, "unknown attribute <" + attribute.first + ">" );
13012 }
13013 }
13014 }
13015
readTypes(tinyxml2::XMLElement const * element)13016 void VulkanHppGenerator::readTypes( tinyxml2::XMLElement const * element )
13017 {
13018 int line = element->GetLineNum();
13019 checkAttributes( line, getAttributes( element ), { { "comment", {} } }, {} );
13020 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
13021 checkElements( line, children, { { "comment", false }, { "type", false } } );
13022
13023 for ( auto child : children )
13024 {
13025 std::string value = child->Value();
13026 if ( value == "comment" )
13027 {
13028 readComment( child );
13029 }
13030 else
13031 {
13032 assert( value == "type" );
13033 readTypesType( child );
13034 }
13035 }
13036 }
13037
readTypesType(tinyxml2::XMLElement const * element)13038 void VulkanHppGenerator::readTypesType( tinyxml2::XMLElement const * element )
13039 {
13040 int line = element->GetLineNum();
13041 std::map<std::string, std::string> attributes = getAttributes( element );
13042
13043 auto categoryIt = attributes.find( "category" );
13044 if ( categoryIt != attributes.end() )
13045 {
13046 if ( categoryIt->second == "basetype" )
13047 {
13048 readTypesTypeBasetype( element, attributes );
13049 }
13050 else if ( categoryIt->second == "bitmask" )
13051 {
13052 readTypesTypeBitmask( element, attributes );
13053 }
13054 else if ( categoryIt->second == "define" )
13055 {
13056 readTypesTypeDefine( element, attributes );
13057 }
13058 else if ( categoryIt->second == "enum" )
13059 {
13060 readTypesTypeEnum( element, attributes );
13061 }
13062 else if ( categoryIt->second == "funcpointer" )
13063 {
13064 readTypesTypeFuncpointer( element, attributes );
13065 }
13066 else if ( categoryIt->second == "handle" )
13067 {
13068 readTypesTypeHandle( element, attributes );
13069 }
13070 else if ( categoryIt->second == "include" )
13071 {
13072 readTypesTypeInclude( element, attributes );
13073 }
13074 else if ( categoryIt->second == "struct" )
13075 {
13076 readTypesTypeStruct( element, false, attributes );
13077 }
13078 else
13079 {
13080 checkForError( categoryIt->second == "union", element->GetLineNum(), "unknown type category <" + categoryIt->second + ">" );
13081 readTypesTypeStruct( element, true, attributes );
13082 }
13083 }
13084 else
13085 {
13086 auto requiresIt = attributes.find( "requires" );
13087 if ( requiresIt != attributes.end() )
13088 {
13089 readTypesTypeRequires( element, attributes );
13090 }
13091 else
13092 {
13093 checkForError( ( attributes.size() == 1 ) && ( attributes.begin()->first == "name" ) && ( attributes.begin()->second == "int" ), line, "unknown type" );
13094 checkForError( m_types.insert( std::make_pair( attributes.begin()->second, TypeData{ .category = TypeCategory::Unknown } ) ).second,
13095 line,
13096 "type <" + attributes.begin()->second + "> already specified" );
13097 }
13098 }
13099 }
13100
readTypesTypeBasetype(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13101 void VulkanHppGenerator::readTypesTypeBasetype( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13102 {
13103 int line = element->GetLineNum();
13104 checkAttributes( line, attributes, { { "category", { "basetype" } } }, {} );
13105
13106 NameData nameData;
13107 TypeInfo typeInfo;
13108 std::tie( nameData, typeInfo ) = readNameAndType( element );
13109
13110 if ( typeInfo.prefix == "typedef" )
13111 {
13112 // remove redundant typeInfo.prefix "typedef"
13113 typeInfo.prefix.clear();
13114 }
13115
13116 checkForError( nameData.arraySizes.empty(), line, "name <" + nameData.name + "> with unsupported arraySizes" );
13117 checkForError( typeInfo.prefix.empty(), line, "unexpected type prefix <" + typeInfo.prefix + ">" );
13118 checkForError( typeInfo.postfix.empty() || ( typeInfo.postfix == "*" ), line, "unexpected type postfix <" + typeInfo.postfix + ">" );
13119
13120 if ( !typeInfo.type.empty() )
13121 {
13122 checkForError( m_baseTypes.insert( std::make_pair( nameData.name, BaseTypeData( typeInfo, line ) ) ).second,
13123 line,
13124 "basetype <" + nameData.name + "> already specified" );
13125 }
13126 checkForError( m_types.insert( std::make_pair( nameData.name, TypeData{ .category = TypeCategory::BaseType } ) ).second,
13127 line,
13128 "basetype <" + nameData.name + "> already specified as a type" );
13129 }
13130
readTypesTypeBitmask(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13131 void VulkanHppGenerator::readTypesTypeBitmask( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13132 {
13133 int line = element->GetLineNum();
13134
13135 auto aliasIt = attributes.find( "alias" );
13136 if ( aliasIt != attributes.end() )
13137 {
13138 checkAttributes( line, attributes, { { "alias", {} }, { "category", { "bitmask" } }, { "name", {} } }, {} );
13139 checkElements( line, getChildElements( element ), {} );
13140
13141 std::string alias, name;
13142 for ( auto const & attribute : attributes )
13143 {
13144 if ( attribute.first == "alias" )
13145 {
13146 alias = attribute.second;
13147 }
13148 else if ( attribute.first == "name" )
13149 {
13150 name = attribute.second;
13151 }
13152 }
13153
13154 auto bitmasksIt = m_bitmasks.find( alias );
13155 checkForError( bitmasksIt != m_bitmasks.end(), line, "missing alias <" + alias + ">." );
13156 checkForError(
13157 bitmasksIt->second.alias.empty(), line, "alias for bitmask <" + bitmasksIt->first + "> already specified as <" + bitmasksIt->second.alias + ">" );
13158 bitmasksIt->second.alias = name;
13159 checkForError( m_types.insert( std::make_pair( name, TypeData{ .category = TypeCategory::Bitmask } ) ).second,
13160 line,
13161 "aliased bitmask <" + name + "> already specified as a type" );
13162 }
13163 else
13164 {
13165 checkAttributes( line, attributes, { { "category", { "bitmask" } } }, { { "api", { "vulkan", "vulkansc" } }, { "bitvalues", {} }, { "requires", {} } } );
13166
13167 std::string bitvalues, requirements;
13168 for ( auto const & attribute : attributes )
13169 {
13170 if ( attribute.first == "api" )
13171 {
13172 if ( attribute.second == "vulkansc" )
13173 {
13174 return; // skip stuff marked as "vulkansc" !
13175 }
13176 assert( attribute.second == "vulkan" );
13177 }
13178 else if ( attribute.first == "bitvalues" )
13179 {
13180 bitvalues = attribute.second;
13181 }
13182 else if ( attribute.first == "requires" )
13183 {
13184 requirements = attribute.second;
13185 }
13186 }
13187
13188 NameData nameData;
13189 TypeInfo typeInfo;
13190 std::tie( nameData, typeInfo ) = readNameAndType( element );
13191
13192 checkForError( nameData.name.starts_with( "Vk" ), line, "name <" + nameData.name + "> does not begin with <Vk>" );
13193 checkForError( nameData.arraySizes.empty(), line, "name <" + nameData.name + "> with unsupported arraySizes" );
13194 checkForWarning( ( typeInfo.type == "VkFlags" ) || ( typeInfo.type == "VkFlags64" ), line, "unexpected bitmask type <" + typeInfo.type + ">" );
13195 checkForError( typeInfo.prefix == "typedef", line, "unexpected type prefix <" + typeInfo.prefix + ">" );
13196 checkForError( typeInfo.postfix.empty(), line, "unexpected type postfix <" + typeInfo.postfix + ">" );
13197 checkForError( bitvalues.empty() || requirements.empty(), line, "attributes <bitvalues> and <requires> are both specified" );
13198 checkForError( ( typeInfo.type != "VkFlags64" ) || !bitvalues.empty(), line, "bitmask of type <VkFlags64> needs attribute bitvalues to be set" );
13199
13200 if ( !bitvalues.empty() )
13201 {
13202 requirements = bitvalues;
13203 }
13204 m_bitmasks.insert( std::make_pair( nameData.name, BitmaskData( requirements, typeInfo.type, line ) ) );
13205 checkForError( m_types.insert( std::make_pair( nameData.name, TypeData{ .category = TypeCategory::Bitmask } ) ).second,
13206 line,
13207 "bitmask <" + nameData.name + "> already specified as a type" );
13208 }
13209 }
13210
readTypesTypeDefine(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13211 void VulkanHppGenerator::readTypesTypeDefine( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13212 {
13213 int line = element->GetLineNum();
13214 checkAttributes( line, attributes, { { "category", { "define" } } }, { { "api", { "vulkan", "vulkansc" } }, { "name", {} }, { "requires", {} } } );
13215
13216 std::string name, require;
13217 for ( auto const & attribute : attributes )
13218 {
13219 if ( attribute.first == "api" )
13220 {
13221 if ( attribute.second == "vulkansc" )
13222 {
13223 return; // skip stuff marked as "vulkansc" !
13224 }
13225 assert( attribute.second == "vulkan" );
13226 }
13227 else if ( attribute.first == "name" )
13228 {
13229 name = attribute.second;
13230 }
13231 else if ( attribute.first == "requires" )
13232 {
13233 require = attribute.second;
13234 }
13235 }
13236
13237 if ( !name.empty() )
13238 {
13239 checkForError( !element->FirstChildElement(), line, "unknown formatting of type category=define name <" + name + ">" );
13240 checkForError( element->LastChild() && element->LastChild()->ToText() && element->LastChild()->ToText()->Value(),
13241 line,
13242 "unknown formatting of type category=define named <" + name + ">" );
13243
13244 // filter out the check for the different types of VK_DEFINE_NON_DISPATCHABLE_HANDLE
13245 if ( name == "VK_USE_64_BIT_PTR_DEFINES" )
13246 {
13247 m_typesafeCheck = "#if ( VK_USE_64_BIT_PTR_DEFINES == 1 )";
13248 }
13249 else if ( ( name == "VK_DEFINE_NON_DISPATCHABLE_HANDLE" ) && ( m_typesafeCheck.empty() ) )
13250 {
13251 std::string text = element->LastChild()->ToText()->Value();
13252 size_t start = text.find( "#if defined(__LP64__)" );
13253 checkForError( start != std::string::npos, line, "unexpected text in type category=define named <" + name + ">" );
13254 size_t end = text.find_first_of( "\r\n", start + 1 );
13255 checkForError( end != std::string::npos, line, "unexpected text in type category=define named <" + name + ">" );
13256 m_typesafeCheck = text.substr( start, end - start );
13257 }
13258 }
13259 else if ( element->GetText() )
13260 {
13261 std::string text = element->GetText();
13262 if ( ( text.find( "class" ) != std::string::npos ) || ( text.find( "struct" ) != std::string::npos ) )
13263 {
13264 // here are a couple of structs as defines, which really are types!
13265 tinyxml2::XMLElement const * child = element->FirstChildElement();
13266 checkForError( child && ( strcmp( child->Value(), "name" ) == 0 ) && child->GetText(), line, "unexpected formatting of type category=define" );
13267 name = child->GetText();
13268 checkForError(
13269 m_types.insert( std::make_pair( name, TypeData{ .category = TypeCategory::Define } ) ).second, line, "type <" + name + "> has already been speficied" );
13270 }
13271 else
13272 {
13273 tinyxml2::XMLElement const * child = element->FirstChildElement();
13274 checkForError( child && !child->FirstAttribute() && ( strcmp( child->Value(), "name" ) == 0 ) && child->GetText(),
13275 line,
13276 "unknown formatting of type category define" );
13277 name = trim( child->GetText() );
13278 if ( name == "VK_HEADER_VERSION" )
13279 {
13280 m_version = trimEnd( element->LastChild()->ToText()->Value() );
13281 }
13282 // ignore all the other defines
13283 checkForWarning( !child->NextSiblingElement() ||
13284 ( child->NextSiblingElement() && !child->NextSiblingElement()->FirstAttribute() &&
13285 ( strcmp( child->NextSiblingElement()->Value(), "type" ) == 0 ) && !child->NextSiblingElement()->NextSiblingElement() ),
13286 line,
13287 "unknown formatting of type category define" );
13288 }
13289 }
13290
13291 assert( !name.empty() );
13292 checkForError( m_defines.insert( { name, { require, line } } ).second, line, "define <" + name + "> has already been specified" );
13293 }
13294
readTypesTypeEnum(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13295 void VulkanHppGenerator::readTypesTypeEnum( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13296 {
13297 int line = element->GetLineNum();
13298 checkAttributes( line, attributes, { { "category", { "enum" } }, { "name", {} } }, { { "alias", {} } } );
13299 checkElements( line, getChildElements( element ), {} );
13300
13301 std::string alias, name;
13302 for ( auto const & attribute : attributes )
13303 {
13304 if ( attribute.first == "alias" )
13305 {
13306 alias = attribute.second;
13307 checkForError( !alias.empty(), line, "enum with empty alias" );
13308 }
13309 else if ( attribute.first == "name" )
13310 {
13311 name = attribute.second;
13312 checkForError( !name.empty(), line, "enum with empty name" );
13313 checkForError( m_enums.find( name ) == m_enums.end(), line, "enum <" + name + "> already specified" );
13314 }
13315 }
13316 assert( !name.empty() );
13317
13318 if ( alias.empty() )
13319 {
13320 checkForError( m_enums.insert( std::make_pair( name, EnumData{ .xmlLine = line } ) ).second, line, "enum <" + name + "> already specified" );
13321 }
13322 else
13323 {
13324 auto enumIt = m_enums.find( alias );
13325 checkForError( enumIt != m_enums.end(), line, "enum with unknown alias <" + alias + ">" );
13326 checkForError( enumIt->second.alias.empty(), line, "enum <" + enumIt->first + "> already has an alias <" + enumIt->second.alias + ">" );
13327 enumIt->second.alias = name;
13328 }
13329 checkForError(
13330 m_types.insert( std::make_pair( name, TypeData{ .category = TypeCategory::Enum } ) ).second, line, "enum <" + name + "> already specified as a type" );
13331 }
13332
readTypesTypeFuncpointer(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13333 void VulkanHppGenerator::readTypesTypeFuncpointer( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13334 {
13335 int line = element->GetLineNum();
13336 checkAttributes( line, attributes, { { "category", { "funcpointer" } } }, { { "requires", {} } } );
13337 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
13338 checkElements( line, children, { { "name", true } }, { "type" } );
13339
13340 std::string requirements;
13341 for ( auto const & attribute : attributes )
13342 {
13343 if ( attribute.first == "requires" )
13344 {
13345 requirements = attribute.second;
13346 }
13347 }
13348
13349 auto funcPointerIt = m_funcPointers.end();
13350 std::set<std::string> argumentNames;
13351 for ( auto const & child : children )
13352 {
13353 std::string value = child->Value();
13354 int childLine = child->GetLineNum();
13355 if ( value == "name" )
13356 {
13357 std::string name = child->GetText();
13358 checkForError( !name.empty(), childLine, "funcpointer with empty name" );
13359 checkForError( m_funcPointers.find( name ) == m_funcPointers.end(), childLine, "funcpointer <" + name + "> already specified" );
13360 funcPointerIt = m_funcPointers.insert( std::make_pair( name, FuncPointerData( requirements, line ) ) ).first;
13361 checkForError( m_types.insert( std::make_pair( name, TypeData{ .category = TypeCategory::FuncPointer } ) ).second,
13362 childLine,
13363 "funcpointer <" + name + "> already specified as a type" );
13364 }
13365 else if ( value == "type" )
13366 {
13367 assert( funcPointerIt != m_funcPointers.end() );
13368 std::string type = child->GetText();
13369 funcPointerIt->second.arguments.push_back( { type, childLine } );
13370
13371 auto sibling = child->NextSibling();
13372 char const * siblingValue = sibling->Value();
13373 assert( siblingValue != nullptr );
13374 std::string argumentName = siblingValue;
13375 argumentName = argumentName.substr( argumentName.find_first_not_of( "* " ) );
13376 argumentName = argumentName.substr( 0, argumentName.find_first_of( ",)" ) );
13377 checkForError( argumentNames.insert( argumentName ).second,
13378 childLine,
13379 "funcpointer <" + funcPointerIt->first + "> already has an argument named <" + argumentName + ">" );
13380 }
13381 }
13382 }
13383
readTypesTypeHandle(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13384 void VulkanHppGenerator::readTypesTypeHandle( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13385 {
13386 int line = element->GetLineNum();
13387
13388 auto aliasIt = attributes.find( "alias" );
13389 if ( aliasIt != attributes.end() )
13390 {
13391 checkAttributes( line, attributes, { { "alias", {} }, { "category", { "handle" } }, { "name", {} } }, {} );
13392 checkElements( line, getChildElements( element ), {} );
13393
13394 auto handlesIt = m_handles.find( aliasIt->second );
13395 checkForError( handlesIt != m_handles.end(), line, "using unspecified alias <" + aliasIt->second + ">." );
13396 checkForError( handlesIt->second.alias.empty(), line, "handle <" + handlesIt->first + "> already has an alias <" + handlesIt->second.alias + ">" );
13397 handlesIt->second.alias = attributes.find( "name" )->second;
13398 checkForError( m_types.insert( std::make_pair( handlesIt->second.alias, TypeData{ .category = TypeCategory::Handle } ) ).second,
13399 line,
13400 "handle alias <" + handlesIt->second.alias + "> already specified as a type" );
13401 }
13402 else
13403 {
13404 checkAttributes( line, attributes, { { "category", { "handle" } } }, { { "objtypeenum", {} }, { "parent", {} } } );
13405
13406 std::string objTypeEnum, parent;
13407 for ( auto const & attribute : attributes )
13408 {
13409 if ( attribute.first == "objtypeenum" )
13410 {
13411 objTypeEnum = attribute.second;
13412 }
13413 else if ( attribute.first == "parent" )
13414 {
13415 parent = attribute.second;
13416 }
13417 }
13418
13419 NameData nameData;
13420 TypeInfo typeInfo;
13421 std::tie( nameData, typeInfo ) = readNameAndType( element );
13422 const bool isDispatchable = typeInfo.type == "VK_DEFINE_HANDLE";
13423
13424 checkForError( nameData.name.starts_with( "Vk" ), line, "name <" + nameData.name + "> does not begin with <Vk>" );
13425 checkForError( nameData.arraySizes.empty(), line, "name <" + nameData.name + "> with unsupported arraySizes" );
13426 checkForError( ( typeInfo.type == "VK_DEFINE_HANDLE" ) || ( typeInfo.type == "VK_DEFINE_NON_DISPATCHABLE_HANDLE" ),
13427 line,
13428 "handle with invalid type <" + typeInfo.type + ">" );
13429 checkForError( typeInfo.prefix.empty(), line, "unexpected type prefix <" + typeInfo.prefix + ">" );
13430 checkForError( typeInfo.postfix == "(", line, "unexpected type postfix <" + typeInfo.postfix + ">" );
13431 checkForError( !objTypeEnum.empty(), line, "handle <" + nameData.name + "> does not specify attribute \"objtypeenum\"" );
13432
13433 checkForError( parent.find( ',' ) == std::string::npos, line, "mulitple parents specified for handle <" + nameData.name + ">" );
13434 checkForError( m_handles.insert( std::make_pair( nameData.name, HandleData( parent, objTypeEnum, isDispatchable, line ) ) ).second,
13435 line,
13436 "handle <" + nameData.name + "> already specified" );
13437 checkForError( m_types.insert( std::make_pair( nameData.name, TypeData{ .category = TypeCategory::Handle } ) ).second,
13438 line,
13439 "handle <" + nameData.name + "> already specified as a type" );
13440 }
13441 }
13442
readTypesTypeInclude(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13443 void VulkanHppGenerator::readTypesTypeInclude( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13444 {
13445 int line = element->GetLineNum();
13446 checkAttributes( line, attributes, { { "category", { "include" } }, { "name", {} } }, {} );
13447 checkElements( line, getChildElements( element ), {} );
13448
13449 std::string name = attributes.find( "name" )->second;
13450 checkForError( m_includes.insert( name ).second, element->GetLineNum(), "include named <" + name + "> already specified" );
13451 }
13452
readTypesTypeRequires(tinyxml2::XMLElement const * element,std::map<std::string,std::string> const & attributes)13453 void VulkanHppGenerator::readTypesTypeRequires( tinyxml2::XMLElement const * element, std::map<std::string, std::string> const & attributes )
13454 {
13455 int line = element->GetLineNum();
13456 checkAttributes( line, attributes, { { "name", {} }, { "requires", {} } }, {} );
13457 checkElements( line, getChildElements( element ), {} );
13458
13459 for ( auto attribute : attributes )
13460 {
13461 if ( attribute.first == "name" )
13462 {
13463 checkForError( m_types.insert( std::make_pair( attribute.second, TypeData{ .category = TypeCategory::Requires } ) ).second,
13464 line,
13465 "type named <" + attribute.second + "> already specified" );
13466 }
13467 else
13468 {
13469 assert( attribute.first == "requires" );
13470 checkForError( m_includes.find( attribute.second ) != m_includes.end(), line, "type requires unknown include <" + attribute.second + ">" );
13471 }
13472 }
13473 }
13474
readTypesTypeStruct(tinyxml2::XMLElement const * element,bool isUnion,std::map<std::string,std::string> const & attributes)13475 void VulkanHppGenerator::readTypesTypeStruct( tinyxml2::XMLElement const * element, bool isUnion, std::map<std::string, std::string> const & attributes )
13476 {
13477 int line = element->GetLineNum();
13478 if ( attributes.find( "alias" ) != attributes.end() )
13479 {
13480 checkAttributes( line, attributes, { { "alias", {} }, { "category", { "struct" } }, { "name", {} } }, {} );
13481 checkElements( line, getChildElements( element ), {}, {} );
13482
13483 std::string alias, name;
13484 for ( auto const & attribute : attributes )
13485 {
13486 if ( attribute.first == "alias" )
13487 {
13488 alias = attribute.second;
13489 }
13490 else if ( attribute.first == "name" )
13491 {
13492 name = attribute.second;
13493 }
13494 }
13495
13496 checkForError(
13497 m_structureAliases.insert( std::make_pair( name, StructureAliasData( alias, line ) ) ).second, line, "structure alias <" + name + "> already used" );
13498 checkForError( m_structureAliasesInverse[alias].insert( name ).second, line, "structure alias <" + name + "> already used with structure <" + alias + ">" );
13499 checkForError( m_types.insert( std::make_pair( name, TypeData{ .category = TypeCategory::Struct } ) ).second,
13500 line,
13501 "struct <" + name + "> already specified as a type" );
13502 }
13503 else
13504 {
13505 checkAttributes( line,
13506 attributes,
13507 { { "category", { isUnion ? "union" : "struct" } }, { "name", {} } },
13508 { { "allowduplicate", { "false", "true" } }, { "comment", {} }, { "returnedonly", { "true" } }, { "structextends", {} } } );
13509 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
13510 checkElements( line, children, {}, { "member", "comment" } );
13511
13512 std::string category, name;
13513 std::vector<std::string> structExtends;
13514 bool allowDuplicate = false;
13515 bool returnedOnly = false;
13516 for ( auto const & attribute : attributes )
13517 {
13518 if ( attribute.first == "allowduplicate" )
13519 {
13520 allowDuplicate = ( attribute.second == "true" );
13521 }
13522 else if ( attribute.first == "category" )
13523 {
13524 category = attribute.second;
13525 }
13526 else if ( attribute.first == "name" )
13527 {
13528 name = attribute.second;
13529 }
13530 else if ( attribute.first == "returnedonly" )
13531 {
13532 checkForError( attribute.second == "true", line, "unknown value for attribute returnedonly: <" + attribute.second + ">" );
13533 returnedOnly = true;
13534 }
13535 else if ( attribute.first == "structextends" )
13536 {
13537 structExtends = tokenize( attribute.second, "," );
13538 }
13539 }
13540 assert( !name.empty() );
13541 // make this warn a check, as soon as vk.xml has been fixed on attribute "allowduplicate" !
13542 checkForWarning( !allowDuplicate || !structExtends.empty(), line, "attribute <allowduplicate> is true, but no structures are listed in <structextends>" );
13543
13544 checkForError( m_structures.find( name ) == m_structures.end(), line, "struct <" + name + "> already specfied" );
13545 std::map<std::string, StructureData>::iterator it = m_structures.insert( std::make_pair( name, StructureData( structExtends, line ) ) ).first;
13546 it->second.allowDuplicate = allowDuplicate;
13547 it->second.isUnion = isUnion;
13548 it->second.returnedOnly = returnedOnly;
13549
13550 for ( auto child : children )
13551 {
13552 std::string value = child->Value();
13553 if ( value == "comment" )
13554 {
13555 readComment( child );
13556 }
13557 else if ( value == "member" )
13558 {
13559 readTypesTypeStructMember( child, it->second.members, isUnion );
13560 }
13561 }
13562 it->second.subStruct = determineSubStruct( *it );
13563
13564 // check if multiple structure members use the very same (not empty) len attribute
13565 // Note: even though the arrays are not marked as optional, they still might be mutually exclusive (like in
13566 // VkWriteDescriptorSet)! That is, there's not enough information available in vk.xml to decide on that, so we
13567 // need this external knowledge!
13568 static std::set<std::string> mutualExclusiveStructs = {
13569 "VkAccelerationStructureBuildGeometryInfoKHR", "VkAccelerationStructureTrianglesOpacityMicromapEXT", "VkMicromapBuildInfoEXT", "VkWriteDescriptorSet"
13570 };
13571 static std::set<std::string> multipleLenStructs = { "VkImageConstraintsInfoFUCHSIA",
13572 "VkIndirectCommandsLayoutTokenNV",
13573 "VkPresentInfoKHR",
13574 "VkSemaphoreWaitInfo",
13575 "VkSubmitInfo",
13576 "VkSubpassDescription",
13577 "VkSubpassDescription2",
13578 "VkWin32KeyedMutexAcquireReleaseInfoKHR",
13579 "VkWin32KeyedMutexAcquireReleaseInfoNV" };
13580 bool warned = false;
13581 for ( auto m0It = it->second.members.begin(); !warned && ( m0It != it->second.members.end() ); ++m0It )
13582 {
13583 if ( !m0It->len.empty() && ( m0It->len.front() != "null-terminated" ) )
13584 {
13585 for ( auto m1It = std::next( m0It ); !warned && ( m1It != it->second.members.end() ); ++m1It )
13586 {
13587 if ( !m1It->len.empty() && ( m0It->len.front() == m1It->len.front() ) )
13588 {
13589 if ( mutualExclusiveStructs.find( it->first ) != mutualExclusiveStructs.end() )
13590 {
13591 it->second.mutualExclusiveLens = true;
13592 }
13593 else
13594 {
13595 checkForWarning(
13596 multipleLenStructs.find( it->first ) != multipleLenStructs.end(),
13597 line,
13598 "Encountered structure <" + it->first +
13599 "> with multiple members referencing the same member for len. Need to be checked if they are supposed to be mutually exclusive." );
13600 warned = true;
13601 }
13602 }
13603 }
13604 }
13605 }
13606
13607 m_extendedStructs.insert( structExtends.begin(), structExtends.end() );
13608 checkForError(
13609 m_types.insert( std::make_pair( name, TypeData{ .category = ( category == "struct" ) ? TypeCategory::Struct : TypeCategory::Union } ) ).second,
13610 line,
13611 "struct <" + name + "> already specified as a type" ); // log type and alias in m_types
13612 }
13613 }
13614
readTypesTypeStructMember(tinyxml2::XMLElement const * element,std::vector<MemberData> & members,bool isUnion)13615 void VulkanHppGenerator::readTypesTypeStructMember( tinyxml2::XMLElement const * element, std::vector<MemberData> & members, bool isUnion )
13616 {
13617 int line = element->GetLineNum();
13618 std::map<std::string, std::string> attributes = getAttributes( element );
13619 checkAttributes( line,
13620 attributes,
13621 {},
13622 { { "altlen", {} },
13623 { "api", { "vulkan", "vulkansc" } },
13624 { "externsync", { "true" } },
13625 { "len", {} },
13626 { "limittype", { "bitmask", "bits", "exact", "max", "min", "mul", "noauto", "pot", "range", "struct" } },
13627 { "noautovalidity", { "true" } },
13628 { "objecttype", { "objectType" } },
13629 { "optional", { "false", "true" } },
13630 { "selection", {} },
13631 { "selector", {} },
13632 { "values", {} } } );
13633 std::vector<tinyxml2::XMLElement const *> children = getChildElements( element );
13634 checkElements( line, children, { { "name", true }, { "type", true } }, { "comment", "enum" } );
13635
13636 MemberData memberData( line );
13637
13638 for ( auto const & attribute : attributes )
13639 {
13640 if ( attribute.first == "api" )
13641 {
13642 if ( attribute.second == "vulkansc" )
13643 {
13644 return; // skip stuff marked as "vulkansc" !
13645 }
13646 assert( attribute.second == "vulkan" );
13647 }
13648 else if ( attribute.first == "altlen" )
13649 {
13650 assert( memberData.len.empty() );
13651 memberData.len = tokenize( attribute.second, "," );
13652 checkForError( memberData.len.size() == 1, line, "member attribute <altlen> holds unknown number of data: " + std::to_string( memberData.len.size() ) );
13653 checkForError( altLens.find( memberData.len[0] ) != altLens.end(), line, "member attribute <altlen> holds unknown value <" + memberData.len[0] + ">" );
13654 }
13655 else if ( attribute.first == "len" )
13656 {
13657 if ( memberData.len.empty() )
13658 {
13659 memberData.len = tokenize( attribute.second, "," );
13660 checkForError( !memberData.len.empty() && ( memberData.len.size() <= 2 ),
13661 line,
13662 "member attribute <len> holds unknown number of data: " + std::to_string( memberData.len.size() ) );
13663 auto lenMember = findStructMemberIt( memberData.len[0], members );
13664 checkForError( lenMember != members.end() || ( memberData.len[0] == "null-terminated" ),
13665 line,
13666 "member attribute <len> holds unknown value <" + memberData.len[0] + ">" );
13667 if ( lenMember != members.end() )
13668 {
13669 checkForError( lenMember->type.prefix.empty(),
13670 line,
13671 "member attribute <len> references a member of unexpected type <" + lenMember->type.compose( "VULKAN_HPP_NAMESPACE" ) + ">" );
13672 }
13673 if ( 1 < memberData.len.size() )
13674 {
13675 checkForError( ( memberData.len[1] == "1" ) || ( memberData.len[1] == "null-terminated" ),
13676 line,
13677 "member attribute <len> holds unknown second value <" + memberData.len[1] + ">" );
13678 }
13679 }
13680 }
13681 else if ( attribute.first == "noautovalidity" )
13682 {
13683 memberData.noAutoValidity = ( attribute.second == "true" );
13684 }
13685 else if ( attribute.first == "optional" )
13686 {
13687 std::vector<std::string> optional = tokenize( attribute.second, "," );
13688 memberData.optional.reserve( optional.size() );
13689 for ( auto const & o : optional )
13690 {
13691 memberData.optional.push_back( o == "true" );
13692 }
13693 }
13694 else if ( attribute.first == "selection" )
13695 {
13696 checkForError( isUnion, line, "attribute <selection> is used with a non-union structure." );
13697 memberData.selection = tokenize( attribute.second, "," );
13698 }
13699 else if ( attribute.first == "selector" )
13700 {
13701 memberData.selector = attribute.second;
13702 auto selectorIt = findStructMemberIt( memberData.selector, members );
13703 checkForError( selectorIt != members.end(), line, "member attribute <selector> holds unknown value <" + memberData.selector + ">" );
13704 checkForError( m_enums.find( selectorIt->type.type ) != m_enums.end(),
13705 line,
13706 "member attribute <selector> references unknown enum type <" + selectorIt->type.type + ">" );
13707 }
13708 else if ( attribute.first == "values" )
13709 {
13710 std::vector<std::string> values = tokenize( attribute.second, "," );
13711 checkForError( values.size() == 1, line, "attribute \"values\" holds multiple values <" + attribute.first + ">, but it's expected to hold just one" );
13712 memberData.value = values[0];
13713 }
13714 }
13715
13716 for ( auto child : children )
13717 {
13718 std::string value = child->Value();
13719 if ( value == "enum" )
13720 {
13721 readTypesTypeStructMemberEnum( child, memberData );
13722 }
13723 else if ( value == "name" )
13724 {
13725 readTypesTypeStructMemberName( child, memberData, members );
13726 }
13727 else if ( value == "type" )
13728 {
13729 readTypesTypeStructMemberType( child, memberData );
13730 }
13731 }
13732
13733 members.push_back( memberData );
13734 }
13735
readTypesTypeStructMemberEnum(tinyxml2::XMLElement const * element,MemberData & memberData)13736 void VulkanHppGenerator::readTypesTypeStructMemberEnum( tinyxml2::XMLElement const * element, MemberData & memberData )
13737 {
13738 int line = element->GetLineNum();
13739 checkAttributes( line, getAttributes( element ), {}, {} );
13740 checkElements( line, getChildElements( element ), {}, {} );
13741
13742 std::string enumString = element->GetText();
13743
13744 checkForError( element->PreviousSibling() && ( strcmp( element->PreviousSibling()->Value(), "[" ) == 0 ) && element->NextSibling() &&
13745 ( strcmp( element->NextSibling()->Value(), "]" ) == 0 ),
13746 line,
13747 std::string( "structure member array specifiation is ill-formatted: <" ) + enumString + ">" );
13748
13749 memberData.arraySizes.push_back( enumString );
13750 checkForError( memberData.usedConstant.empty(), line, "struct already holds a constant <" + memberData.usedConstant + ">" );
13751 memberData.usedConstant = enumString;
13752 }
13753
readTypesTypeStructMemberName(tinyxml2::XMLElement const * element,MemberData & memberData,std::vector<MemberData> const & members)13754 void VulkanHppGenerator::readTypesTypeStructMemberName( tinyxml2::XMLElement const * element, MemberData & memberData, std::vector<MemberData> const & members )
13755 {
13756 int line = element->GetLineNum();
13757 checkAttributes( line, getAttributes( element ), {}, {} );
13758 checkElements( line, getChildElements( element ), {}, {} );
13759
13760 std::string name = element->GetText();
13761 checkForError( !isStructMember( name, members ), line, "structure member name <" + name + "> already used" );
13762
13763 memberData.name = name;
13764 std::tie( memberData.arraySizes, memberData.bitCount ) = readModifiers( element->NextSibling() );
13765 }
13766
readTypesTypeStructMemberType(tinyxml2::XMLElement const * element,MemberData & memberData)13767 void VulkanHppGenerator::readTypesTypeStructMemberType( tinyxml2::XMLElement const * element, MemberData & memberData )
13768 {
13769 int line = element->GetLineNum();
13770 checkAttributes( line, getAttributes( element ), {}, {} );
13771 checkElements( line, getChildElements( element ), {}, {} );
13772
13773 memberData.type = readTypeInfo( element );
13774 }
13775
readTypeInfo(tinyxml2::XMLElement const * element) const13776 VulkanHppGenerator::TypeInfo VulkanHppGenerator::readTypeInfo( tinyxml2::XMLElement const * element ) const
13777 {
13778 TypeInfo typeInfo;
13779 tinyxml2::XMLNode const * previousSibling = element->PreviousSibling();
13780 if ( previousSibling && previousSibling->ToText() )
13781 {
13782 typeInfo.prefix = trim( previousSibling->Value() );
13783 }
13784 typeInfo.type = element->GetText();
13785 tinyxml2::XMLNode const * nextSibling = element->NextSibling();
13786 if ( nextSibling && nextSibling->ToText() )
13787 {
13788 typeInfo.postfix = trimStars( trimEnd( nextSibling->Value() ) );
13789 }
13790 return typeInfo;
13791 }
13792
registerDeleter(std::string const & name,std::pair<std::string,CommandData> const & commandData)13793 void VulkanHppGenerator::registerDeleter( std::string const & name, std::pair<std::string, CommandData> const & commandData )
13794 {
13795 if ( ( commandData.first.substr( 2, 7 ) == "Destroy" ) || ( commandData.first.substr( 2, 4 ) == "Free" ) )
13796 {
13797 std::string key;
13798 size_t valueIndex;
13799 switch ( commandData.second.params.size() )
13800 {
13801 case 2:
13802 case 3:
13803 assert( commandData.second.params.back().type.type == "VkAllocationCallbacks" );
13804 key = ( commandData.second.params.size() == 2 ) ? "" : commandData.second.params[0].type.type;
13805 valueIndex = commandData.second.params.size() - 2;
13806 break;
13807 case 4:
13808 key = commandData.second.params[0].type.type;
13809 valueIndex = 3;
13810 assert( m_handles.find( commandData.second.params[valueIndex].type.type ) != m_handles.end() );
13811 m_handles.find( commandData.second.params[valueIndex].type.type )->second.deletePool = commandData.second.params[1].type.type;
13812 break;
13813 default: assert( false ); valueIndex = 0;
13814 }
13815 auto keyHandleIt = m_handles.find( key );
13816 assert( keyHandleIt != m_handles.end() );
13817 keyHandleIt->second.childrenHandles.insert( commandData.second.params[valueIndex].type.type );
13818
13819 auto handleIt = m_handles.find( commandData.second.params[valueIndex].type.type );
13820 assert( handleIt != m_handles.end() );
13821 handleIt->second.deleteCommand = name;
13822 }
13823 }
13824
rescheduleRAIIHandle(std::string & str,std::pair<std::string,HandleData> const & handle,std::set<std::string> & listedHandles,std::set<std::string> const & specialFunctions) const13825 void VulkanHppGenerator::rescheduleRAIIHandle( std::string & str,
13826 std::pair<std::string, HandleData> const & handle,
13827 std::set<std::string> & listedHandles,
13828 std::set<std::string> const & specialFunctions ) const
13829 {
13830 listedHandles.insert( handle.first );
13831 if ( !handle.second.parent.empty() && ( listedHandles.find( handle.second.parent ) == listedHandles.end() ) )
13832 {
13833 auto parentIt = m_handles.find( handle.second.parent );
13834 assert( parentIt != m_handles.end() );
13835 str += generateRAIIHandle( *parentIt, listedHandles, specialFunctions );
13836 }
13837
13838 for ( auto constructorIt : handle.second.constructorIts )
13839 {
13840 for ( auto const & param : constructorIt->second.params )
13841 {
13842 auto handleIt = m_handles.find( param.type.type );
13843 if ( handleIt != m_handles.end() && ( listedHandles.find( param.type.type ) == listedHandles.end() ) )
13844 {
13845 str += generateRAIIHandle( *handleIt, listedHandles, specialFunctions );
13846 }
13847 }
13848 }
13849 }
13850
selectCommandsByHandle(std::vector<RequireData> const & requireData,std::set<std::string> const & handleCommands,std::set<std::string> & listedCommands) const13851 std::vector<std::string> VulkanHppGenerator::selectCommandsByHandle( std::vector<RequireData> const & requireData,
13852 std::set<std::string> const & handleCommands,
13853 std::set<std::string> & listedCommands ) const
13854 {
13855 std::vector<std::string> selectedCommands;
13856 for ( auto const & require : requireData )
13857 {
13858 for ( auto const & command : require.commands )
13859 {
13860 if ( ( handleCommands.find( command ) != handleCommands.end() ) && listedCommands.insert( command ).second )
13861 {
13862 selectedCommands.push_back( command );
13863 }
13864 }
13865 }
13866 return selectedCommands;
13867 }
13868
setVulkanLicenseHeader(int line,std::string const & comment)13869 void VulkanHppGenerator::setVulkanLicenseHeader( int line, std::string const & comment )
13870 {
13871 checkForError( m_vulkanLicenseHeader.empty(), line, "second encounter of a Copyright comment" );
13872 m_vulkanLicenseHeader = comment;
13873
13874 // replace any '\n' with "\n// "
13875 for ( size_t pos = m_vulkanLicenseHeader.find( '\n' ); pos != std::string::npos; pos = m_vulkanLicenseHeader.find( '\n', pos + 1 ) )
13876 {
13877 m_vulkanLicenseHeader.replace( pos, 1, "\n// " );
13878 }
13879 // remove any trailing spaces
13880 m_vulkanLicenseHeader = trimEnd( m_vulkanLicenseHeader );
13881
13882 // and add a little message on our own
13883 m_vulkanLicenseHeader += "\n\n// This header is generated from the Khronos Vulkan XML API Registry.";
13884 m_vulkanLicenseHeader = trim( m_vulkanLicenseHeader ) + "\n";
13885 }
13886
skipLeadingGrandParent(std::pair<std::string,HandleData> const & handle) const13887 bool VulkanHppGenerator::skipLeadingGrandParent( std::pair<std::string, HandleData> const & handle ) const
13888 {
13889 bool skip = false;
13890 assert( !handle.second.constructorIts.empty() );
13891 auto constructorIt = handle.second.constructorIts.begin();
13892 if ( ( 1 < ( *constructorIt )->second.params.size() ) && isHandleType( ( *constructorIt )->second.params[0].type.type ) &&
13893 ( ( *constructorIt )->second.params[1].type.type == handle.second.parent ) )
13894 {
13895 auto parentIt = m_handles.find( handle.second.parent );
13896 assert( parentIt != m_handles.end() );
13897 skip = ( ( *constructorIt )->second.params[0].type.type == parentIt->second.parent );
13898 #if !defined( NDEBUG )
13899 for ( auto it = std::next( constructorIt ); it != handle.second.constructorIts.end(); ++it )
13900 {
13901 assert( ( *it )->second.params[0].type.type == ( *constructorIt )->second.params[0].type.type );
13902 assert( !skip || ( ( *it )->second.params[1].type.type == ( *constructorIt )->second.params[1].type.type ) );
13903 }
13904 #endif
13905 }
13906 return skip;
13907 }
13908
toString(TypeCategory category)13909 std::string VulkanHppGenerator::toString( TypeCategory category )
13910 {
13911 switch ( category )
13912 {
13913 case TypeCategory::Bitmask: return "bitmask";
13914 case TypeCategory::BaseType: return "basetype";
13915 case TypeCategory::Define: return "define";
13916 case TypeCategory::Enum: return "enum";
13917 case TypeCategory::FuncPointer: return "funcpointer";
13918 case TypeCategory::Handle: return "handle";
13919 case TypeCategory::Requires: return "requires";
13920 case TypeCategory::Struct: return "struct";
13921 case TypeCategory::Union: return "union";
13922 case TypeCategory::Unknown: return "unkown";
13923 default: assert( false ); return "";
13924 }
13925 }
13926
addEnumAlias(int line,std::string const & name,std::string const & aliasName)13927 void VulkanHppGenerator::EnumData::addEnumAlias( int line, std::string const & name, std::string const & aliasName )
13928 {
13929 auto aliasIt = aliases.find( name );
13930 checkForError(
13931 ( aliasIt == aliases.end() ) || ( aliasIt->second.name == aliasName ), line, "enum alias <" + name + "> already listed for a different enum value" );
13932 aliases.insert( std::make_pair( name, EnumAliasData( aliasName, line ) ) );
13933 }
13934
addEnumValue(int line,std::string const & valueName,std::string const & protect,bool bitpos,std::string const & extension)13935 void VulkanHppGenerator::EnumData::addEnumValue(
13936 int line, std::string const & valueName, std::string const & protect, bool bitpos, std::string const & extension )
13937 {
13938 auto valueIt = std::find_if( values.begin(), values.end(), [&valueName]( EnumValueData const & evd ) { return evd.name == valueName; } );
13939 if ( valueIt == values.end() )
13940 {
13941 values.emplace_back( line, valueName, protect, extension, bitpos );
13942 }
13943 }
13944
compose(std::string const & nameSpace) const13945 std::string VulkanHppGenerator::TypeInfo::compose( std::string const & nameSpace ) const
13946 {
13947 return prefix + ( prefix.empty() ? "" : " " ) +
13948 ( nameSpace.empty() ? type : ( ( ( type.substr( 0, 2 ) == "Vk" ) ? ( nameSpace + "::" ) : "" ) + stripPrefix( type, "Vk" ) ) ) +
13949 ( postfix.empty() ? "" : " " ) + postfix;
13950 }
13951
RequireData(int line,std::vector<std::string> const & depends_)13952 VulkanHppGenerator::RequireData::RequireData( int line, std::vector<std::string> const & depends_ ) : depends( depends_ ), xmlLine( line ) {}
13953
13954 //
13955 // VulkanHppGenerator local functions
13956 //
13957
13958 // check the validity of an attributes map
13959 // line : the line in the xml file where the attributes are listed
13960 // attributes : the map of name/value pairs of the encountered attributes
13961 // required : the required attributes, with a set of allowed values per attribute
13962 // optional : the optional attributes, with a set of allowed values per attribute
checkAttributes(int line,std::map<std::string,std::string> const & attributes,std::map<std::string,std::set<std::string>> const & required,std::map<std::string,std::set<std::string>> const & optional)13963 void checkAttributes( int line,
13964 std::map<std::string, std::string> const & attributes,
13965 std::map<std::string, std::set<std::string>> const & required,
13966 std::map<std::string, std::set<std::string>> const & optional )
13967 {
13968 // check if all required attributes are included and if there is a set of allowed values, check if the actual
13969 // value is part of that set
13970 for ( auto const & r : required )
13971 {
13972 auto attributesIt = attributes.find( r.first );
13973 checkForError( attributesIt != attributes.end(), line, "missing attribute <" + r.first + ">" );
13974 if ( !r.second.empty() )
13975 {
13976 std::vector<std::string> values = tokenize( attributesIt->second, "," );
13977 for ( auto const & v : values )
13978 {
13979 checkForError( r.second.find( v ) != r.second.end(), line, "unexpected attribute value <" + v + "> in attribute <" + attributesIt->first + ">" );
13980 }
13981 }
13982 }
13983 // check if all not required attributes or optional, and if there is a set of allowed values, check if the
13984 // actual value is part of that set
13985 for ( auto const & a : attributes )
13986 {
13987 if ( required.find( a.first ) == required.end() )
13988 {
13989 auto optionalIt = optional.find( a.first );
13990 if ( optionalIt == optional.end() )
13991 {
13992 checkForWarning( false, line, "unknown attribute <" + a.first + ">" );
13993 continue;
13994 }
13995 if ( !optionalIt->second.empty() )
13996 {
13997 std::vector<std::string> values = tokenize( a.second, "," );
13998 for ( auto const & v : values )
13999 {
14000 checkForWarning(
14001 optionalIt->second.find( v ) != optionalIt->second.end(), line, "unexpected attribute value <" + v + "> in attribute <" + a.first + ">" );
14002 }
14003 }
14004 }
14005 }
14006 }
14007
checkElements(int line,std::vector<tinyxml2::XMLElement const * > const & elements,std::map<std::string,bool> const & required,std::set<std::string> const & optional)14008 void checkElements( int line,
14009 std::vector<tinyxml2::XMLElement const *> const & elements,
14010 std::map<std::string, bool> const & required,
14011 std::set<std::string> const & optional )
14012 {
14013 std::map<std::string, size_t> encountered;
14014 for ( auto const & e : elements )
14015 {
14016 std::string value = e->Value();
14017 encountered[value]++;
14018 checkForWarning(
14019 ( required.find( value ) != required.end() ) || ( optional.find( value ) != optional.end() ), e->GetLineNum(), "unknown element <" + value + ">" );
14020 }
14021 for ( auto const & r : required )
14022 {
14023 auto encounteredIt = encountered.find( r.first );
14024 checkForError( encounteredIt != encountered.end(), line, "missing required element <" + r.first + ">" );
14025 // check: r.second (means: required excactly once) => (encouteredIt->second == 1)
14026 checkForError( !r.second || ( encounteredIt->second == 1 ),
14027 line,
14028 "required element <" + r.first + "> is supposed to be listed exactly once, but is listed " + std::to_string( encounteredIt->second ) );
14029 }
14030 }
14031
checkForError(bool condition,int line,std::string const & message)14032 void checkForError( bool condition, int line, std::string const & message )
14033 {
14034 if ( !condition )
14035 {
14036 throw std::runtime_error( "VulkanHppGenerator: Spec error on line " + std::to_string( line ) + ": " + message );
14037 }
14038 }
14039
checkForWarning(bool condition,int line,std::string const & message)14040 void checkForWarning( bool condition, int line, std::string const & message )
14041 {
14042 if ( !condition )
14043 {
14044 std::cerr << "VulkanHppGenerator: Spec warning on line " << std::to_string( line ) << ": " << message << "!" << std::endl;
14045 }
14046 }
14047
findTag(std::set<std::string> const & tags,std::string const & name,std::string const & postfix)14048 std::string findTag( std::set<std::string> const & tags, std::string const & name, std::string const & postfix )
14049 {
14050 auto tagIt = std::find_if( tags.begin(), tags.end(), [&name, &postfix]( std::string const & t ) { return name.ends_with( t + postfix ); } );
14051 return ( tagIt != tags.end() ) ? *tagIt : "";
14052 }
14053
generateCArraySizes(std::vector<std::string> const & sizes)14054 std::string generateCArraySizes( std::vector<std::string> const & sizes )
14055 {
14056 std::string arraySizes;
14057 for ( auto const & s : sizes )
14058 {
14059 arraySizes += "[" + s + "]";
14060 }
14061 return arraySizes;
14062 }
14063
generateEnumSuffixes(std::string const & name,bool bitmask,std::set<std::string> const & tags)14064 std::pair<std::string, std::string> generateEnumSuffixes( std::string const & name, bool bitmask, std::set<std::string> const & tags )
14065 {
14066 std::string prefix, postfix;
14067 if ( name == "VkResult" )
14068 {
14069 prefix = "VK_";
14070 }
14071 else
14072 {
14073 if ( bitmask )
14074 {
14075 // for a bitmask enum, start with "VK", cut off the trailing "FlagBits", and convert that name to upper case
14076 // end that with "Bit"
14077 size_t pos = name.find( "FlagBits" );
14078 assert( pos != std::string::npos );
14079 std::string shortenedName = name;
14080 shortenedName.erase( pos, strlen( "FlagBits" ) );
14081 std::string tag = findTag( tags, shortenedName );
14082 prefix = toUpperCase( stripPostfix( shortenedName, tag ) ) + "_";
14083 }
14084 else
14085 {
14086 // for a non-bitmask enum, convert the name to upper case
14087 prefix = toUpperCase( name ) + "_";
14088 }
14089
14090 // if the enum name contains a tag move it from the prefix to the postfix to generate correct enum value
14091 // names.
14092 for ( auto const & tag : tags )
14093 {
14094 if ( prefix.ends_with( tag + "_" ) )
14095 {
14096 prefix.erase( prefix.length() - tag.length() - 1 );
14097 postfix = "_" + tag;
14098 break;
14099 }
14100 else if ( name.ends_with( tag ) )
14101 {
14102 postfix = "_" + tag;
14103 break;
14104 }
14105 }
14106 }
14107
14108 return std::make_pair( prefix, postfix );
14109 }
14110
generateEnumValueName(std::string const & enumName,std::string const & valueName,bool bitmask,std::set<std::string> const & tags)14111 std::string generateEnumValueName( std::string const & enumName, std::string const & valueName, bool bitmask, std::set<std::string> const & tags )
14112 {
14113 std::string prefix, postfix;
14114 std::tie( prefix, postfix ) = generateEnumSuffixes( enumName, bitmask, tags );
14115 std::string tag = findTag( tags, valueName, "" );
14116 if ( postfix == "_" + tag )
14117 {
14118 tag = findTag( tags, valueName, postfix );
14119 }
14120
14121 std::string result = "e" + toCamelCase( stripPostfix( stripPrefix( valueName, prefix ), postfix ) );
14122 if ( bitmask )
14123 {
14124 size_t pos = result.find( "Bit" );
14125 if ( pos != std::string::npos )
14126 {
14127 result.erase( pos, 3 );
14128 }
14129 }
14130 if ( !tag.empty() && ( result.substr( result.length() - tag.length() ) == toCamelCase( tag ) ) )
14131 {
14132 result = result.substr( 0, result.length() - tag.length() ) + tag;
14133 }
14134 return result;
14135 }
14136
generateNamespacedType(std::string const & type)14137 std::string generateNamespacedType( std::string const & type )
14138 {
14139 return type.starts_with( "Vk" ) ? ( "VULKAN_HPP_NAMESPACE::" + stripPrefix( type, "Vk" ) ) : type;
14140 }
14141
generateNoDiscard(bool returnsSomething,bool multiSuccessCodes,bool multiErrorCodes)14142 std::string generateNoDiscard( bool returnsSomething, bool multiSuccessCodes, bool multiErrorCodes )
14143 {
14144 return ( returnsSomething || multiSuccessCodes ) ? "VULKAN_HPP_NODISCARD " : ( multiErrorCodes ? "VULKAN_HPP_NODISCARD_WHEN_NO_EXCEPTIONS " : "" );
14145 }
14146
generateStandardArray(std::string const & type,std::vector<std::string> const & sizes)14147 std::string generateStandardArray( std::string const & type, std::vector<std::string> const & sizes )
14148 {
14149 std::string arrayString = "std::array<" + type + "," + sizes.back() + ">";
14150 for ( size_t i = sizes.size() - 2; i < sizes.size(); i-- )
14151 {
14152 arrayString = "std::array<" + arrayString + "," + sizes[i] + ">";
14153 }
14154 return arrayString;
14155 }
14156
generateStandardArrayWrapper(std::string const & type,std::vector<std::string> const & sizes)14157 std::string generateStandardArrayWrapper( std::string const & type, std::vector<std::string> const & sizes )
14158 {
14159 std::string arrayString = "VULKAN_HPP_NAMESPACE::ArrayWrapper" + std::to_string( sizes.size() ) + "D<" + type;
14160 for ( auto const & size : sizes )
14161 {
14162 arrayString += ", " + size;
14163 }
14164 arrayString += ">";
14165 return arrayString;
14166 }
14167
generateSuccessCode(std::string const & code,std::set<std::string> const & tags)14168 std::string generateSuccessCode( std::string const & code, std::set<std::string> const & tags )
14169 {
14170 std::string tag = findTag( tags, code );
14171 // on each success code: prepend 'VULKAN_HPP_NAMESPACE::Result::e', strip "VK_" and a tag, convert it to camel
14172 // case, and add the tag again
14173 return "VULKAN_HPP_NAMESPACE::Result::e" + toCamelCase( stripPostfix( stripPrefix( code, "VK_" ), tag ) ) + tag;
14174 }
14175
getAttributes(tinyxml2::XMLElement const * element)14176 std::map<std::string, std::string> getAttributes( tinyxml2::XMLElement const * element )
14177 {
14178 std::map<std::string, std::string> attributes;
14179 for ( auto attribute = element->FirstAttribute(); attribute; attribute = attribute->Next() )
14180 {
14181 assert( attributes.find( attribute->Name() ) == attributes.end() );
14182 attributes[attribute->Name()] = attribute->Value();
14183 }
14184 return attributes;
14185 }
14186
14187 template <typename ElementContainer>
getChildElements(ElementContainer const * element)14188 std::vector<tinyxml2::XMLElement const *> getChildElements( ElementContainer const * element )
14189 {
14190 std::vector<tinyxml2::XMLElement const *> childElements;
14191 for ( tinyxml2::XMLElement const * childElement = element->FirstChildElement(); childElement; childElement = childElement->NextSiblingElement() )
14192 {
14193 childElements.push_back( childElement );
14194 }
14195 return childElements;
14196 }
14197
readModifiers(tinyxml2::XMLNode const * node)14198 std::pair<std::vector<std::string>, std::string> readModifiers( tinyxml2::XMLNode const * node )
14199 {
14200 std::vector<std::string> arraySizes;
14201 std::string bitCount;
14202 if ( node && node->ToText() )
14203 {
14204 // following the name there might be some array size
14205 std::string value = node->Value();
14206 assert( !value.empty() );
14207 if ( value[0] == '[' )
14208 {
14209 std::string::size_type endPos = 0;
14210 while ( endPos + 1 != value.length() )
14211 {
14212 std::string::size_type startPos = value.find( '[', endPos );
14213 checkForError( startPos != std::string::npos, node->GetLineNum(), "could not find '[' in <" + value + ">" );
14214 endPos = value.find( ']', startPos );
14215 checkForError( endPos != std::string::npos, node->GetLineNum(), "could not find ']' in <" + value + ">" );
14216 checkForError( startPos + 2 <= endPos, node->GetLineNum(), "missing content between '[' and ']' in <" + value + ">" );
14217 arraySizes.push_back( value.substr( startPos + 1, endPos - startPos - 1 ) );
14218 }
14219 }
14220 else if ( value[0] == ':' )
14221 {
14222 bitCount = value.substr( 1 );
14223 }
14224 else
14225 {
14226 checkForError( ( value[0] == ';' ) || ( value[0] == ')' ), node->GetLineNum(), "unknown modifier <" + value + ">" );
14227 }
14228 }
14229 return std::make_pair( arraySizes, bitCount );
14230 }
14231
readSnippet(std::string const & snippetFile)14232 std::string readSnippet( std::string const & snippetFile )
14233 {
14234 std::ifstream ifs( std::string( BASE_PATH ) + "/snippets/" + snippetFile );
14235 assert( !ifs.fail() );
14236 std::ostringstream oss;
14237 oss << ifs.rdbuf();
14238 return oss.str();
14239 }
14240
replaceWithMap(std::string const & input,std::map<std::string,std::string> replacements)14241 std::string replaceWithMap( std::string const & input, std::map<std::string, std::string> replacements )
14242 {
14243 // This will match ${someVariable} and contain someVariable in match group 1
14244 std::regex re( R"(\$\{([^\}]+)\})" );
14245 auto it = std::sregex_iterator( input.begin(), input.end(), re );
14246 auto end = std::sregex_iterator();
14247
14248 // No match, just return the original string
14249 if ( it == end )
14250 {
14251 assert( replacements.empty() );
14252 return input;
14253 }
14254
14255 #if !defined( NDEBUG )
14256 std::set<std::string> matchedReplacements;
14257 #endif
14258
14259 std::string result = "";
14260 while ( it != end )
14261 {
14262 std::smatch match = *it;
14263 auto itReplacement = replacements.find( match[1].str() );
14264 assert( itReplacement != replacements.end() );
14265 #if !defined( NDEBUG )
14266 matchedReplacements.insert( match[1].str() );
14267 #endif
14268
14269 result += match.prefix().str() + ( ( itReplacement != replacements.end() ) ? itReplacement->second : match[0].str() );
14270 ++it;
14271
14272 // we've passed the last match. Append the rest of the orignal string
14273 if ( it == end )
14274 {
14275 result += match.suffix().str();
14276 }
14277 }
14278 #if !defined( NDEBUG )
14279 std::set<std::string> missedReplacements;
14280 for ( auto r : replacements )
14281 {
14282 if ( matchedReplacements.find( r.first ) == matchedReplacements.end() )
14283 {
14284 missedReplacements.insert( r.first );
14285 }
14286 }
14287 assert( missedReplacements.empty() );
14288 #endif
14289 return result;
14290 }
14291
startLowerCase(std::string const & input)14292 std::string startLowerCase( std::string const & input )
14293 {
14294 assert( !input.empty() );
14295 return static_cast<char>( tolower( input[0] ) ) + input.substr( 1 );
14296 }
14297
startUpperCase(std::string const & input)14298 std::string startUpperCase( std::string const & input )
14299 {
14300 assert( !input.empty() );
14301 return static_cast<char>( toupper( input[0] ) ) + input.substr( 1 );
14302 }
14303
stripPostfix(std::string const & value,std::string const & postfix)14304 std::string stripPostfix( std::string const & value, std::string const & postfix )
14305 {
14306 std::string strippedValue = value;
14307 if ( strippedValue.ends_with( postfix ) )
14308 {
14309 strippedValue.erase( strippedValue.length() - postfix.length() );
14310 }
14311 return strippedValue;
14312 }
14313
stripPluralS(std::string const & name,std::set<std::string> const & tags)14314 std::string stripPluralS( std::string const & name, std::set<std::string> const & tags )
14315 {
14316 std::string strippedName = name;
14317 std::string tag = findTag( tags, name );
14318 if ( strippedName.ends_with( "s" + tag ) )
14319 {
14320 size_t pos = strippedName.rfind( 's' );
14321 if ( ( 2 <= pos ) && ( strippedName.substr( pos - 2, 3 ) == "ies" ) )
14322 {
14323 strippedName.replace( pos - 2, 3, "y" );
14324 }
14325 else
14326 {
14327 strippedName.erase( pos, 1 );
14328 }
14329 }
14330 return strippedName;
14331 }
14332
stripPrefix(std::string const & value,std::string const & prefix)14333 std::string stripPrefix( std::string const & value, std::string const & prefix )
14334 {
14335 std::string strippedValue = value;
14336 if ( strippedValue.starts_with( prefix ) )
14337 {
14338 strippedValue.erase( 0, prefix.length() );
14339 }
14340 return strippedValue;
14341 }
14342
toCamelCase(std::string const & value)14343 std::string toCamelCase( std::string const & value )
14344 {
14345 assert( !value.empty() && ( isupper( value[0] ) || isdigit( value[0] ) ) );
14346 std::string result;
14347 result.reserve( value.size() );
14348 bool keepUpper = true;
14349 for ( auto c : value )
14350 {
14351 if ( c == '_' )
14352 {
14353 keepUpper = true;
14354 }
14355 else if ( isdigit( c ) )
14356 {
14357 keepUpper = true;
14358 result.push_back( c );
14359 }
14360 else if ( keepUpper )
14361 {
14362 result.push_back( c );
14363 keepUpper = false;
14364 }
14365 else
14366 {
14367 result.push_back( static_cast<char>( tolower( c ) ) );
14368 }
14369 }
14370 return result;
14371 }
14372
toUpperCase(std::string const & name)14373 std::string toUpperCase( std::string const & name )
14374 {
14375 std::string convertedName;
14376 bool previousIsLowerCase = false;
14377 bool previousIsDigit = false;
14378 for ( auto c : name )
14379 {
14380 if ( ( isupper( c ) && ( previousIsLowerCase || previousIsDigit ) ) || ( isdigit( c ) && previousIsLowerCase ) )
14381 {
14382 convertedName.push_back( '_' );
14383 }
14384 convertedName.push_back( static_cast<char>( toupper( c ) ) );
14385 previousIsLowerCase = !!islower( c );
14386 previousIsDigit = !!isdigit( c );
14387 }
14388 return convertedName;
14389 }
14390
tokenize(std::string const & tokenString,std::string const & separator)14391 std::vector<std::string> tokenize( std::string const & tokenString, std::string const & separator )
14392 {
14393 std::vector<std::string> tokens;
14394 if ( !tokenString.empty() )
14395 {
14396 size_t start = 0, end;
14397 do
14398 {
14399 end = tokenString.find( separator, start );
14400 if ( start != end )
14401 {
14402 tokens.push_back( trim( tokenString.substr( start, end - start ) ) );
14403 }
14404 start = end + separator.length();
14405 } while ( end != std::string::npos );
14406 }
14407 return tokens;
14408 }
14409
tokenizeAny(std::string const & tokenString,std::string const & separators)14410 std::vector<std::string> tokenizeAny( std::string const & tokenString, std::string const & separators )
14411 {
14412 std::vector<std::string> tokens;
14413 if ( !tokenString.empty() )
14414 {
14415 size_t start = 0, end;
14416 do
14417 {
14418 end = tokenString.find_first_of( separators, start );
14419 if ( start != end )
14420 {
14421 tokens.push_back( trim( tokenString.substr( start, end - start ) ) );
14422 }
14423 start = end + 1;
14424 } while ( end != std::string::npos );
14425 }
14426 return tokens;
14427 }
14428
trim(std::string const & input)14429 std::string trim( std::string const & input )
14430 {
14431 std::string result = input;
14432 result.erase( result.begin(), std::find_if( result.begin(), result.end(), []( char c ) { return !std::isspace( c ); } ) );
14433 result.erase( std::find_if( result.rbegin(), result.rend(), []( char c ) { return !std::isspace( c ); } ).base(), result.end() );
14434 return result;
14435 }
14436
trimEnd(std::string const & input)14437 std::string trimEnd( std::string const & input )
14438 {
14439 std::string result = input;
14440 result.erase( std::find_if( result.rbegin(), result.rend(), []( char c ) { return !std::isspace( c ); } ).base(), result.end() );
14441 return result;
14442 }
14443
trimStars(std::string const & input)14444 std::string trimStars( std::string const & input )
14445 {
14446 std::string result = input;
14447 size_t pos = result.find( '*' );
14448 while ( pos != std::string::npos )
14449 {
14450 if ( ( 0 < pos ) && ( result[pos - 1] != ' ' ) && ( result[pos - 1] != '*' ) )
14451 {
14452 result.insert( pos, 1, ' ' );
14453 ++pos;
14454 }
14455 else if ( ( pos < result.length() - 1 ) && ( result[pos + 1] != ' ' ) && ( result[pos + 1] != '*' ) )
14456 {
14457 result.insert( pos + 1, 1, ' ' );
14458 }
14459 pos = result.find( '*', pos + 1 );
14460 }
14461 return result;
14462 }
14463
writeToFile(std::string const & str,std::string const & fileName)14464 void writeToFile( std::string const & str, std::string const & fileName )
14465 {
14466 std::ofstream ofs( fileName );
14467 assert( !ofs.fail() );
14468 ofs << str;
14469 ofs.close();
14470
14471 #if defined( CLANG_FORMAT_EXECUTABLE )
14472 std::cout << "VulkanHppGenerator: Formatting " << fileName << " ..." << std::endl;
14473 std::string commandString = "\"" CLANG_FORMAT_EXECUTABLE "\" -i --style=file " + fileName;
14474 int ret = std::system( commandString.c_str() );
14475 if ( ret != 0 )
14476 {
14477 std::cout << "VulkanHppGenerator: failed to format file " << fileName << " with error <" << ret << ">\n";
14478 }
14479 #endif
14480 }
14481
toString(tinyxml2::XMLError error)14482 std::string toString( tinyxml2::XMLError error )
14483 {
14484 switch ( error )
14485 {
14486 case tinyxml2::XML_SUCCESS: return "XML_SUCCESS";
14487 case tinyxml2::XML_NO_ATTRIBUTE: return "XML_NO_ATTRIBUTE";
14488 case tinyxml2::XML_WRONG_ATTRIBUTE_TYPE: return "XML_WRONG_ATTRIBUTE_TYPE";
14489 case tinyxml2::XML_ERROR_FILE_NOT_FOUND: return "XML_ERROR_FILE_NOT_FOUND";
14490 case tinyxml2::XML_ERROR_FILE_COULD_NOT_BE_OPENED: return "XML_ERROR_FILE_COULD_NOT_BE_OPENED";
14491 case tinyxml2::XML_ERROR_FILE_READ_ERROR: return "XML_ERROR_FILE_READ_ERROR";
14492 case tinyxml2::XML_ERROR_PARSING_ELEMENT: return "XML_ERROR_PARSING_ELEMENT";
14493 case tinyxml2::XML_ERROR_PARSING_ATTRIBUTE: return "XML_ERROR_PARSING_ATTRIBUTE";
14494 case tinyxml2::XML_ERROR_PARSING_TEXT: return "XML_ERROR_PARSING_TEXT";
14495 case tinyxml2::XML_ERROR_PARSING_CDATA: return "XML_ERROR_PARSING_CDATA";
14496 case tinyxml2::XML_ERROR_PARSING_COMMENT: return "XML_ERROR_PARSING_COMMENT";
14497 case tinyxml2::XML_ERROR_PARSING_DECLARATION: return "XML_ERROR_PARSING_DECLARATION";
14498 case tinyxml2::XML_ERROR_PARSING_UNKNOWN: return "XML_ERROR_PARSING_UNKNOWN";
14499 case tinyxml2::XML_ERROR_EMPTY_DOCUMENT: return "XML_ERROR_EMPTY_DOCUMENT";
14500 case tinyxml2::XML_ERROR_MISMATCHED_ELEMENT: return "XML_ERROR_MISMATCHED_ELEMENT";
14501 case tinyxml2::XML_ERROR_PARSING: return "XML_ERROR_PARSING";
14502 case tinyxml2::XML_CAN_NOT_CONVERT_TEXT: return "XML_CAN_NOT_CONVERT_TEXT";
14503 case tinyxml2::XML_NO_TEXT_NODE: return "XML_NO_TEXT_NODE";
14504 default: return "unknown error code <" + std::to_string( error ) + ">";
14505 }
14506 }
14507
main(int argc,char ** argv)14508 int main( int argc, char ** argv )
14509 {
14510 try
14511 {
14512 tinyxml2::XMLDocument doc;
14513
14514 std::string filename = ( argc == 1 ) ? VK_SPEC : argv[1];
14515
14516 #if defined( CLANG_FORMAT_EXECUTABLE )
14517 std::cout << "VulkanHppGenerator: Found ";
14518 std::string commandString = "\"" CLANG_FORMAT_EXECUTABLE "\" --version ";
14519 int ret = std::system( commandString.c_str() );
14520 if ( ret != 0 )
14521 {
14522 std::cout << "VulkanHppGenerator: failed to determine clang_format version with error <" << ret << ">\n";
14523 }
14524 #endif
14525
14526 std::cout << "VulkanHppGenerator: Loading " << filename << std::endl;
14527 tinyxml2::XMLError error = doc.LoadFile( filename.c_str() );
14528 if ( error != tinyxml2::XML_SUCCESS )
14529 {
14530 std::cout << "VulkanHppGenerator: failed to load file " << filename << " with error <" << toString( error ) << ">" << std::endl;
14531 return -1;
14532 }
14533
14534 std::cout << "VulkanHppGenerator: Parsing " << filename << std::endl;
14535 VulkanHppGenerator generator( doc );
14536
14537 generator.generateVulkanHppFile();
14538 generator.generateVulkanEnumsHppFile();
14539 generator.generateVulkanFormatTraitsHppFile();
14540 generator.prepareVulkanFuncs();
14541 generator.generateVulkanFuncsHppFile();
14542 generator.generateVulkanHandlesHppFile();
14543 generator.generateVulkanHashHppFile();
14544 generator.prepareRAIIHandles();
14545 generator.generateVulkanRAIIHppFile();
14546 generator.generateVulkanStaticAssertionsHppFile();
14547 generator.generateVulkanStructsHppFile();
14548 generator.generateVulkanToStringHppFile();
14549
14550 #if !defined( CLANG_FORMAT_EXECUTABLE )
14551 std::cout << "VulkanHppGenerator: could not find clang-format. The generated files will not be formatted accordingly.\n";
14552 #endif
14553 }
14554 catch ( std::exception const & e )
14555 {
14556 std::cout << "caught exception: " << e.what() << std::endl;
14557 return -1;
14558 }
14559 catch ( ... )
14560 {
14561 std::cout << "caught unknown exception" << std::endl;
14562 return -1;
14563 }
14564 }
14565