From 0b8dfc3968358aed98f2398aee244f067444331f Mon Sep 17 00:00:00 2001 From: Markus Tavenrath Date: Tue, 16 Feb 2016 15:07:55 +0100 Subject: [PATCH] Initial revision for Vulkan 1.0 --- CMakeLists.txt | 69 ++ LICENSE.txt | 25 + README.md | 191 +++++ main.cpp | 1887 ++++++++++++++++++++++++++++++++++++++++++++++++ 4 files changed, 2172 insertions(+) create mode 100644 CMakeLists.txt create mode 100644 LICENSE.txt create mode 100644 README.md create mode 100644 main.cpp diff --git a/CMakeLists.txt b/CMakeLists.txt new file mode 100644 index 0000000..5428f85 --- /dev/null +++ b/CMakeLists.txt @@ -0,0 +1,69 @@ +# Copyright(c) 2015-2016, NVIDIA CORPORATION. All rights reserved. +# +# Redistribution and use in source and binary forms, with or without +# modification, are permitted provided that the following conditions +# are met: +# * Redistributions of source code must retain the above copyright +# notice, this list of conditions and the following disclaimer. +# * Redistributions in binary form must reproduce the above copyright +# notice, this list of conditions and the following disclaimer in the +# documentation and/or other materials provided with the distribution. +# * Neither the name of NVIDIA CORPORATION nor the names of its +# contributors may be used to endorse or promote products derived +# from this software without specific prior written permission. +# +# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +# EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +# IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +# PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +# OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +# (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +# OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +cmake_minimum_required(VERSION 3.2) + +project(VkCppGenerator) + +if(NOT EXISTS "${CMAKE_SOURCE_DIR}/tinyxml/tinyxml.cpp") + message(FATAL_ERROR, "TinyXML is missing. Please download the latest version from http://www.grinninglizard.com/tinyxml/index.html and put the sources in a folder named 'tinyxml'") +endif() + +set(HEADERS +) + +set(SOURCES + main.cpp +) + +set(TINYXML_SOURCES + tinyxml/tinyxml.cpp + tinyxml/tinyxmlerror.cpp + tinyxml/tinyxmlparser.cpp + tinyxml/tinystr.cpp +) + +set(TINYXML_HEADERS + tinyxml/tinyxml.h + tinyxml/tinystr.h +) + +source_group(headers FILES ${HEADERS}) +source_group(sources FILES ${SOURCES}) + +source_group(TinyXML\\headers FILES ${TINYXML_HEADERS}) +source_group(TinyXML\\sources FILES ${TINYXML_SOURCES}) + +add_executable(VkCppGenerator + ${HEADERS} + ${SOURCES} + ${TINYXML_SOURCES} + ${TINYXML_HEADERS} +) + +set_property(TARGET VkCppGenerator PROPERTY CXX_STANDARD 11) + +target_include_directories(VkCppGenerator PRIVATE "${CMAKE_SOURCE_DIR}/tinyxml") diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..c42c65d --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,25 @@ +Copyright(c) 2015-2016, NVIDIA CORPORATION. All rights reserved. + +Redistribution and use in source and binary forms, with or without +modification, are permitted provided that the following conditions +are met: + * Redistributions of source code must retain the above copyright + notice, this list of conditions and the following disclaimer. + * Redistributions in binary form must reproduce the above copyright + notice, this list of conditions and the following disclaimer in the + documentation and/or other materials provided with the distribution. + * Neither the name of NVIDIA CORPORATION nor the names of its + contributors may be used to endorse or promote products derived + from this software without specific prior written permission. + +THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..615f35d --- /dev/null +++ b/README.md @@ -0,0 +1,191 @@ +# Open-Source Vulkan C++ API + +Vulkan is a C API and as such inherits all common pitfalls of using a general C programming library. The motivation of a low-level Vulkan C++ API is to avoid these common pitfalls by applying commonly known C++ features while keeping the overall structure of a Vulkan program and preserving the full freedom it provides as low-level graphics API. An additional guideline we followed was not to introduce additional runtime overhead by providing a header-only library with inline functions. + +Have a look at the following piece of code which creates a VkImage: + +
+
+  VkImageCreateInfo ci;
+  ci.sType = VK_STRUCTURE_TYPE_IMAGE_CREATE_INFO;
+  ci.pNext = nullptr;
+  ci.flags = ...some flags...;
+  ci.imageType = VK_IMAGE_TYPE_2D;
+  ci.format = VK_FORMAT_R8G8B8A8_UNORM;
+  ci.extent = VkExtent3D { width, height, 1 };
+  ci.mipLevels = 1;
+  ci.arrayLayers = 1;
+  ci.samples = VK_SAMPLE_COUNT_1_BIT;
+  ci.tiling = VK_IMAGE_TILING_OPTIMAL;
+  ci.usage = VK_IMAGE_USAGE_COLOR_ATTACHMENT_BIT;
+  ci.sharingMode = VK_SHARING_MODE_EXCLUSIVE;
+  ci.queueFamilyIndexCount = 0;
+  ci.pQueueFamilyIndices = 0;
+  ci.initialLayout = VK_IMAGE_LAYOUT_UNDEFINED;
+  vkCreateImage(device, &ci, allocator, &image));
+
+
+ +There may be some issues that can happen when filling the structure which cannot be caught at compile time: + +* initialization of ci.sType using wrong enum values +* uninitialized data fields (e.g. missing initialization of ci.mipLevels) +* use of invalid bits for ci.flags (no type-safety for bits) +* use of incorrect enums for fields (no type-safety for enums) + +These initializations will most likely show up as random runtime errors, which usually are nasty and time-consuming to debug. +Our auto-generated, C++ 11-conform layer uses commonly known C++ features like implicit initialization through constructors +to avoid incorrect or missing initializations and introduces type-safety with scoped enums to turn explicit initialization +errors into compile errors. Following is a list of features and conventions introduced by our Vulkan C++ layer: + +* works along the official C version of the API +* defines all symbols within the 'vk' namespace and to avoid redundancy the vk/Vk/VK_ prefixes have been removed from all symbols, i.e. vk::commandBindPipeline for vkCommandBindPipeline. +* camel case syntax with an 'e' prefix has been introduced for all enums, i.e. vk::ImageType::e2D (the prefix was a compromise, more about that later) removes the 'BIT' suffix from all flag related enums, i.e. vk::ImageUsage::eColorAttachment. +* introduces constructors for all structs, which by default set the appropriate sType and all other values to zero. +* encapsulates member variables of the structs with getter and setter functions, i.e. ci.imageType() to get a value and ci.imageType(vk::ImageType::e2D) to set a value. + +With those changes applied, the updated code snippet looks like this: + +
+
+vk::ImageCreateInfo ci;
+ci.flags(...some flags...);
+ci.imageType(vk::ImageType::e2D);
+ci.format(vk::Format::eR8G8B8A8Unorm);
+ci.extent(vk::Extent3D { width, height, 1 });
+ci.mipLevels(1);
+ci.arrayLayers(1);
+ci.samples(1);
+ci.tiling(vk::ImageTiling::eOptimal);
+ci.usage(vk::ImageUsage::eColorAttachment);
+ci.sharingMode(vk::SharingMode::eExclusive);
+  // ci.queueFamilyIndexCount(0)	// no need to set, already initialized
+  // ci.pQueueFamilyIndices(0)	// no need to set, already initialized
+ci.initialLayout(vk::ImageLayout::eUndefined);
+vk::createImage(device, &ci, allocator, &image));
+
+
+ +Which is a total of 13 lines of code, versus 17 lines for the C version. In addition, this code is more robust as described above. + +# Type-safe Enums + +Splitting up the C enums into a namespace and scoped enums resulted in two compilation issues. +First some enums started with a digit like vk::ImageType::1D which resulted in a compilation error. +Second, there's the risk that upper symbols like vk::CompositeAlphaFlagBitsKHR::OPAQUE do clash with preprocessor defines. +In the given example OPAQUE has been defined in win32gdi.h resulting a compilation error. + +To overcome those two issues the symbols have been converted to camel case and the prefix 'e' has been added so that each enum starts with a letter. + +# Improvements to Bit Flags + +After those changes the code might look more familiar to C++ developers, but there is still no gain with regards to safety. + With C++ features available we replaced all Vulkan enums with scoped enums to achieve type safety which already uncovered +a few small issues in our code. The good thing with scoped enums is that there is no implicit casts to integer types anymore. +The downside is that OR'ing the bits for the flags does not work anymore without an explicit cast. As a solution to this problem +we have introduced a new vk::Flags<T> template which is used for all flags. This class supports the standard +operations one usually needs on bitmasks like &=, |=, & and |. Except for the initialization with 0, which is being replaced by +the default constructor, the vk::Flags<T> class works exactly like a normal bitmask with the improvement that +it is impossible to set bits not specified by the corresponding enum. To generate a bit mask with two bits set write: + +
+
+ci.usage = vk::ImageUsage::eColorAttachment | vk::ImageUsage::eStorage;
+
+
+ +By adding the scoped enums and vk::Flags<T> the C++ API provides type safety for all enums and flags which is a +big improvement. This leaves the remaining issue that the compiler might not detect uninitialized fields in structs. As a solution +we have added constructors to all structs which accept all values defined by the corresponding struct. + +
+
+vk::ImageCreateInfo ci(
+  ...some flags..., vk::ImageType::e2D, vk::Format::eR8G8B8A8Unorm,
+  vk::Extent3D { width, height, 1 }, 1, 1,
+  vk::SampleCount::e1, vk::ImageTiling::eOptimal,
+  vk::ImageUsage::eColorAttachment, vk::SharingMode::eExclusive,
+  0, 0, vk::ImageLayout::eUndefined);
+
+
+ +# Alternative Initialization of Structs + +Another nice feature of those constructors is that sType is being initialized internally and thus is always correct. + +Finally, we have added a default constructor to each struct which initializes all values to 0 to allow setting the values with the named parameter idiom which is similar to the designated initializer list of C99. + +
+
+vk::ImageCreateInfo ci = vk::ImageCreateInfo()
+  .flags(...some flags...)
+  .imageType(vk::ImageType::e2D)
+  .format(vk::Format::eR8G8B8A8Unorm)
+  .extent(vk::Extent3D { width, height, 1 })
+  .mipLevels(1)
+  .arrayLayers(1)
+  .samples(1)
+  .tiling(vk::ImageTiling::eOptimal)
+  .usage(vk::ImageUsage::eColorAttachment)
+  .sharingMode(vk::SharingMode::eExclusive)
+  // .queueFamilyIndexCount(0)	// no need to set, already initialized
+  // .pQueueFamilyIndices(0)	// no need to set, already initialized
+  .initialLayout(vk::ImageLayout::eUndefined);
+vk::createImage(device, &ci, allocator, &image));
+
+
+ + +# Enhancements beyond the API +While mapping the Vulkan API to C++ without adding new functions is already a big help, one can do even more by adding new functionality. For example several C++ developers tend to use std::string and std::vector in their code, therefore we have added some more optional convenience features: + +* Use std::string instead of const char * for strings +* Use std::vector instead of (count, ptr) for sized arrays +* Throw exceptions instead of error return values (in progress) +* Return handles/vectors where applicable, i.e. for the create* functions + +As example let's examine the device extension property enumeration in Vulkan: + +
+
+    uint32_t count;
+    VK_VERIFY(vk::enumerateDeviceExtensionProperties(physicalDevice, layerName.c_str(), &count, nullptr));
+
+    std::vector properties(count);
+    VK_VERIFY(vk::enumerateDeviceExtensionProperties(physicalDevice, layerName.c_str(), &count, properties.data()));
+
+
+ +Luckily the official Khronos-provided vk.xml has enough information to figure out which pair of values represents a sized array or strings, so that it is possible to generate a function which allows you to write the following line of code instead: + +
+
+    std::vector<ExtensionProperties> properties = vk::enumerateDeviceExtensionProperties(physicalDevice, layerName);
+
+
+ +# Usage +To start with the C++ version of the Vulkan API download header from GIT, put it in a vulkan subdirectory and add +#include <vulkan/vk_cpp.h> to your source code. + +To build the header for a given vk.xml specification continue with the following steps: + +* Build VkCppGenerator +* Grab your favourite version vk.xml from Khronos +* Version 1.0 of the API has a tiny bug. The section of the VK_KHR_display extension is missing one symbol which +can easily be fixed by adding the following line +
+                <type name="VkDisplayPlaneAlphaFlagsKHR"/>
+
+before this line: +
+                <type name="VkDisplayPlaneAlphaFlagBitsKHR"/>
+
+* Excute VkCppGenerator <vk.xml> to generate vk_cpp.h in the current working directory. + +# Build instructions for VkCppGenerator + +* Clone the repository +* Download tinyxml from http://www.grinninglizard.com/tinyxml/index.html and extract it in the source folder +* Use CMake to generate a solution or makefile for your favourite build environment +* Launch the build diff --git a/main.cpp b/main.cpp new file mode 100644 index 0000000..5bb2b47 --- /dev/null +++ b/main.cpp @@ -0,0 +1,1887 @@ +// Copyright(c) 2015-2016, NVIDIA CORPORATION. All rights reserved. +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions +// are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of NVIDIA CORPORATION nor the names of its +// contributors may be used to endorse or promote products derived +// from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE +// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR +// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, +// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, +// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR +// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY +// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE +// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define VK_PROTOTYPES + +const std::string licenseHeader( +"// Copyright(c) 2015-2016, NVIDIA CORPORATION. All rights reserved.\n" +"//\n" +"// Redistribution and use in source and binary forms, with or without\n" +"// modification, are permitted provided that the following conditions\n" +"// are met:\n" +"// * Redistributions of source code must retain the above copyright\n" +"// notice, this list of conditions and the following disclaimer.\n" +"// * Redistributions in binary form must reproduce the above copyright\n" +"// notice, this list of conditions and the following disclaimer in the\n" +"// documentation and/or other materials provided with the distribution.\n" +"// * Neither the name of NVIDIA CORPORATION nor the names of its\n" +"// contributors may be used to endorse or promote products derived\n" +"// from this software without specific prior written permission.\n" +"//\n" +"// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS ``AS IS'' AND ANY\n" +"// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE\n" +"// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR\n" +"// PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR\n" +"// CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,\n" +"// EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,\n" +"// PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR\n" +"// PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY\n" +"// OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT\n" +"// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE\n" +"// OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.\n" +); + +const std::string flagsHeader( +" template \n" +" class Flags\n" +" {\n" +" public:\n" +" Flags()\n" +" : m_mask(0)\n" +" {\n" +" }\n" +" \n" +" Flags(BitType bit)\n" +" : m_mask(static_cast(bit))\n" +" {\n" +" }\n" +" \n" +" Flags(Flags const& rhs)\n" +" : m_mask(rhs.m_mask)\n" +" {\n" +" }\n" +" \n" +" Flags & operator=(Flags const& rhs)\n" +" {\n" +" m_mask = rhs.m_mask;\n" +" return *this;\n" +" }\n" +" \n" +" Flags & operator|=(Flags const& rhs)\n" +" {\n" +" m_mask |= rhs.m_mask;\n" +" return *this;\n" +" }\n" +" \n" +" Flags & operator&=(Flags const& rhs)\n" +" {\n" +" m_mask &= rhs.m_mask;\n" +" return *this;\n" +" }\n" +" \n" +" Flags & operator^=(Flags const& rhs)\n" +" {\n" +" m_mask ^= rhs.m_mask;\n" +" return *this;\n" +" }\n" +" \n" +" Flags operator|(Flags const& rhs) const\n" +" {\n" +" Flags result(*this);\n" +" result |= rhs;\n" +" return result;\n" +" }\n" +" \n" +" Flags operator&(Flags const& rhs) const\n" +" {\n" +" Flags result(*this);\n" +" result &= rhs;\n" +" return result;\n" +" }\n" +" \n" +" Flags operator^(Flags const& rhs) const\n" +" {\n" +" Flags result(*this);\n" +" result ^= rhs;\n" +" return result;\n" +" }\n" +" \n" +" bool operator!() const\n" +" {\n" +" return !m_mask;\n" +" }\n" +" \n" +" bool operator==(Flags const& rhs) const\n" +" {\n" +" return m_mask == rhs.m_mask;\n" +" }\n" +" \n" +" bool operator!=(Flags const& rhs) const\n" +" {\n" +" return m_mask != rhs.m_mask;\n" +" }\n" +" \n" +" operator bool() const\n" +" {\n" +" return !!m_mask;\n" +" }\n" +" \n" +" private:\n" +" MaskType m_mask;\n" +" };\n" +" \n" +" template \n" +" Flags operator|(BitType bit, Flags const& flags)\n" +" {\n" +" return flags | bit;\n" +" }\n" +" \n" +" template \n" +" Flags operator&(BitType bit, Flags const& flags)\n" +" {\n" +" return flags & bit;\n" +" }\n" +" \n" +" template \n" +" Flags operator^(BitType bit, Flags const& flags)\n" +" {\n" +" return flags ^ bit;\n" +" }\n" +"\n" +); + +struct MemberData +{ + std::string type; + std::string name; + std::string arraySize; + std::string pureType; + std::string len; +}; + +struct StructData +{ + bool returnedOnly; + std::vector members; +}; + +struct NameValue +{ + std::string name; + std::string value; +}; + +struct EnumData +{ + bool bitmask; + std::vector members; +}; + +struct CommandData +{ + std::string returnType; + std::vector arguments; +}; + +struct ExtensionData +{ + std::string name; + std::string protect; + std::vector elements; +}; + +struct DependencyData +{ + enum class Category + { + COMMAND, + ENUM, + FLAGS, + FUNC_POINTER, + HANDLE, + REQUIRED, + SCALAR, + STRUCT, + UNION + }; + + DependencyData( Category c, std::string const& n ) + : category(c) + , name(n) + {} + + Category category; + std::string name; + std::set dependencies; + size_t extension; +}; + +void createDefaults( std::vector const& dependencies, std::map const& enums, std::map & defaultValues ); +size_t findComplexIndex(CommandData const& commandData, std::vector> const& lenParameters); +size_t findReturnIndex(CommandData const& commandData, std::vector> const& lenParameters); +std::vector> getLenParameters(CommandData const& commandData); +bool noDependencies(std::set const& dependencies, std::map & listedTypes); +void readCommandParam( TiXmlElement * element, DependencyData & typeData, std::vector & arguments ); +CommandData & readCommandProto( TiXmlElement * element, std::list & dependencies, std::map & commands ); +void readCommands( TiXmlElement * element, std::list & dependencies, std::map & commands ); +void readCommandsCommand( TiXmlElement * element, std::list & dependencies, std::map & commands ); +void readEnums( TiXmlElement * element, std::list & dependencies, std::map & enums, std::set & vkTypes ); +void readEnumsEnum( TiXmlElement * element, std::string const& prefix, std::string const& postfix, EnumData & enumData ); +void readExtensionRequire( TiXmlElement * element, std::vector & elements ); +void readExtensions( TiXmlElement * element, std::vector & extensions ); +void readExtensionsExtension( TiXmlElement * element, std::vector & extensions ); +void readTypeBasetype( TiXmlElement * element, std::list & dependencies ); +void readTypeBitmask( TiXmlElement * element, std::list & dependencies, std::set & flags, std::set & vkTypes ); +void readTypeDefine( TiXmlElement * element, std::string & version ); +void readTypeFuncpointer( TiXmlElement * element, std::list & dependencies ); +void readTypeHandle( TiXmlElement * element, std::list & dependencies ); +void readTypeStruct( TiXmlElement * element, std::list & dependencies, std::map & structs, std::set & vkTypes ); +void readTypeStructMember( TiXmlElement * element, std::vector & members, std::set & dependencies ); +void readTypeUnion( TiXmlElement * element, std::list & dependencies, std::map & structs, std::set & vkTypes ); +void readTypeUnionMember( TiXmlElement * element, std::vector & members, std::set & dependencies ); +void readTypes( TiXmlElement * element, std::string & version, std::list & dependencies, std::set & flags, std::map & structs, std::set & vkTypes ); +void sortDependencies( std::list & dependencies, std::vector const& extensions, std::vector> & sortedDependencies ); +std::string reduceName(std::string const& name); +std::string strip( std::string const& value, std::string const& prefix ); +std::string toCamelCase(std::string const& value); +std::string toUpperCase(std::string const& name); +void writeMemberData(std::ofstream & ofs, MemberData const& memberData, std::set const& vkTypes); +void writeStructConstructor( std::ofstream & ofs, std::string const& name, std::string const& memberName, StructData const& structData, std::set const& vkTypes, std::map const& defaultValues ); +void writeStructGetter( std::ofstream & ofs, MemberData const& memberData, std::string const& memberName, std::set const& vkTypes ); +void writeStructSetter( std::ofstream & ofs, std::string const& name, MemberData const& memberData, std::string const& memberName, std::set const& vkTypes, std::map const& structs ); +void writeTypeCommand( std::ofstream & ofs, DependencyData const& dependencyData, CommandData const& commandData, std::set const& vkTypes ); +void writeTypeCommandEnhanced(std::ofstream & ofs, DependencyData const& dependencyData, CommandData const& commandData, std::set const& vkTypes); +void writeTypeCommandStandard(std::ofstream & ofs, DependencyData const& dependencyData, CommandData const& commandData, std::set const& vkTypes); +void writeTypeCommandComplexBody(std::ofstream & ofs, DependencyData const& dependencyData, CommandData const& commandData, std::map const& nameMap, std::vector> const& lenParameters, std::set const& argIndices, size_t complexIndex, size_t returnIndex); +void writeTypeCommandSimpleBody(std::ofstream & ofs, DependencyData const& dependencyData, CommandData const& commandData, std::map const& nameMap, std::set const& argIndices, std::map> const& sizeIndices); +void writeTypeEnum(std::ofstream & ofs, DependencyData const& dependencyData, EnumData const& enumData); +void writeTypeFlags( std::ofstream & ofs, DependencyData const& dependencyData ); +void writeTypeHandle( std::ofstream & ofs, DependencyData const& dependencyData ); +void writeTypeScalar( std::ofstream & ofs, DependencyData const& dependencyData ); +void writeTypeStruct( std::ofstream & ofs, DependencyData const& dependencyData, std::set const& vkTypes, std::map const& structs, std::map const& defaultValues ); +void writeTypeUnion( std::ofstream & ofs, DependencyData const& dependencyData, StructData const& unionData, std::set const& vkTypes, std::map const& structs, std::map const& defaultValues ); +void writeTypes( std::ofstream & ofs, std::vector const& dependencies, std::map const& commands, std::map const& enums, std::map const& structs, std::map const& defaultValues, std::set const& vkTypes ); +void writeVersionCheck( std::ofstream & ofs, std::string const& version ); + +void createDefaults( std::vector const& dependencies, std::map const& enums, std::map & defaultValues ) +{ + for ( std::vector::const_iterator it = dependencies.begin() ; it != dependencies.end() ; ++it ) + { + assert( defaultValues.find( it->name ) == defaultValues.end() ); + switch( it->category ) + { + case DependencyData::Category::COMMAND : // commands should never be asked for defaults + break; + case DependencyData::Category::ENUM : + assert( enums.find( it->name ) != enums.end() ); + defaultValues[it->name] = it->name + "::" + enums.find( it->name )->second.members.front().name; + break; + case DependencyData::Category::FLAGS : + case DependencyData::Category::STRUCT : + case DependencyData::Category::UNION : // just call the default constructor for flags, structs, and structs (which are mapped to classes) + defaultValues[it->name] = it->name + "()"; + break; + case DependencyData::Category::FUNC_POINTER : // func_pointers explicitly have no default! + defaultValues[it->name]; + break; + case DependencyData::Category::HANDLE : // handles are pointers + defaultValues[it->name] = "nullptr"; + break; + case DependencyData::Category::REQUIRED : // all required default to "0" + case DependencyData::Category::SCALAR : // all scalars default to "0" + defaultValues[it->name] = "0"; + break; + default : + assert( false ); + break; + } + } +} + +size_t findComplexIndex(CommandData const& commandData, std::vector> const& lenParameters) +{ + for (size_t i = 0; i < lenParameters.size(); i++) + { + if ((lenParameters[i].second != ~0) && (commandData.arguments[lenParameters[i].second].type.find("*") != std::string::npos)) + { +#if !defined(NDEBUG) + for (size_t j = i + 1; j < lenParameters.size(); j++) + { + assert((lenParameters[i].second == ~0) || (commandData.arguments[lenParameters[i].second].type.find("*") == std::string::npos)); + } +#endif + return i; + } + } + return ~0; +} + +size_t findReturnIndex(CommandData const& commandData, std::vector> const& lenParameters) +{ + for (size_t i = 0; i < lenParameters.size(); i++) + { + if (commandData.arguments[lenParameters[i].first].type.find("const") == std::string::npos) + { +#if !defined(NDEBUG) + for (size_t j = i + 1; j < lenParameters.size(); j++) + { + assert(commandData.arguments[lenParameters[j].first].type.find("const") == 0); + } +#endif + return i; + } + } + return ~0; +} + +std::vector> getLenParameters(CommandData const& commandData) +{ + std::vector> lenParameters; + for (size_t i = 0; i < commandData.arguments.size(); i++) + { + if (!commandData.arguments[i].len.empty()) + { + lenParameters.push_back(std::make_pair(i, ~0)); + for (size_t j = 0; j < commandData.arguments.size(); j++) + { + if (commandData.arguments[i].len == commandData.arguments[j].name) + { + lenParameters.back().second = j; + } + } + assert( (lenParameters.back().second != ~0) + || (commandData.arguments[i].len == "dataSize/4") + || (commandData.arguments[i].len == "null-terminated") + || (commandData.arguments[i].len == "pAllocateInfo->descriptorSetCount") + || (commandData.arguments[i].len == "pAllocateInfo->commandBufferCount")); + assert((lenParameters.back().second == ~0) || (lenParameters.back().second < lenParameters.back().first)); + } + } + return std::move(lenParameters); +} + +bool noDependencies(std::set const& dependencies, std::set & listedTypes) +{ + bool ok = true; + for ( std::set::const_iterator it = dependencies.begin() ; it != dependencies.end() && ok ; ++it ) + { + ok = ( listedTypes.find( *it ) != listedTypes.end() ); + } + return( ok ); +} + +void readCommandParam( TiXmlElement * element, DependencyData & typeData, std::vector & arguments ) +{ + arguments.push_back( MemberData() ); + MemberData & arg = arguments.back(); + + if (element->Attribute("len")) + { + arg.len = element->Attribute("len"); + } + + TiXmlNode * child = element->FirstChild(); + assert( child ); + if ( child->Type() == TiXmlNode::TINYXML_TEXT ) + { + assert( ( strcmp( child->Value(), "const" ) == 0 ) || ( strcmp( child->Value(), "struct" ) == 0 ) ); + arg.type = std::string( child->Value() ) + " "; + child = child->NextSibling(); + assert( child ); + } + + assert( child->Type() == TiXmlNode::TINYXML_ELEMENT ); + assert( ( strcmp( child->Value(), "type" ) == 0 ) && child->ToElement() && child->ToElement()->GetText() ); + std::string type = strip( child->ToElement()->GetText(), "Vk" ); + typeData.dependencies.insert( type ); + arg.type += type; + arg.pureType = type; + + child = child->NextSibling(); + assert( child ); + if ( child->Type() == TiXmlNode::TINYXML_TEXT ) + { + std::string value = child->Value(); + assert( ( value == "*" ) || ( value == "**" ) || ( value == "* const*" ) ); + arg.type += value; + child = child->NextSibling(); + } + + assert( ( child->Type() == TiXmlNode::TINYXML_ELEMENT ) && ( strcmp( child->Value(), "name" ) == 0 ) && child->ToElement() ); + arg.name = child->ToElement()->GetText(); + + if ( arg.name.back() == ']' ) + { + assert( !child->NextSibling() ); + size_t pos = arg.name.find( '[' ); + assert( pos != std::string::npos ); + arg.arraySize = arg.name.substr( pos + 1, arg.name.length() - 2 - pos ); + arg.name.erase( pos ); + } + + child = child->NextSibling(); + if ( child ) + { + if ( child->Type() == TiXmlNode::TINYXML_TEXT ) + { + std::string value = child->Value(); + if ( value == "[" ) + { + child = child->NextSibling(); + assert( child ); + assert( ( child->Type() == TiXmlNode::TINYXML_ELEMENT ) && ( strcmp( child->Value(), "enum" ) == 0 ) ); + arg.arraySize = child->ToElement()->GetText(); + child = child->NextSibling(); + assert( child ); + assert( child->Type() == TiXmlNode::TINYXML_TEXT ); + assert( strcmp( child->Value(), "]" ) == 0 ); + assert( !child->NextSibling() ); + } + else + { + assert( ( value.front() == '[' ) && ( value.back() == ']' ) ); + arg.arraySize = value.substr( 1, value.length() - 2 ); + assert( !child->NextSibling() ); + } + } + } +} + +CommandData & readCommandProto( TiXmlElement * element, std::list & dependencies, std::map & commands ) +{ + TiXmlElement * typeElement = element->FirstChildElement(); + assert( typeElement && ( strcmp( typeElement->Value(), "type" ) == 0 ) ); + TiXmlElement * nameElement = typeElement->NextSiblingElement(); + assert( nameElement && ( strcmp( nameElement->Value(), "name" ) == 0 ) ); + assert( !nameElement->NextSiblingElement() ); + + std::string type = strip( typeElement->GetText(), "Vk" ); + + std::string name = strip( nameElement->GetText(), "vk" ); + assert( isupper( name[0] ) ); + name[0] = tolower( name[0] ); + + dependencies.push_back( DependencyData( DependencyData::Category::COMMAND, name ) ); + assert( commands.find( name ) == commands.end() ); + std::map::iterator it = commands.insert( std::make_pair( name, CommandData() ) ).first; + it->second.returnType = type; + + return it->second; +} + +void readCommands( TiXmlElement * element, std::list & dependencies, std::map & commands ) +{ + TiXmlElement * child = element->FirstChildElement(); + assert( child ); + do + { + assert( strcmp( child->Value(), "command" ) == 0 ); + readCommandsCommand( child, dependencies, commands ); + } while ( child = child->NextSiblingElement() ); +} + +void readCommandsCommand( TiXmlElement * element, std::list & dependencies, std::map & commands ) +{ + TiXmlElement * child = element->FirstChildElement(); + assert( child && ( strcmp( child->Value(), "proto" ) == 0 ) ); + + CommandData & commandData = readCommandProto( child, dependencies, commands ); + + while ( child = child->NextSiblingElement() ) + { + std::string value = child->Value(); + if ( value == "param" ) + { + readCommandParam(child, dependencies.back(), commandData.arguments); + } + else + { + assert( ( value == "implicitexternsyncparams" ) || ( value == "validity" ) ); + } + } +} + +void readEnums( TiXmlElement * element, std::list & dependencies, std::map & enums, std::set & vkTypes ) +{ + assert( element->Attribute( "name" ) ); + std::string name = strip( element->Attribute( "name" ), "Vk" ); + if ( name != "API Constants" ) + { + dependencies.push_back( DependencyData( DependencyData::Category::ENUM, name ) ); + std::map::iterator it = enums.insert( std::make_pair( name, EnumData() ) ).first; + + assert( element->Attribute( "type" ) ); + std::string type = element->Attribute( "type" ); + assert( ( type == "bitmask" ) || ( type == "enum" ) ); + it->second.bitmask = ( type == "bitmask" ); + std::string prefix, postfix; + if ( it->second.bitmask ) + { + size_t pos = name.find( "FlagBits" ); + assert( pos != std::string::npos ); + prefix = "VK" + toUpperCase( name.substr( 0, pos ) ) + "_"; + postfix = "Bit"; + } + else + { + prefix = "VK" + toUpperCase( name ) + "_"; + } + + readEnumsEnum( element, prefix, postfix, it->second ); + + assert( vkTypes.find( name ) == vkTypes.end() ); + vkTypes.insert( name ); + } +} + +void readEnumsEnum( TiXmlElement * element, std::string const& prefix, std::string const& postfix, EnumData & enumData ) +{ + TiXmlElement * child = element->FirstChildElement(); + do + { + if ( child->Attribute( "name" ) ) + { + enumData.members.push_back( NameValue() ); + enumData.members.back().name = "e" + toCamelCase( strip( child->Attribute( "name" ), prefix ) ); + enumData.members.back().value = child->Attribute( "name" ); + if ( !postfix.empty() ) + { + size_t pos = enumData.members.back().name.find( postfix ); + if ( pos != std::string::npos ) + { + enumData.members.back().name.erase( pos ); + } + } + } + } while ( child = child->NextSiblingElement() ); +} + +void readExtensionRequire( TiXmlElement * element, std::vector & elements ) +{ + TiXmlElement * child = element->FirstChildElement(); + do + { + std::string value = child->Value(); + assert( child->Attribute( "name" ) ); + if ( value == "command" ) + { + elements.push_back( strip( child->Attribute( "name" ), "vk" ) ); + assert( isupper( elements.back()[0] ) ); + elements.back()[0] = tolower( elements.back()[0] ); + } + else if ( value == "type" ) + { + elements.push_back( strip( child->Attribute( "name" ), "Vk" ) ); + } + else + { + assert( value == "enum" ); + } + } while ( child = child->NextSiblingElement() ); +} + +void readExtensions( TiXmlElement * element, std::vector & extensions ) +{ + TiXmlElement * child = element->FirstChildElement(); + assert( child ); + do + { + assert( strcmp( child->Value(), "extension" ) == 0 ); + readExtensionsExtension( child, extensions ); + } while ( child = child->NextSiblingElement() ); +} + +void readExtensionsExtension( TiXmlElement * element, std::vector & extensions ) +{ + extensions.push_back( ExtensionData() ); + ExtensionData & ext = extensions.back(); + + assert( element->Attribute( "name" ) ); + ext.name = element->Attribute( "name" ); + if ( element->Attribute( "protect" ) ) + { + ext.protect = element->Attribute( "protect" ); + } + + TiXmlElement * child = element->FirstChildElement(); + assert( child && ( strcmp( child->Value(), "require" ) == 0 ) && !child->NextSiblingElement() ); + readExtensionRequire( child, ext.elements ); +} + +void readTypeBasetype( TiXmlElement * element, std::list & dependencies ) +{ + TiXmlElement * typeElement = element->FirstChildElement(); + assert( typeElement && ( strcmp( typeElement->Value(), "type" ) == 0 ) && typeElement->GetText() ); + std::string type = typeElement->GetText(); + assert( ( type == "uint32_t" ) || ( type == "uint64_t" ) ); + + TiXmlElement * nameElement = typeElement->NextSiblingElement(); + assert( nameElement && ( strcmp( nameElement->Value(), "name" ) == 0 ) && nameElement->GetText() ); + std::string name = strip( nameElement->GetText(), "Vk" ); + + // skip "Flags", + if ( name != "Flags" ) + { + dependencies.push_back( DependencyData( DependencyData::Category::SCALAR, name ) ); + dependencies.back().dependencies.insert( type ); + } + else + { + assert( type == "uint32_t" ); + } +} + +void readTypeBitmask( TiXmlElement * element, std::list & dependencies, std::set & flags, std::set & vkTypes ) +{ + TiXmlElement * typeElement = element->FirstChildElement(); + assert( typeElement && ( strcmp( typeElement->Value(), "type" ) == 0 ) && typeElement->GetText() && ( strcmp( typeElement->GetText(), "VkFlags" ) == 0 ) ); + std::string type = typeElement->GetText(); + + TiXmlElement * nameElement = typeElement->NextSiblingElement(); + assert( nameElement && ( strcmp( nameElement->Value(), "name" ) == 0 ) && nameElement->GetText() ); + std::string name = strip( nameElement->GetText(), "Vk" ); + + assert( !nameElement->NextSiblingElement() ); + + if ( element->Attribute( "requires" ) ) + { + std::string requires = strip( element->Attribute( "requires" ), "Vk" ); + dependencies.push_back( DependencyData( DependencyData::Category::FLAGS, name ) ); + dependencies.back().dependencies.insert( requires ); + flags.insert( name ); + + assert( vkTypes.find( name ) == vkTypes.end() ); + vkTypes.insert( name ); + } + else + { + dependencies.push_back( DependencyData( DependencyData::Category::SCALAR, name ) ); + dependencies.back().dependencies.insert( type ); + } +} + +void readTypeDefine( TiXmlElement * element, std::string & version ) +{ + TiXmlElement * child = element->FirstChildElement(); + if ( child && ( strcmp( child->GetText(), "VK_API_VERSION" ) == 0 ) ) + { + version = element->LastChild()->ToText()->Value(); + } +} + +void readTypeFuncpointer( TiXmlElement * element, std::list & dependencies ) +{ + TiXmlElement * child = element->FirstChildElement(); + assert( child && ( strcmp( child->Value(), "name" ) == 0 ) && child->GetText() ); + dependencies.push_back( DependencyData( DependencyData::Category::FUNC_POINTER, child->GetText() ) ); +} + +void readTypeHandle( TiXmlElement * element, std::list & dependencies ) +{ + TiXmlElement * typeElement = element->FirstChildElement(); + assert( typeElement && ( strcmp( typeElement->Value(), "type" ) == 0 ) && typeElement->GetText() ); +#if !defined(NDEBUG) + std::string type = typeElement->GetText(); + assert( type.find( "VK_DEFINE" ) == 0 ); +#endif + + TiXmlElement * nameElement = typeElement->NextSiblingElement(); + assert( nameElement && ( strcmp( nameElement->Value(), "name" ) == 0 ) && nameElement->GetText() ); + std::string name = strip( nameElement->GetText(), "Vk" ); + + dependencies.push_back( DependencyData( DependencyData::Category::HANDLE, name ) ); +} + +void readTypeStructMember( TiXmlElement * element, std::vector & members, std::set & dependencies ) +{ + members.push_back( MemberData() ); + MemberData & member = members.back(); + + TiXmlNode * child = element->FirstChild(); + assert( child ); + if ( child->Type() == TiXmlNode::TINYXML_TEXT ) + { + assert( ( strcmp( child->Value(), "const" ) == 0 ) || ( strcmp( child->Value(), "struct" ) == 0 ) ); + member.type = std::string( child->Value() ) + " "; + child = child->NextSibling(); + assert( child ); + } + + assert( child->Type() == TiXmlNode::TINYXML_ELEMENT ); + assert( ( strcmp( child->Value(), "type" ) == 0 ) && child->ToElement() && child->ToElement()->GetText() ); + std::string type = strip( child->ToElement()->GetText(), "Vk" ); + dependencies.insert( type ); + member.type += type; + member.pureType = type; + + child = child->NextSibling(); + assert( child ); + if ( child->Type() == TiXmlNode::TINYXML_TEXT ) + { + std::string value = child->Value(); + assert( ( value == "*" ) || ( value == "**" ) || ( value == "* const*" ) ); + member.type += value; + child = child->NextSibling(); + } + + assert( ( child->Type() == TiXmlNode::TINYXML_ELEMENT ) && ( strcmp( child->Value(), "name" ) == 0 ) && child->ToElement() ); + member.name = child->ToElement()->GetText(); + + if ( member.name.back() == ']' ) + { + assert( !child->NextSibling() ); + size_t pos = member.name.find( '[' ); + assert( pos != std::string::npos ); + member.arraySize = member.name.substr( pos + 1, member.name.length() - 2 - pos ); + member.name.erase( pos ); + } + + child = child->NextSibling(); + if ( child ) + { + assert( member.arraySize.empty() ); + if ( child->Type() == TiXmlNode::TINYXML_TEXT ) + { + std::string value = child->Value(); + if ( value == "[" ) + { + child = child->NextSibling(); + assert( child ); + assert( ( child->Type() == TiXmlNode::TINYXML_ELEMENT ) && ( strcmp( child->Value(), "enum" ) == 0 ) ); + member.arraySize = child->ToElement()->GetText(); + child = child->NextSibling(); + assert( child ); + assert( child->Type() == TiXmlNode::TINYXML_TEXT ); + assert( strcmp( child->Value(), "]" ) == 0 ); + assert( !child->NextSibling() ); + } + else + { + assert( ( value.front() == '[' ) && ( value.back() == ']' ) ); + member.arraySize = value.substr( 1, value.length() - 2 ); + assert( !child->NextSibling() ); + } + } + } +} + +void readTypeStruct( TiXmlElement * element, std::list & dependencies, std::map & structs, std::set & vkTypes ) +{ + assert( !element->Attribute( "returnedonly" ) || ( strcmp( element->Attribute( "returnedonly" ), "true" ) == 0 ) ); + + assert( element->Attribute( "name" ) ); + std::string name = strip( element->Attribute( "name" ), "Vk" ); + + if ( name == "Rect3D" ) + { + return; + } + + dependencies.push_back( DependencyData( DependencyData::Category::STRUCT, name ) ); + + assert( structs.find( name ) == structs.end() ); + std::map::iterator it = structs.insert( std::make_pair( name, StructData() ) ).first; + it->second.returnedOnly = !!element->Attribute( "returnedonly" ); + + TiXmlElement * child = element->FirstChildElement(); + do + { + assert( child->Value() ); + std::string value = child->Value(); + if ( value == "member" ) + { + readTypeStructMember( child, it->second.members, dependencies.back().dependencies ); + } + else + { + assert( value == "validity" ); + } + } while ( child = child->NextSiblingElement() ); + + assert( vkTypes.find( name ) == vkTypes.end() ); + vkTypes.insert( name ); +} + +void readTypeUnionMember( TiXmlElement * element, std::vector & members, std::set & dependencies ) +{ + members.push_back( MemberData() ); + MemberData & member = members.back(); + + TiXmlNode * child = element->FirstChild(); + assert( child ); + if ( child->Type() == TiXmlNode::TINYXML_TEXT ) + { + assert( ( strcmp( child->Value(), "const" ) == 0 ) || ( strcmp( child->Value(), "struct" ) == 0 ) ); + member.type = std::string( child->Value() ) + " "; + child = child->NextSibling(); + assert( child ); + } + + assert( child->Type() == TiXmlNode::TINYXML_ELEMENT ); + assert( ( strcmp( child->Value(), "type" ) == 0 ) && child->ToElement() && child->ToElement()->GetText() ); + std::string type = strip( child->ToElement()->GetText(), "Vk" ); + dependencies.insert( type ); + member.type += type; + member.pureType = type; + + child = child->NextSibling(); + assert( child ); + if ( child->Type() == TiXmlNode::TINYXML_TEXT ) + { + std::string value = child->Value(); + assert( ( value == "*" ) || ( value == "**" ) || ( value == "* const*" ) ); + member.type += value; + child = child->NextSibling(); + } + + assert( ( child->Type() == TiXmlNode::TINYXML_ELEMENT ) && ( strcmp( child->Value(), "name" ) == 0 ) && child->ToElement() ); + member.name = child->ToElement()->GetText(); + + if ( member.name.back() == ']' ) + { + assert( !child->NextSibling() ); + size_t pos = member.name.find( '[' ); + assert( pos != std::string::npos ); + member.arraySize = member.name.substr( pos + 1, member.name.length() - 2 - pos ); + member.name.erase( pos ); + } + + child = child->NextSibling(); + if ( child ) + { + if ( child->Type() == TiXmlNode::TINYXML_TEXT ) + { + std::string value = child->Value(); + if ( value == "[" ) + { + child = child->NextSibling(); + assert( child ); + assert( ( child->Type() == TiXmlNode::TINYXML_ELEMENT ) && ( strcmp( child->Value(), "enum" ) == 0 ) ); + member.arraySize = child->ToElement()->GetText(); + child = child->NextSibling(); + assert( child ); + assert( child->Type() == TiXmlNode::TINYXML_TEXT ); + assert( strcmp( child->Value(), "]" ) == 0 ); + assert( !child->NextSibling() ); + } + else + { + assert( ( value.front() == '[' ) && ( value.back() == ']' ) ); + member.arraySize = value.substr( 1, value.length() - 2 ); + assert( !child->NextSibling() ); + } + } + } +} + +void readTypeUnion( TiXmlElement * element, std::list & dependencies, std::map & structs, std::set & vkTypes ) +{ + assert( element->Attribute( "name" ) ); + std::string name = strip( element->Attribute( "name" ), "Vk" ); + + dependencies.push_back( DependencyData( DependencyData::Category::UNION, name ) ); + + assert( structs.find( name ) == structs.end() ); + std::map::iterator it = structs.insert( std::make_pair( name, StructData() ) ).first; + + TiXmlElement * child = element->FirstChildElement(); + do + { + assert( strcmp( child->Value(), "member" ) == 0 ); + readTypeUnionMember( child, it->second.members, dependencies.back().dependencies ); + } while ( child = child->NextSiblingElement() ); + + assert( vkTypes.find( name ) == vkTypes.end() ); + vkTypes.insert( name ); +} + +void readTypes( TiXmlElement * element, std::string & version, std::list & dependencies, std::set & flags, std::map & structs, std::set & vkTypes ) +{ + TiXmlElement * child = element->FirstChildElement(); + do + { + assert( strcmp( child->Value(), "type" ) == 0 ); + std::string type = child->Value(); + assert( type == "type" ); + if ( child->Attribute( "category" ) ) + { + std::string category = child->Attribute( "category" ); + if ( category == "basetype" ) + { + readTypeBasetype( child, dependencies ); + } + else if ( category == "bitmask" ) + { + readTypeBitmask( child, dependencies, flags, vkTypes ); + } + else if ( category == "define" ) + { + readTypeDefine( child, version ); + } + else if ( category == "funcpointer" ) + { + readTypeFuncpointer( child, dependencies ); + } + else if ( category == "handle" ) + { + readTypeHandle( child, dependencies ); + } + else if ( category == "struct" ) + { + readTypeStruct( child, dependencies, structs, vkTypes ); + } + else if ( category == "union" ) + { + readTypeUnion( child, dependencies, structs, vkTypes ); + } + else + { + assert( ( category == "enum" ) || ( category == "include" ) ); + } + } + else + { + assert( child->Attribute( "requires" ) && child->Attribute( "name" ) ); + dependencies.push_back( DependencyData( DependencyData::Category::REQUIRED, child->Attribute( "name" ) ) ); + } + } while ( child = child->NextSiblingElement() ); +} + +void sortDependencies( std::list & dependencies, std::vector const& extensions, std::vector> & sortedDependencies ) +{ + std::set listedTypes = { "VkFlags" }; + + std::map extensionMap; + for ( size_t i=0 ; i::iterator it = dependencies.begin() ; it != dependencies.end() ; ++it ) + { + if ( noDependencies( it->dependencies, listedTypes ) ) + { + std::map::iterator extMapIt = extensionMap.find( it->name ); + size_t idx = ( extMapIt != extensionMap.end() ) ? extMapIt->second : 0; + sortedDependencies[idx].push_back( *it ); + listedTypes.insert( it->name ); + dependencies.erase( it ); +#if !defined(NDEBUG) + ok = true; +#endif + break; + } + } + assert( ok ); + } +} + +std::string reduceName(std::string const& name) +{ + assert((1 < name.length()) && (name[0] == 'p') && (isupper(name[1]))); + std::string reducedName = strip(name, "p"); + reducedName[0] = tolower(reducedName[0]); + return reducedName; +} + +std::string strip( std::string const& value, std::string const& prefix ) +{ + if ( value.find( prefix ) == 0 ) + { + return value.substr( prefix.length() ); + } + return value; +} + +std::string toCamelCase(std::string const& value) +{ + assert(!value.empty() && (isupper(value[0]) || isdigit(value[0]))); + std::string result; + result.reserve(value.size()); + result.push_back(value[0]); + for (size_t i = 1; i < value.size(); i++) + { + if (value[i] != '_') + { + if ((value[i - 1] == '_') || isdigit(value[i-1])) + { + result.push_back(value[i]); + } + else + { + result.push_back(tolower(value[i])); + } + } + } + return result; +} + +std::string toUpperCase(std::string const& name) +{ + assert(isupper(name.front())); + std::string convertedName; + + for (size_t i = 0; i const& vkTypes) +{ + if ( vkTypes.find( memberData.pureType ) != vkTypes.end() ) + { + if ( memberData.type.back() == '*' ) + { + ofs << "reinterpret_cast<"; + if ( memberData.type.find( "const" ) == 0 ) + { + ofs << "const "; + } + ofs << "Vk" << memberData.pureType << "*"; + } + else + { + ofs << "static_cast( " << memberData.name << " )"; + } + else + { + ofs << memberData.name; + } +} + +void writeStructConstructor( std::ofstream & ofs, std::string const& name, std::string const& memberName, StructData const& structData, std::set const& vkTypes, std::map const& defaultValues ) +{ + // check if there is a member element with no default available + bool noDefault = false; + for (size_t i = 0; i < structData.members.size() && !noDefault; i++) + { + std::map::const_iterator it = defaultValues.find(structData.members[i].pureType); + assert(it != defaultValues.end()); + noDefault = it->second.empty(); + } + + if (!noDefault) + { + // if there's a default for all memeber, provide a default constructor + ofs << " " << name << "()" << std::endl + << " : " << name << "( "; + bool listedArgument = false; + for (size_t i = 0; i < structData.members.size(); i++) + { + if (listedArgument) + { + ofs << ", "; + } + if ((structData.members[i].name != "pNext") && (structData.members[i].name != "sType")) + { + if (structData.members[i].type.back() == '*') + { + ofs << "nullptr"; + } + else + { + std::map::const_iterator it = defaultValues.find(structData.members[i].pureType); + assert((it != defaultValues.end()) && !it->second.empty()); + + if (structData.members[i].arraySize.empty()) + { + ofs << it->second; + } + else + { + ofs << "{ " << it->second << " }"; + } + } + listedArgument = true; + } + } + ofs << " )" << std::endl + << " {}" << std::endl + << std::endl; + } + + // the constructor with all the elements as arguments + ofs << " " << name << "( "; + std::vector noDefaultArgs, defaultArgs; + bool listedArgument = false; + for (size_t i = 0; i const& " + structData.members[i].name; + } + listedArgument = true; + } + } + ofs << ")" << std::endl; + + // now the body of the constructor, copying over data from argument list into wrapped struct + ofs << " {" << std::endl; + for ( size_t i=0 ; i here for the correct name. In this case the 'generic' rule to create the enums doesn't work + if (name == "DebugReportCallbackCreateInfoEXT") + { + ofs << "VK_STRUCTURE_TYPE_DEBUG_REPORT_CREATE_INFO_EXT"; + } + else + { + ofs << "VK_STRUCTURE_TYPE" << toUpperCase(name); + } + } + else + { + writeMemberData( ofs, structData.members[i], vkTypes ); + } + } + ofs << ";" << std::endl; + } + ofs << " }" << std::endl + << std::endl; +} + +void writeStructGetter( std::ofstream & ofs, MemberData const& memberData, std::string const& memberName, std::set const& vkTypes ) +{ + ofs << " "; + if ( memberData.type.back() == '*' ) + { + if ( memberData.type.find( "const" ) != 0 ) + { + ofs << "const "; + } + ofs << memberData.type; + } + else + { + ofs << "const " << memberData.type << ( memberData.arraySize.empty() ? "&" : "*" ); + } + + ofs << " " << memberData.name << "() const" << std::endl + << " {" << std::endl + << " return "; + if ( ! memberData.arraySize.empty() ) + { + ofs << "reinterpret_cast( " << memberName << "." << memberData.name << " )"; + } + else if ( memberData.type.back() == '*' ) + { + ofs << "reinterpret_cast<" << memberData.type << ">( " << memberName << "." << memberData.name << " )"; + } + else if ( vkTypes.find( memberData.pureType ) != vkTypes.end() ) + { + ofs << "reinterpret_cast( " << memberName << "." << memberData.name << " )"; + } + else + { + ofs << memberName << "." << memberData.name; + } + ofs << ";" << std::endl + << " }" << std::endl + << std::endl; +} + +void writeStructSetter( std::ofstream & ofs, std::string const& name, MemberData const& memberData, std::string const& memberName, std::set const& vkTypes ) +{ + ofs << " " << name << "& " << memberData.name << "( "; + if ( memberData.arraySize.empty() ) + { + ofs << memberData.type << " "; + } + else + { + ofs << "std::array<" << memberData.type << "," << memberData.arraySize << "> "; + } + ofs << memberData.name << " )" << std::endl + << " {" << std::endl; + if ( !memberData.arraySize.empty() ) + { + ofs << " memcpy( &" << memberName << "." << memberData.name << ", " << memberData.name << ".data(), " << memberData.arraySize << " * sizeof( " << memberData.type << " ) )"; + } + else + { + ofs << " " << memberName << "." << memberData.name << " = "; + writeMemberData( ofs, memberData, vkTypes ); + } + ofs << ";" << std::endl + << " return *this;" << std::endl + << " }" << std::endl + << std::endl; +} + +void writeTypeCommand( std::ofstream & ofs, DependencyData const& dependencyData, CommandData const& commandData, std::set const& vkTypes ) +{ + writeTypeCommandStandard(ofs, dependencyData, commandData, vkTypes); + writeTypeCommandEnhanced(ofs, dependencyData, commandData, vkTypes); +} + +bool hasPointerArguments(CommandData const& commandData) +{ + for (size_t i = 0; i < commandData.arguments.size(); i++) + { + size_t pos = commandData.arguments[i].type.find('*'); + if ((pos != std::string::npos) && (commandData.arguments[i].type.find('*', pos + 1) == std::string::npos)) + { + return true; + } + } + return false; +} + +void writeTypeCommandEnhanced(std::ofstream & ofs, DependencyData const& dependencyData, CommandData const& commandData, std::set const& vkTypes) +{ + if (hasPointerArguments( commandData )) + { + std::vector> lenParameters = getLenParameters(commandData); + ofs << "#ifdef VKCPP_ENHANCED_MODE" << std::endl + << " inline "; + size_t returnIndex = (commandData.returnType == "void") ? findReturnIndex(commandData, lenParameters) : ~0; + if (returnIndex == ~0) + { + ofs << commandData.returnType; + } + else + { + ofs << "std::vector<" << commandData.arguments[lenParameters[returnIndex].first].pureType << ">"; + ofs << std::flush; + } + ofs << " " << dependencyData.name << "( "; + + std::set argIndices; + std::map> sizeIndices; + for (size_t i = 0; i < lenParameters.size(); i++) + { + argIndices.insert(lenParameters[i].first); + if (lenParameters[i].second != ~0) + { + sizeIndices[lenParameters[i].second].push_back( lenParameters[i].first ); + } + } + + bool argEncounterd = false; + std::map nameMap; + for (size_t i = 0; i < commandData.arguments.size(); i++) + { + nameMap[commandData.arguments[i].name] = commandData.arguments[i].name; + + if ((sizeIndices.find(i) != sizeIndices.end()) || ((returnIndex != ~0) && (i == lenParameters[returnIndex].first))) + { + // skip size arguments and the returning arguments + } + else + { + if (argEncounterd) + { + ofs << ", "; + } + if (argIndices.find(i) != argIndices.end()) + { + // take a vector or a string here + if (commandData.arguments[i].len == "null-terminated") + { + assert(commandData.arguments[i].pureType == "char"); + ofs << "std::string const& "; + } + else + { + std::string dataType = (commandData.arguments[i].pureType == "void") ? "uint8_t" : commandData.arguments[i].pureType; + ofs << "std::vector<" << dataType << "> "; + if (commandData.arguments[i].type.find("const") == 0) + { + ofs << "const"; + } + ofs << "&"; + } + nameMap[commandData.arguments[i].name] = reduceName(commandData.arguments[i].name); + } + else + { + assert(commandData.arguments[i].arraySize.empty()); + std::string type = commandData.arguments[i].type; + size_t pos = type.find('*'); + if ((pos != std::string::npos) && (type.find('*', pos + 1) == std::string::npos) && (commandData.arguments[i].name[0] == 'p') && (isupper(commandData.arguments[i].name[1]))) + { + type[pos] = '&'; + assert(type.find('*') == std::string::npos); + nameMap[commandData.arguments[i].name] = reduceName(commandData.arguments[i].name); + } + ofs << type; + } + ofs << " " << nameMap[commandData.arguments[i].name]; + argEncounterd = true; + } + } + ofs << " )" << std::endl + << " {" << std::endl; + + size_t complexIndex = findComplexIndex(commandData, lenParameters); + if (complexIndex == ~0) + { + writeTypeCommandSimpleBody(ofs, dependencyData, commandData, nameMap, argIndices, sizeIndices); + } + else + { + writeTypeCommandComplexBody(ofs, dependencyData, commandData, nameMap, lenParameters, argIndices, complexIndex, returnIndex); + } + + ofs << " }" << std::endl + << "#endif // VKCPP_ENHANCED_MODE" << std::endl + << std::endl; + } +} + +void writeTypeCommandStandard(std::ofstream & ofs, DependencyData const& dependencyData, CommandData const& commandData, std::set const& vkTypes) +{ + ofs << " inline " << commandData.returnType << " " << dependencyData.name << "( "; + for (size_t i = 0; i( "; + } + } + + std::string callName(dependencyData.name); + assert(islower(callName[0])); + callName[0] = toupper(callName[0]); + + ofs << "vk" << callName << "( "; + for (size_t i = 0; i const& nameMap, std::vector> const& lenParameters, std::set const& argIndices, size_t complexIndex, size_t returnIndex) +{ + assert(lenParameters[complexIndex].second != ~0); + ofs << " " << commandData.arguments[lenParameters[complexIndex].second].pureType << " " << nameMap.find(commandData.arguments[lenParameters[complexIndex].second].name)->second << " = 0;" << std::endl; + ofs << " "; + assert((commandData.returnType == "void") || (commandData.returnType == "Result")); + if (commandData.returnType == "Result") + { + ofs << commandData.returnType << " result = "; + } + ofs << dependencyData.name << "( "; + for (size_t i = 0; isecond; + } + else if (argIndices.find(i) != argIndices.end()) + { + ofs << argit->second << ".data()"; + } + else + { + ofs << argit->second; + } + } + ofs << " );" << std::endl; + if (commandData.returnType == "Result") + { + ofs << " if ( result == Result::eVkSuccess )" << std::endl + << " {" << std::endl + << " "; + } + ofs << " "; + if (returnIndex == ~0) + { + ofs << nameMap.find(commandData.arguments[lenParameters[complexIndex].first].name)->second << ".resize( " << nameMap.find(commandData.arguments[lenParameters[complexIndex].second].name)->second << " );" << std::endl; + } + else + { + ofs << "std::vector<" << commandData.arguments[lenParameters[returnIndex].first].pureType << "> " << nameMap.find(commandData.arguments[lenParameters[returnIndex].first].name)->second << "( " << nameMap.find(commandData.arguments[lenParameters[returnIndex].second].name)->second << " );" << std::endl; + } + ofs << " "; + if (commandData.returnType == "Result") + { + ofs << " result = "; + } + ofs << dependencyData.name << "( "; + for (size_t i = 0; isecond << ".data()"; + } + else if (i == lenParameters[complexIndex].second) + { + ofs << "&" << argit->second; + } + else if (argIndices.find(i) != argIndices.end()) + { + ofs << argit->second << ".data()"; + } + else + { + ofs << argit->second; + } + } + ofs << " );" << std::endl; + if (commandData.returnType == "Result") + { + assert(returnIndex == ~0); + ofs << " }" << std::endl + << " return result;" << std::endl; + } + else if (returnIndex != ~0) + { + ofs << " return std::move( " << nameMap.find(commandData.arguments[lenParameters[returnIndex].first].name)->second << " );" << std::endl; + } +} + +void writeTypeCommandSimpleBody(std::ofstream & ofs, DependencyData const& dependencyData, CommandData const& commandData, std::map const& nameMap, std::set const& argIndices, std::map> const& sizeIndices) +{ + for (std::map>::const_iterator it = sizeIndices.begin(); it != sizeIndices.end(); ++it) + { + if (1 < it->second.size()) + { + assert(it->second.size() == 2); + ofs << " assert( " << nameMap.find(commandData.arguments[it->second[0]].name)->second << ".size() <= " << nameMap.find(commandData.arguments[it->second[1]].name)->second << ".size() );" << std::endl; + } + } + ofs << " "; + if (commandData.returnType != "void") + { + ofs << "return "; + } + ofs << dependencyData.name << "( "; + for (size_t i = 0; i < commandData.arguments.size(); i++) + { + auto argit = nameMap.find(commandData.arguments[i].name); + if (0 < i) + { + ofs << ", "; + } + if (argIndices.find(i) != argIndices.end()) + { + ofs << argit->second << ".data()"; + } + else + { + std::map>::const_iterator it = sizeIndices.find(i); + if (it != sizeIndices.end()) + { + ofs << "static_cast<" << commandData.arguments[i].type << ">( " << nameMap.find(commandData.arguments[it->second.front()].name)->second << ".size() )"; + } + else if (nameMap.find(commandData.arguments[i].name)->second != commandData.arguments[i].name) + { + ofs << "&" << argit->second; + } + else + { + ofs << argit->second; + } + } + } + ofs << " );" << std::endl; +} + +void writeTypeEnum( std::ofstream & ofs, DependencyData const& dependencyData, EnumData const& enumData ) +{ + ofs << " enum class " << dependencyData.name << std::endl + << " {" << std::endl; + for ( size_t i=0 ; i " << dependencyData.name << ";" << std::endl + << std::endl + << " inline " << dependencyData.name << " operator|( " << *dependencyData.dependencies.begin() << " bit0, " << *dependencyData.dependencies.begin() << " bit1 )" << std::endl + << " {" << std::endl + << " return " << dependencyData.name << "( bit0 ) | bit1;" << std::endl + << " }" << std::endl + << std::endl; +} + +void writeTypeHandle( std::ofstream & ofs, DependencyData const& dependencyData ) +{ + assert( dependencyData.dependencies.empty() ); + ofs << " typedef Vk" << dependencyData.name << " " << dependencyData.name << ";" << std::endl; +} + +void writeTypeScalar( std::ofstream & ofs, DependencyData const& dependencyData ) +{ + assert( dependencyData.dependencies.size() == 1 ); + ofs << " typedef " << *dependencyData.dependencies.begin() << " " << dependencyData.name << ";" << std::endl; +} + +void writeTypeStruct( std::ofstream & ofs, DependencyData const& dependencyData, std::set const& vkTypes, std::map const& structs, std::map const& defaultValues ) +{ + std::map::const_iterator it = structs.find( dependencyData.name ); + assert( it != structs.end() ); + + ofs << " class " << dependencyData.name << std::endl + << " {" << std::endl + << " public:" << std::endl; + + std::string memberName( dependencyData.name ); + assert( isupper( memberName[0] ) ); + memberName[0] = tolower( memberName[0] ); + memberName = "m_" + memberName; + + // only structs that are not returnedOnly get a constructor! + if ( !it->second.returnedOnly ) + { + writeStructConstructor( ofs, dependencyData.name, memberName, it->second, vkTypes, defaultValues ); + } + + // create the getters and setters + for ( size_t i=0 ; isecond.members.size() ; i++ ) + { + writeStructGetter( ofs, it->second.members[i], memberName, vkTypes ); + if ( !it->second.returnedOnly ) + { + writeStructSetter( ofs, dependencyData.name, it->second.members[i], memberName, vkTypes ); + } + } + + // the cast-operator to the wrapped struct, and the struct itself as a private member variable + ofs << " operator const Vk" << dependencyData.name << "&() const" << std::endl + << " {" << std::endl + << " return " << memberName << ";" << std::endl + << " }" << std::endl + << std::endl + << " private:" << std::endl + << " Vk" << dependencyData.name << " " << memberName << ";" << std::endl + << " };" << std::endl +#if 0 + << " static_assert( sizeof( " << dependencyData.name << " ) == sizeof( Vk" << dependencyData.name << " ), \"struct and wrapper have different size!\" );" << std::endl +#endif + << std::endl; +} + +void writeTypeUnion( std::ofstream & ofs, DependencyData const& dependencyData, StructData const& unionData, std::set const& vkTypes, std::map const& structs, std::map const& defaultValues ) +{ + std::ostringstream oss; + ofs << " class " << dependencyData.name << std::endl + << " {" << std::endl + << " public:" << std::endl; + + std::string memberName( dependencyData.name ); + assert( isupper( memberName[0] ) ); + memberName[0] = tolower( memberName[0] ); + memberName = "m_" + memberName; + + for ( size_t i=0 ; i& "; + } + ofs << unionData.members[i].name; + + // just the very first constructor gets default arguments + if ( i == 0 ) + { + std::map::const_iterator it = defaultValues.find( unionData.members[i].pureType ); + assert( it != defaultValues.end() ); + if ( unionData.members[i].arraySize.empty() ) + { + ofs << " = " << it->second; + } + else + { + ofs << " = { " << it->second << " }"; + } + } + ofs << " )" << std::endl + << " {" << std::endl + << " "; + if ( unionData.members[i].arraySize.empty() ) + { + ofs << memberName << "." << unionData.members[i].name << " = " << unionData.members[i].name; + } + else + { + ofs << "memcpy( &" << memberName << "." << unionData.members[i].name << ", " << unionData.members[i].name << ".data(), " << unionData.members[i].arraySize << " * sizeof( " << unionData.members[i].type << " ) )"; + } + ofs << ";" << std::endl + << " }" << std::endl + << std::endl; + + // one getter/setter per union element + writeStructGetter( ofs, unionData.members[i], memberName, vkTypes ); + writeStructSetter( ofs, dependencyData.name, unionData.members[i], memberName, vkTypes ); + } + ofs << " operator Vk" << dependencyData.name << " const& () const" << std::endl + << " {" << std::endl + << " return " << memberName << ";" << std::endl + << " }" << std::endl + << std::endl + << " private:" << std::endl + << " Vk" << dependencyData.name << " " << memberName << ";" << std::endl + << " };" << std::endl + << std::endl; +} + +void writeTypes( std::ofstream & ofs, std::vector const& dependencies, std::map const& commands, std::map const& enums, std::map const& structs, std::map const& defaultValues, std::set const& vkTypes ) +{ + for ( std::vector::const_iterator it = dependencies.begin() ; it != dependencies.end() ; ++it ) + { + switch( it->category ) + { + case DependencyData::Category::COMMAND : + assert( commands.find( it->name ) != commands.end() ); + writeTypeCommand( ofs, *it, commands.find( it->name )->second, vkTypes ); + break; + case DependencyData::Category::ENUM : + assert( enums.find( it->name ) != enums.end() ); + writeTypeEnum( ofs, *it, enums.find( it->name )->second ); + break; + case DependencyData::Category::FLAGS : + writeTypeFlags( ofs, *it ); + break; + case DependencyData::Category::FUNC_POINTER : + case DependencyData::Category::REQUIRED : + // skip FUNC_POINTER and REQUIRED, they just needed to be in the dependencies list to resolve dependencies + break; + case DependencyData::Category::HANDLE : + writeTypeHandle( ofs, *it ); + break; + case DependencyData::Category::SCALAR : + writeTypeScalar( ofs, *it ); + break; + case DependencyData::Category::STRUCT : + writeTypeStruct( ofs, *it, vkTypes, structs, defaultValues ); + break; + case DependencyData::Category::UNION : + assert( structs.find( it->name ) != structs.end() ); + writeTypeUnion( ofs, *it, structs.find( it->name )->second, vkTypes, structs, defaultValues ); + break; + default : + assert( false ); + break; + } + } +} + +void writeVersionCheck( std::ofstream & ofs, std::string const& version ) +{ + ofs << "static_assert( VK_MAKE_VERSION" << version << " == VK_API_VERSION, \"Wrong VK_API_VERSION!\" );" << std::endl + << std::endl; +} + +int main( int argc, char **argv ) +{ + TiXmlDocument doc; + + if ( !doc.LoadFile( argv[1] ) ) + { + std::cout << "VkGenerate: failed to load file " << argv[1] << std::endl; + return -1; + } + + TiXmlElement * registryElement = doc.FirstChildElement(); + assert( strcmp( registryElement->Value(), "registry" ) == 0 ); + assert( !registryElement->NextSiblingElement() ); + + std::string version; + std::list dependencies; + std::map enums; + std::vector extensions; + std::set flags; + std::map structs; + std::map commands; + std::set vkTypes; + + TiXmlElement * child = registryElement->FirstChildElement(); + do + { + assert( child->Value() ); + const std::string value = child->Value(); + if ( value == "commands" ) + { + readCommands( child, dependencies, commands ); + } + else if ( value == "enums" ) + { + readEnums( child, dependencies, enums, vkTypes ); + } + else if ( value == "extensions" ) + { + readExtensions( child, extensions ); + } + else if ( value == "types" ) + { + readTypes( child, version, dependencies, flags, structs, vkTypes ); + } + else + { + assert( ( value == "comment" ) || ( value == "feature" ) || ( value == "tags" ) || ( value == "vendorids" ) ); + } + } while ( child = child->NextSiblingElement() ); + + std::vector> sortedDependencies; + sortDependencies( dependencies, extensions, sortedDependencies ); + + std::map defaultValues; + for ( size_t i=0 ; i" << std::endl + << "#include " << std::endl + << "#include " << std::endl + << "#include " << std::endl + << "#ifdef VKCPP_ENHANCED_MODE" << std::endl + << "# include " << std::endl + << "#endif // VKCPP_ENHANCED_MODE" << std::endl + << std::endl; + writeVersionCheck( ofs, version ); + ofs << "namespace vk" << std::endl + << "{" << std::endl; + + ofs << flagsHeader; + + for ( size_t i=0 ; i