Das Ziel des Vulkan-HPP ist es, nur C ++-Bindungen für die Vulkan-C-API zu liefern, um die Entwickler von Vulkan-Erfahrung zu verbessern, ohne die CPU-Laufzeitkosten einzuführen. Es fügt Funktionen wie Type Safety für Enums und Bitfields, STL -Containerunterstützung, Ausnahmen und einfache Aufzählungen hinzu.
| Plattform | Status erstellen |
|---|---|
| Linux |
Vulkan-HPP ist seit Version 1.0.24 Teil des Lunarg Vulkan SDK. Nur #include <vulkan/vulkan.hpp> und Sie können die C ++ - Bindungen verwenden. Wenn Sie eine Vulkan -Version verwenden, die noch nicht vom Vulkan SDK unterstützt wird, finden Sie hier die neueste Version der Header.
Vulkan-HPP benötigt einen C ++ 11-fähigen Compiler zum Kompilieren. Es ist bekannt, dass die folgenden Compiler funktionieren:
Um die lokalen Proben und Tests zu erstellen, müssen Sie dieses Repository klonen und CMake ausführen, um die erforderlichen Build -Dateien zu generieren
Abhängigkeiten installieren.
Öffnen Sie eine Schale, die Git liefert und das Repository mit: Klon mit:
git clone --recurse-submodules https://github.com/KhronosGroup/Vulkan-Hpp.git
Ändern Sie das aktuelle Verzeichnis in das neu erstellte Vulkan-HPP-Verzeichnis.
Erstellen Sie eine Build -Umgebung mit CMake:
cmake -DVULKAN_HPP_SAMPLES_BUILD=ON -DVULKAN_HPP_SAMPLES_BUILD_WITH_LOCAL_VULKAN_HPP=ON -DVULKAN_HPP_TESTS_BUILD=ON -DVULKAN_HPP_TESTS_BUILD_WITH_LOCAL_VULKAN_HPP=ON -B build
Möglicherweise müssen Sie einen Generator über -G angeben, um eine vollständige Liste von Generatoren auszuführen cmake -G ausführen.
vulkan.hpp aus der Registrierungsdatei vk.xml XML wieder aufzubauen, fügen Sie die Option -DVULKAN_HPP_RUN_GENERATOR=ON Option CMAKE -Befehlszeile hinzu. Öffnen Sie entweder das generierte Projekt mit einer IDE, z. B. Visual Studio, oder starten Sie den Build -Prozess mit cmake --build build --parallel .
Optional: Um das Vulkan-HPP und seine Submodules zu aktualisieren, führen git pull --recurse-submodules aus.
Sie können Vulkan-HPP mit dem VCPKG-Abhängigkeitsmanager herunterladen und installieren:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install vulkan-headersDer Vulkan-HPP-Port in VCPKG wird von Microsoft-Teammitgliedern und Community-Mitwirkenden auf dem Laufenden gehalten. Wenn die Version veraltet ist, erstellen Sie bitte eine Ausgabe- oder Pull -Anfrage im VCPKG -Repository.
Wenn das Programm clang-format von cmake gefunden wird, wird das definierte CLANG_FORMAT_EXECUTABLE entsprechend festgelegt. In diesem Fall wird der generierte vulkan.hpp unter Verwendung der .clang-format Datei im Stammverzeichnis dieses Projekts formatiert. Ansonsten ist es im Generator als hart codiert.
Die Datei VulkanHpp.natvis bietet eine benutzerdefinierte Ansicht zu vk::Flags für Visual Studio. Wenn Sie diese Datei dem benutzerspezifischen NATVIS-Verzeichnis Ihrer Visual Studio-Installation (%userProfile% documents Visual Studio 2022 Visualisierer) hinzufügen, erhalten Sie vk::Flags in Ihrem Debugger mit allen Visual Studio-Projekten gut formatiert sind.
Um Namenskollisionen mit der Vulkan -C -API zu vermeiden, befinden sich die C ++ - Bindungen im vk -Namespace. Die folgenden Regeln gelten für die neue Benennung:
Vk -Präfix entfernt. Darüber hinaus ist der erste Funktionsbuchstaben niedrigerer Fall.vkCreateInstance kann als vk::createInstance zugegriffen werden.VkImageTiling kann als vk::ImageTiling zugänglich sein.VkImageCreateInfo kann als vk::ImageCreateInfo zugegriffen werden.VK_ -Präfix in 'E' + Camelcase geändert und ein Infix eingeben. Wenn der Enum -Typ eine Erweiterung ist, wurde das Erweiterungssuffix aus den Enum -Werten entfernt.In allen anderen Fällen wurde das Verlängerungssuffix nicht entfernt.
VK_IMAGETYPE_2D ist jetzt vk::ImageType::e2D .VK_COLOR_SPACE_SRGB_NONLINEAR_KHR ist jetzt vk::ColorSpaceKHR::eSrgbNonlinear .VK_STRUCTURE_TYPE_PRESENT_INFO_KHR ist jetzt vk::StructureType::ePresentInfoKHR ._BIT -Suffix ebenfalls entfernt wurde. In einigen Fällen kann es erforderlich sein, Vulkan-HPP in einen benutzerdefinierten Namespace zu verschieben. Dies kann erreicht werden, indem VULKAN_HPP_NAMESPACE vor der Einbeziehung von Vulkan-HPP definiert wird.
Vulkan-HPP erklärt eine Klasse für alle Griffe, um die Sicherheit des Typs zu gewährleisten und Unterstützung für Mitgliederfunktionen für Handles hinzuzufügen. Für jede Funktion wurde eine Mitgliedsfunktion zu einer Handlungsklasse hinzugefügt, die den entsprechenden Handle als erster Parameter akzeptiert. Anstelle von vkBindBufferMemory(device, ...) vk::bindBufferMemory(device, ...) man device.bindBufferMemory(...) schreiben.
Es gibt einen zusätzlichen Header namens vulkan_raii.hpp generiert. Dieser Header hält Raii-konforme Wrapper-Klassen für die Grifftypen. Das heißt, für den Grifftyp VkInstance gibt es eine raii-konforme Wrapper vk::raii::Instance . Bitte schauen Sie sich die Proben anhand dieser Klassen im Verzeichnis raiii_samples an.
Auf 64-Bit-Plattformen unterstützt Vulkan-HPP implizite Conversions zwischen C ++-Vulkan-Handles und C Vulkan-Handles. Auf 32-Bit-Plattformen sind alle nicht-dispatchierbaren Griffe als uint64_t definiert, wodurch Typenkonversionsprüfungen zum Kompilierungszeitpunkt verhindert werden, was Zuordnungen zwischen inkompatiblen Grifftypen erfassen würde. Aufgrund dieses Vulkan-HPP aktiviert die implizite Konvertierung für 32-Bit-Plattformen standardmäßig nicht und es wird empfohlen, einen static_cast für die Konvertierung wie diese zu verwenden: VkImage = static_cast<VkImage>(cppImage) um zu verhindern, dass die Konvertierung einiger willkürlicher INT in ein Griff oder Vize-Vers-Vers-Versa nach Unfall umgewandelt wird. Wenn Sie Ihren Code auf einer 64-Bit-Plattform entwickeln, aber Ihren Code für eine 32-Bit-Plattform kompilieren möchten, ohne die expliziten Abzüge hinzuzufügen, können Sie in Ihrem Build-System oder vor der Einbeziehung vulkan.hpp VULKAN_HPP_TYPESAFE_CONVERSION zu 1 definieren. Auf 64-Bit-Plattformen wird diese Definition standardmäßig auf 1 gesetzt und kann auf 0 gesetzt werden, um implizite Conversions zu deaktivieren.
Die Fecoped Enum -Funktion fügt den Flags die Typensicherheit hinzu, verhindert jedoch auch die Verwendung der Flag -Bits als Eingabe für bitweise Operationen wie & und | .
Als Lösung bietet Vulkan-HPP eine Klassenvorlage vk::Flags , die die Standardvorgänge wie &= , |= , & und | verleiht zu unseren Scoped Enum. Mit Ausnahme der Initialisierung mit 0 verhält sich diese Klasse genau wie eine normale Bitmaske mit der Verbesserung, dass es unmöglich ist, durch den entsprechenden Enum nicht angegebenen Bits festzulegen. Hier sind einige Beispiele für die Bitmaskenhandhabung:
vk::ImageUsageFlags iu1; // initialize a bitmask with no bit set
vk::ImageUsageFlags iu2 = {}; // initialize a bitmask with no bit set
vk::ImageUsageFlags iu3 = vk::ImageUsageFlagBits::eColorAttachment; // initialize with a single value
vk::ImageUsageFlags iu4 = vk::ImageUsageFlagBits::eColorAttachment | vk::ImageUsageFlagBits::eStorage; // or two bits to get a bitmask
PipelineShaderStageCreateInfo ci ({} /* pass a flag without any bits set */ , ...); Wenn Sie einen Griff in Vulkan erstellen, muss man normalerweise einige CreateInfo -Strukturen erstellen, die den neuen Griff beschreibt. Dies kann zu einem ziemlich langen Code führen, wie im folgenden Vulkan C -Beispiel zu sehen ist:
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); Es gibt zwei typische Probleme, die Vulkan -Entwickler begegnen, wenn ein Feld CreateInfo Struct" nach Feld ausgefüllt wird:
sType ist falsch.Besonders der erste ist schwer zu erkennen.
Vulkan-HPP bietet Konstruktoren für alle CreateInfo Objekte, die einen Parameter für jede Mitgliedsvariable akzeptieren. Auf diese Weise wirft der Compiler einen Compiler -Fehler aus, wenn ein Wert vergessen wurde. Zusätzlich zu diesem sType wird automatisch mit dem richtigen Wert gefüllt und standardmäßig auf nullptr pNext . So sieht der gleiche Code mit einem Konstruktor aus:
vk::ImageCreateInfo ci ({}, vk::ImageType::e2D, vk::Format::eR8G8B8A8Unorm,
{ width, height, 1 },
1 , 1 , vk::SampleCountFlagBits:: e1 ,
vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eColorAttachment,
vk::SharingMode::eExclusive, 0 , nullptr , vk::ImageLayout::eUndefined);
vk::Image image = device.createImage(ci); Mit Konstruktoren für CreateInfo -Strukturen kann man auch temporäre an Vulkan -Funktionen wie folgt übergeben:
vk::Image image = device.createImage({{}, vk::ImageType::e2D, vk::Format::eR8G8B8A8Unorm,
{ width, height, 1 },
1 , 1 , vk::SampleCountFlagBits:: e1 ,
vk::ImageTiling::eOptimal, vk::ImageUsageFlagBits::eColorAttachment,
vk::SharingMode::eExclusive, 0 , nullptr , vk::ImageLayout::eUndefined}); Beginnend mit C ++ 20 unterstützt C ++ die benannten Initialisierer. Da diese Funktion erforderlich ist, um keine vom Benutzer abgeschlossenen oder vererbten Konstruktoren zu haben, müssen Sie #define VULKAN_HPP_NO_CONSTRUCTORS , wodurch alle Struktur- und Gewerkschaftskonstruktoren von vulkan.hpp entfernt werden. Stattdessen können Sie dann die Aggregatinitialisierung verwenden. Die ersten VK-Linien in Ihrer Quelle könnten dann so aussehen:
// initialize the vk::ApplicationInfo structure
vk::ApplicationInfo applicationInfo{ . pApplicationName = AppName,
. applicationVersion = 1 ,
. pEngineName = EngineName,
. engineVersion = 1 ,
. apiVersion = VK_API_VERSION_1_1 };
// initialize the vk::InstanceCreateInfo
vk::InstanceCreateInfo instanceCreateInfo{ . pApplicationInfo = &applicationInfo };anstatt
// initialize the vk::ApplicationInfo structure
vk::ApplicationInfo applicationInfo (AppName, 1 , EngineName, 1 , VK_API_VERSION_1_1);
// initialize the vk::InstanceCreateInfo
vk::InstanceCreateInfo instanceCreateInfo ({}, &applicationInfo); Beachten Sie, dass die Beweisanweisung mit der Deklarationsbestellung übereinstimmen muss. Beachten Sie auch, dass Sie jetzt das sType Mitglied von VK-Strukturen explizit festlegen können. Dies ist weder ein teuer (da sie standardmäßig korrekt initialisiert werden) noch empfohlen.
Die Vulkan -API verfügt über mehrere Orte, die (zählen, Zeiger) als zwei Funktionsargumente und C ++ erforderlich sind, die ein paar Container enthält, die perfekt an dieses Paar abbilden. Um die Entwicklung zu vereinfachen, haben die Vulkan-HPP-Bindungen diese Argumentpaare durch die vk::ArrayProxy -Klassenvorlage ersetzt, die leere Arrays und einen einzelnen Wert sowie STL-Container std::initializer_list , std::array und std::vector als Argument für die Konstruktion akzeptiert. Auf diese Weise kann eine einzelne generierte Vulkan -Version eine Vielzahl von Eingaben akzeptieren, ohne die Kombinatorexplosion zu haben, die beim Erstellen einer Funktion für jeden Containertyp auftreten würde.
Hier sind einige Code -Beispiele zur Verwendung des vk::ArrayProxy :
vk::CommandBuffer c;
// pass an empty array
c.setScissor( 0 , nullptr );
// pass a single value. Value is passed as reference
vk::Rect2D scissorRect = { { 0 , 0 }, { 640 , 480 } };
c.setScissor( 0 , scissorRect);
// pass a temporary value.
c.setScissor( 0 , { { 0 , 0 }, { 640 , 480 } });
// pass a fixed size array
vk::Rect2D scissorRects[ 2 ] = { { { 0 , 0 }, { 320 , 240 } }, { { 320 , 240 }, { 320 , 240 } } };
c.setScissor( 0 , scissorRects);
// generate a std::initializer_list using two rectangles from the stack. This might generate a copy of the rectangles.
vk::Rect2D scissorRect1 = { { 0 , 0 }, { 320 , 240 } };
vk::Rect2D scissorRect2 = { { 320 , 240 }, { 320 , 240 } };
c.setScissor( 0 , { scissorRect, scissorRect2 });
// construct a std::initializer_list using two temporary rectangles.
c.setScissor( 0 , { { { 0 , 0 }, { 320 , 240 } },
{ { 320 , 240 }, { 320 , 240 } } });
// pass a std::array
std::array<vk::Rect2D, 2 > arr{ scissorRect1, scissorRect2 };
c.setScissor( 0 , arr);
// pass a std::vector of dynamic size
std::vector<vk::Rect2D> vec;
vec.push_back(scissorRect1);
vec.push_back(scissorRect2);
c.setScissor( 0 , vec); Vulkan-HPP erzeugt Referenzen für Zeiger auf Strukturen. Diese Konvertierung ermöglicht das Übergeben von temporären Strukturen an Funktionen, die zu einem kürzeren Code führen können. Falls die Eingabe optional ist und somit einen Nullzeiger akzeptiert, ist der Parametertyp vk::Optional<T> const& . Dieser Typ akzeptiert entweder einen Verweis auf T oder nullptr als Eingabe und ermöglicht somit optionale temporäre Strukturen.
// C
VkImageSubresource subResource;
subResource.aspectMask = 0 ;
subResource.mipLevel = 0 ;
subResource.arrayLayer = 0 ;
VkSubresourceLayout layout;
vkGetImageSubresourceLayout (device, image, &subresource, &layout);
// C++
auto layout = device.getImageSubresourceLayout(image, { {} /* flags */ , 0 /* miplevel */ , 0 /* arrayLayer */ }); Vulkan ermöglicht das Erhalten von Strukturen durch den pNext -Zeiger. Vulkan-HPP verfügt über eine variadische Klassenvorlage, die das Erstellen solcher Strukturketten mit minimalen Anstrengungen ermöglicht. Darüber hinaus überprüft es zur Kompilierungszeit, wenn die Spezifikation die Konstruktion einer solchen pNext -Kette ermöglicht.
// This will compile successfully.
vk::StructureChain<vk::MemoryAllocateInfo, vk::ImportMemoryFdInfoKHR> c;
vk::MemoryAllocateInfo &allocInfo = c.get<vk::MemoryAllocateInfo>();
vk::ImportMemoryFdInfoKHR &fdInfo = c.get<vk::ImportMemoryFdInfoKHR>();
// This will fail compilation since it's not valid according to the spec.
vk::StructureChain<vk::MemoryAllocateInfo, vk::MemoryDedicatedRequirementsKHR> c;
vk::MemoryAllocateInfo &allocInfo = c.get<vk::MemoryAllocateInfo>();
vk::ImportMemoryFdInfoKHR &fdInfo = c.get<vk::ImportMemoryFdInfoKHR>(); Vulkan-HPP bietet einen Konstruktor für diese Ketten, ähnlich wie die CreateInfo Objekte, die eine Liste aller Strukturen akzeptiert, die Teil der Kette sind. Das pNext -Feld wird automatisch auf den richtigen Wert eingestellt:
vk::StructureChain<vk::MemoryAllocateInfo, vk::MemoryDedicatedAllocateInfo> c = {
vk::MemoryAllocateInfo (size, type),
vk::MemoryDedicatedAllocateInfo (image)
}; Wenn eine der Strukturen eines Structurechains entfernt werden soll, können Sie möglicherweise aufgrund einiger optionaler Einstellungen die Funktion vk::StructureChain::unlink<ClassType>() verwenden. Es modifiziert den Structurechain so, dass die angegebene Struktur nicht mehr Teil der PNEXT-Kette ist. Beachten Sie, dass das tatsächliche Speicherlayout des Structurechain durch diese Funktion nicht geändert wird. Wenn diese gleiche Struktur wieder in den Structurechain wieder eingeleitet werden muss, verwenden Sie vk::StructureChain::relink<ClassType>() .
Manchmal muss der Benutzer eine preallozierte Strukturkette übergeben, um Informationen abzufragen. In diesen Fällen gibt es zwei entsprechende Getter -Funktionen. Eine mit einer variadischen Vorlage, die eine Strukturkette von mindestens zwei Elementen erzeugt, um den Rückgabewert zu erstellen:
// Query vk::MemoryRequirements2HR and vk::MemoryDedicatedRequirementsKHR when calling Device::getBufferMemoryRequirements2KHR:
auto result = device.getBufferMemoryRequirements2KHR<vk::MemoryRequirements2KHR, vk::MemoryDedicatedRequirementsKHR>({});
vk::MemoryRequirements2KHR &memReqs = result.get<vk::MemoryRequirements2KHR>();
vk::MemoryDedicatedRequirementsKHR &dedMemReqs = result.get<vk::MemoryDedicatedRequirementsKHR>();Um nur die Basisstruktur zu erhalten, muss die andere Getter -Funktion ohne Kettung kein Vorlagenargument für die Struktur benötigen, um zu erhalten:
// Query just vk::MemoryRequirements2KHR
vk::MemoryRequirements2KHR memoryRequirements = device.getBufferMemoryRequirements2KHR({}); Standardmäßig verfügt Vulkan-HPP über Ausnahmen. Dies bedeutet, dass Vulkan-HPP den Rückgabecode jedes Funktionsaufrufs überprüft, der ein vk::Result zurückgibt. Wenn vk::Result ein Fehler ist, wird ein std::runtime_error geworfen. Da der Fehlercode nicht mehr zurückgeben muss, können die C ++ - Bindungen jetzt den tatsächlichen gewünschten Rückgabewert zurückgeben, dh ein Vulkan -Handle. In diesen Fällen wird vk::ResultValue<SomeType>::type definiert als der zurückgegebene Typ.
Um ein Gerät zu erstellen, können Sie jetzt nur schreiben:
vk::Device device = physicalDevice.createDevice(createInfo); Einige Funktionen ermöglichen mehr als nur vk::Result::eSuccess als Erfolgscode. Für diese Funktionen geben wir immer ein vk::ResultValue<SomeType> zurück. Ein Beispiel ist acquireNextImage2KHR , der so verwendet werden kann:
vk::ResultValue< uint32_t > result = device-> acquireNextImage2KHR (acquireNextImageInfo);
switch (result.result)
{
case vk::Result::eSuccess:
currentBuffer = result. value ;
break ;
case vk::Result::eTimeout:
case vk::Result::eNotReady:
case vk::Result::eSuboptimalKHR:
// do something meaningful
break ;
default :
// should not happen, as other return codes are considered to be an error and throw an exception
break ;
} Im Laufe der Zeit können sich einige Vulkan -Funktionen ändern, sodass sie mehr Ergebniscodes als vk::Result::eSuccess als Erfolgscode unterstützen. Diese logische Veränderung wäre in der C -API nicht sichtbar, aber in der C ++ - API würde eine solche Funktion jetzt ein vk::ResultValue<SomeType> anstelle von SomeType zurückgeben. In solchen (seltenen) Fällen müssten Sie Ihre CPP-Quellen anpassen, um diese API-Änderung widerzuspiegeln.
Wenn VULKAN_HPP_NO_EXCEPTIONS Ausnahmebehandlung deaktiviert wird, indem vk::ResultValue<SomeType>::type tytyp ein Struktur ist, das ein vk::Result und eine irgendwoype -type hält, und ein SomeType . Diese Struktur unterstützt das Auspacken der Rückgabewerte durch die Verwendung von std::tie .
Falls Sie nicht die vk::ArrayProxy und die Rückgabe der Wertveränderung verwenden möchten, können Sie die Funktion der C-Art im C-Stil aufrufen. Im Folgenden finden Sie drei Beispiele, die die 3 Möglichkeiten zur Verwendung der API zeigen:
Der erste Ausschnitt zeigt, wie die API ohne Ausnahmen und die Rückgabewerttransformation verwendet werden:
// No exceptions, no return value transformation
vk::ShaderModuleCreateInfo createInfo (...);
vk::ShaderModule shader1;
vk::Result result = device.createShaderModule(&createInfo, allocator, &shader1);
if (result.result != vk::Result::eSuccess)
{
handle error code;
cleanup?
return ?
}
vk::ShaderModule shader2;
vk::Result result = device.createShaderModule(&createInfo, allocator, &shader2);
if (result != vk::Result::eSuccess)
{
handle error code;
cleanup?
return ?
}Der zweite Ausschnitt zeigt, wie die API mithilfe der Rückgabewerttransformation verwendet wird, jedoch ohne Ausnahmen. Es ist schon ein bisschen kürzer als der ursprüngliche Code:
vk::ResultValue<ShaderModule> shaderResult1 = device.createShaderModule({...} /* createInfo temporary */ );
if (shaderResult1.result != vk::Result::eSuccess)
{
handle error code;
cleanup?
return ?
}
// std::tie support.
vk::Result result;
vk::ShaderModule shaderModule2;
std::tie (result, shaderModule2) = device.createShaderModule({...} /* createInfo temporary */ );
if (result != vk::Result::eSuccess)
{
handle error code;
cleanup?
return ?
}Eine schönere Möglichkeit, das Ergebnis auszupacken, besteht darin, strukturierte Bindungen in C ++ 17 zu verwenden. Sie ermöglichen es uns, das Ergebnis mit einer einzelnen Codezeile zu erzielen:
auto [result, shaderModule2] = device.createShaderModule({...} /* createInfo temporary */ );Schließlich ist das letzte Code -Beispiel die Verwendung von Ausnahmen und Rückgabewerttransformation. Dies ist der Standardmodus der API.
vk::ShaderModule shader1;
vk::ShaderModule shader2;
try
{
shader1 = device. createShaderModule ({...});
shader2 = device. createShaderModule ({...});
}
catch (std:: exception const &e)
{
// handle error and free resources
}Wichtig
Die Vulkan -Handles im vk -NamePace unterstützen Raii nicht. Daher müssen Sie Ihre Ressourcen im Fehlerhandler aufräumen! Stattdessen können Sie die Griff -Wrapper -Klassen im vk::raii -namespace verwenden.
Mit C ++ 17 und oben werden einige Funktionen mit [[nodiscard]] zugeschrieben, was zu einer Warnung führt, wenn Sie den Rückgabewert in keiner Weise verwenden. Sie können diese Warnungen ausschalten, indem Sie VULKAN_HPP_NO_NODISCARD_WARNINGS definieren.
Für die Rückgabewerttransformation gibt es eine spezielle Klasse von Rückgabewerten, die eine spezielle Handhabung erfordern: Aufzählungen. Für Aufzählungen müssen Sie normalerweise einen solchen Code schreiben:
std::vector<LayerProperties, Allocator> properties;
uint32_t propertyCount;
vk::Result result;
do
{
// determine number of elements to query
result = static_cast <vk::Result>( vk::enumerateDeviceLayerProperties (m_physicalDevice, &propertyCount, nullptr ));
if ((result == vk::Result::eSuccess) && propertyCount)
{
// allocate memory & query again
properties. resize (propertyCount);
result = static_cast <vk::Result>( vk::enumerateDeviceLayerProperties (m_physicalDevice, &propertyCount, reinterpret_cast
<VkLayerProperties*>(properties. data ())));
}
} while (result == vk::Result::eIncomplete);
// it's possible that the count has changed, start again if properties was not big enough
properties.resize(propertyCount);Da das Schreiben dieser Schleife immer und immer wieder mühsam ist und fehleranfällig ist, kümmert sich die C ++ - Bindung um die Aufzählung, damit Sie einfach schreiben können:
std::vector<LayerProperties> properties = physicalDevice.enumerateDeviceLayerProperties(); Vulkan-HPP bietet eine vk::UniqueHandle<Type, Deleter> Schnittstelle. Für jeden Vulkan -Grifftyp vk::Type gibt es ein einzigartiges Handle vk::UniqueType , der die zugrunde liegende Vulkan -Ressource nach Zerstörung löscht, z. B. vk::UniqueBuffer ist der einzigartige Griff für vk::Buffer .
Für jede Funktion, die ein Vulkan-Handle vom Typ vk::Type Vulkan-HPP erstellt, bietet eine zweite Version, die einen vk::UniqueType Rückgang zurückgibt. EG für vk::Device::createBuffer Es gibt vk::Device::createBufferUnique und für vk::allocateCommandBuffers gibt es vk::allocateCommandBuffersUnique .
Beachten Sie, dass die Verwendung vk::UniqueHandle kostenpflichtig ist, da die meisten Löschungen die für den Bau verwendete vk::AllocationCallbacks und das übergeordnete Handle speichern müssen, da sie für die automatische Zerstörung erforderlich sind.
Vulkan-HPP stellt eine vk::SharedHandle<Type> -Schinnee bereit. Für jeden Vulkan -Handlungs -Typ vk::Type gibt es einen gemeinsam genutzten Griff vk::SharedType , der die zugrunde liegende Vulkan -Ressource nach Zerstörung löscht, z. B. vk::SharedBuffer ist das gemeinsame Griff für vk::Buffer .
Im Gegensatz zu vk::UniqueHandle nimmt vk::SharedHandle die gemeinsame Besitz der Ressource sowie dessen Elternteil. Dies bedeutet, dass der Elterngriff erst zerstört wird, wenn alle Kinderressourcen gelöscht werden. Dies ist nützlich für Ressourcen, die zwischen mehreren Threads oder Objekten geteilt werden.
Dieser Mechanismus sorgt für die korrekte Zerstörungsreihenfolge, auch wenn der übergeordnete vk::SharedHandle vor dem Kindesgriff zerstört wird. Ansonsten verhält sich der Griff wie std::shared_ptr . vk::SharedInstance oder eines seines untergeordneten Objekts sollte zuletzt gelöscht werden (zuerst erstellt, zuerst in der Klassenerklärung).
Es gibt noch keine Funktionen, die einen vk::SharedHandle direkt zurückgeben. Stattdessen können Sie ein vk::SharedHandle aus einem vk::Handle erstellen:
vk::Buffer buffer = device.createBuffer(...);
vk::SharedBuffer sharedBuffer (buffer, device); // sharedBuffer now owns the buffer Es gibt mehrere Spezialisierungen von vk::SharedHandle für verschiedene Grifftypen. Zum Beispiel kann vk::SharedImage ein zusätzliches Argument angeben, um anzugeben, ob das Bild von Swapchain gehört:
vk::Image image = swapchain.getImages(...)[ 0 ]; // get the first image from the swapchain
vk::SharedImage sharedImage (image, device, SwapChainOwns::yes); // sharedImage now owns the image, but won't destroy it Es gibt auch eine Spezialisierung für vk::SwapchainKHR , die ein zusätzliches Argument zum Angeben einer Oberfläche nimmt:
vk::SwapchainKHR swapchain = device.createSwapchainKHR(...);
vk::SharedSwapchainKHR sharedSwapchain (swapchain, device, surface); // sharedSwapchain now owns the swapchain and surface Sie können eine vk::SharedHandle -Überladung für Ihren eigenen Handlungsart oder ihre eigenen gemeinsamen Griffe erstellen, indem Sie SharedHandleBase mehrere Vorlagenargumente bereitstellen:
Geben Sie damit eine benutzerdefinierte statische Zerstörungsfunktion internalDestroy an, die einen übergeordneten Griff und einen Griff zum Zerstören aufnimmt. Vergessen Sie nicht, eine Freundschaftserklärung für die Basisklasse hinzuzufügen.
// Example of a custom shared device, that takes in an instance as a parent
class shared_handle <VkDevice> : public vk::SharedHandleBase<VkDevice, vk::SharedInstance, shared_handle<VkDevice>>
{
using base = vk::SharedHandleBase<VkDevice, vk::SharedInstance, shared_handle<VkDevice>>;
friend base;
public:
shared_handle () = default ;
explicit shared_handle (VkDevice handle, vk::SharedInstance parent) noexcept
: base(handle, std::move(parent)) {}
const auto & getParent () const noexcept
{
return getHeader ();
}
protected:
static void internalDestroy ( const vk::SharedInstance& /* control */ , VkDevice handle) noexcept
{
kDestroyDevice (handle);
}
};Die API wird erweitert, um in Zukunft Erstellungsfunktionen bereitzustellen.
Zusätzlich zu vk::UniqueHandles und vk::SharedHandles gibt es eine Reihe von Wrapper-Klassen für alle Grifftypen, die dem Raii-Paradigma folgen (Ressourcenerwerb ist Initialisierung), die im vk::raii -Namespace bereitgestellt werden.
Während ein vk::UniqueHandle einen von einem std::unique_ptr verpackten Griff imitiert und ein vk::SharedHandle vk::raii::Handle von einem std::shared_ptr , einschließlich Elterninformationen, ein Griff eingepackt hat. Daher können Sie sie als Werte verwenden oder mit einem intelligenten Zeiger einwickeln.
Abgesehen von den vk::Handles müssen alle diese Handlungsklassen zusätzliche Daten enthalten und sind daher nicht binär identisch mit den Vulkan-C-Graßen.
Da die vk::UniqueHandles und die vk::SharedHandles denselben Dispatcher wie die vk::Handles verwenden, können sie leicht gemischt werden. Die vk::raii::Handles verwenden einige etwas andere Disponenten und sind daher nicht mit den anderen Handles kompatibel! Das heißt, für die vk-Handles , die vk::UniqueHandles und die vk::SharedHandles müssen Sie einen globalen Dispatcher instanziieren, wie in https://github.com/khronosgroup/vulkan-hpp#extexssions-Per-device-function-Pointers beschrieben. Für die vk::raii-Handles ist dies nicht erforderlich, da sie ihre eigenen Dispatcher unterhalten. Der große Vorteil hierfür ist, wenn Sie mehrere Geräte haben: Die Funktionen, die über die vk::raii-Handles aufgerufen werden, nennen immer die Gerätespezifischen Funktionen.
Manchmal ist es erforderlich std::vector mit benutzerdefinierten Allocatoren zu verwenden. Vulkan-HPP unterstützt Vektoren mit benutzerdefinierten Allocatoren als Eingabe für vk::ArrayProxy und für Funktionen, die einen Vektor zurückgeben. Fügen Sie für den letzteren Fall Ihren bevorzugten benutzerdefinierten Allocator als Vorlagenargument zum Funktionsaufruf wie folgt hinzu:
std::vector<LayerProperties, MyCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties<MyCustomAllocator>(); Sie können auch einen staatlichen benutzerdefinierten Allocator verwenden, indem Sie ihn als Argument für diese Funktionen vorlegen. Um die Compiler glücklich zu machen, müssen Sie leider auch das Versandargument explizit festlegen. Um die Standardeinstellung dort zu erhalten, würde ein einfaches {} ausreichen:
MyStatefulCustomAllocator allocator;
std::vector<LayerProperties, MyStatefulCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties(allocator, {}); Überall vulkan.hpp gibt es ein paar Anrufe an eine Assert -Funktion. Durch die Definition VULKAN_HPP_ASSERT können Sie Ihre eigene benutzerdefinierte Assert -Funktion stattdessen angeben.
Standardmäßig wird VULKAN_HPP_ASSERT_ON_RESULT zum Überprüfen der Ergebnisse verwendet, wenn VULKAN_HPP_NO_EXCEPTIONS definiert ist. Wenn Sie Fehler selbst bewältigen möchten, können Sie es wie VULKAN_HPP_ASSERT deaktivieren/anpassen.
Es gibt einige statische Behauptungen für jede Handlungsklasse und jede Struktur in der Datei vulkan_static_assertions.hpp . Sie können diese Datei in mindestens einer Ihrer Quelldateien aufnehmen. Durch die Definition VULKAN_HPP_STATIC_ASSERT können Sie Ihre eigene benutzerdefinierte statische Behauptung angeben, die für diese Fälle verwendet werden soll. Das heißt, indem Sie es als NOP definieren, können Sie Ihre Kompilierungszeit ein wenig verkürzen.
Der Vulkan -Lader enthält nur die Vulkan -Kernfunktionen und eine begrenzte Anzahl von Erweiterungen. Um Vulkan-HPP mit Erweiterungen zu verwenden, müssen entweder eine Bibliothek über alle verwendeten Vulkan-Funktionen Stubs bereitgestellt werden, oder um Vulkan-HPP zu fordern, diese Funktionen zu entsenden. Vulkan-HPP stellt einen Funktionsmechanismus pro Funktion an, indem eine Versandklasse als letzter Parameter in jedem Funktionsaufruf akzeptiert wird. Die Versandklasse muss für jede gebrauchte Vulkan -Funktion einen aufrufbaren Typ bereitstellen. Vulkan-HPP bietet eine Implementierung, DispatchLoaderDynamic , die alle Funktionszeiger holt, die der Bibliothek bekannt sind.
// Providing a function pointer resolving vkGetInstanceProcAddr, just the few functions not depending an an instance or a device are fetched
vk::DispatchLoaderDynamic dld (getInstanceProcAddr);
// Providing an already created VkInstance and a function pointer resolving vkGetInstanceProcAddr, all functions are fetched
vk::DispatchLoaderDynamic dldi (instance, getInstanceProcAddr);
// Providing also an already created VkDevice and optionally a function pointer resolving vkGetDeviceProcAddr, all functions are fetched as well, but now device-specific functions are fetched via vkDeviceGetProcAddr.
vk::DispatchLoaderDynamic dldid ( nstance, getInstanceProcAddr, device);
// Pass dispatch class to function call as last parameter
device.getQueue(graphics_queue_family_index, 0 , &graphics_queue, dldid); Um den vk::DispatchLoaderDynamic als Standard -Dispatcher zu verwenden (bedeutet: Sie müssen ihn nicht explizit zu jedem Funktionsaufruf hinzufügen), müssen Sie #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 und den Macro VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE auf genau auf Ihr Defatch_dynamic -Diagramm. Anschließend können Sie es vom Macro VULKAN_HPP_DEFAULT_DISPATCHER verwenden, wie in den folgenden Code -Snippets gezeigt. Das Erstellen eines vollständigen vk::DispatchLoaderDynamic ist ein zwei- bis dreistufiger Prozess, bei dem Sie drei Möglichkeiten für den ersten Schritt haben:
vk::DynamicLoader verwenden: VULKAN_HPP_DEFAULT_DISPATCHER.init();getProcAddress bereitstellen muss (vergleichen Sie mit vk::DynamicLoader in vulkan.hpp ): YourDynamicLoader ydl;
VULKAN_HPP_DEFAULT_DISPATCHER.init(ydl);Notiz
Sie müssen dieses dynamische Laderobjekt bis nach dem letzten Anruf bei einer Vulkan -Funktion in Ihrem Programm am Leben erhalten. Zum Beispiel, indem Sie es statisch machen oder global speichern.
PFN_vkGetInstanceProcAddr : PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = your_own_function_pointer_getter();
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);vk::Instance , um alle anderen Funktionszeiger zu erhalten: vk::Instance instance = vk::createInstance({}, nullptr );
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);vk::Device initialisieren std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
assert (!physicalDevices.empty());
vk::Device device = physicalDevices[ 0 ].createDevice({}, nullptr );
VULKAN_HPP_DEFAULT_DISPATCHER.init(device);Nach dem zweiten Schritt oben ist der Dispatcher voll funktionsfähig. Das Hinzufügen des dritten Schritts kann möglicherweise zu einem effizienteren Code führen. Wenn Sie jedoch mehrere Geräte verwenden möchten, können Sie diesen dritten Schritt einfach weglassen und den Treiber die Geräte-Dispatching durchführen lassen.
In einigen Fällen sollte der Speicher für die Versandladerdynamik in eine DLL eingebettet werden. In diesen Fällen müssen Sie VULKAN_HPP_STORAGE_SHARED definieren, um Vulkan-HPP mitzuteilen, dass sich der Speicher in einer DLL befindet. Beim Kompilieren der DLL mit dem Speicher muss auch VULKAN_HPP_STORAGE_SHARED_EXPORT definiert werden, um die erforderlichen Symbole zu exportieren.
Für alle Funktionen ist dieser VULKAN_HPP_DEFAULT_DISPATCHER der Standard für das letzte Argument für diese Funktion. Wenn Sie den Dispatcher explizit für jeden Funktionsanruf angeben möchten (wenn Sie beispielsweise mehrere Disponenten für verschiedene Geräte haben) und sicherstellen möchten, dass Sie keinen Funktionsanruf verpassen, können Sie VULKAN_HPP_NO_DEFAULT_DISPATCHER definieren, bevor Sie vulkan.hpp einschließen, um dieses Standardargument zu entfernen.
vulkan.hpp bietet ein paar Typ -Merkmale, die die Metaprogrammierung von Vorlagen erleichtern:
template <typename EnumType, EnumType value> struct CppType Maps IndexType -Werte ( IndexType::eUint16 , IndexType::eUint32 , ...) zum entsprechenden Typ ( uint16_t , uint32_t , ...) vom Type ; Maps ObjectType -Werte ( ObjectType::eInstance , ObjectType::eDevice , ...) zum entsprechenden Typ ( vk::Instance , vk::Device , ...) durch den Type ; Maps DebugReportObjectType -Werte ( DebugReportObjectTypeEXT::eInstance , DebugReportObjectTypeEXT::eDevice , ...) zum entsprechenden Typ ( vk::Instance , vk::Device , ...) durch den Type ;template <typename T> struct IndexTypeValue -Karten Skalartypen ( uint16_t , uint32_t , ...) zum entsprechenden IndexType -Wert ( IndexType::eUint16 , IndexType::eUint32 , ...).template <typename T> struct isVulkanHandleType ordnet einen Typ zu true , wenn es nur dann ist, wenn es sich um eine Handlungsklasse ( vk::Instance , vk::Device , ...) durch den statischen value handelt.HandleClass::CType ordnet eine Handlungsklasse ( vk::Instance , vk::Device , ...) an den entsprechenden C-Typ ( VkInstance , VkDevice , ...) durch den Mitgliedstyp CType .HandleClass::objectType ordnet eine Handlungsklasse ( vk::Instance , vk::Device , ...) an den entsprechenden ObjectType -Wert ( ObjectType::eInstance , ObjectType::eDevice , ...) durch das statische Element objectType .HandleClass::debugReportObjectType karten eine Handlungsklasse ( vk::Instance , vk::Device , ...) zu dem entsprechenden DebugReportObjectTypeEXT -Wert ( DebugReportObjectTypeEXT::eInstance , DebugReportObjectTypeEXT::eDevice , ...) durch das statische Mitglied debugReportObjectType Mit dem zusätzlichen Header vulkan_format_traits.hpp werden einige Merkmalsfunktionen auf vk::Format bereitgestellt. Bei C ++ 14 und höher sind alle diese Funktionen als constexpr gekennzeichnet, dh mit geeigneten Argumenten werden sie zum Kompilierungszeit gelöst.
uin8_t blockSize( vk::Format format ); Erholt die Texel -Blockgröße dieses Formats in Bytes.uint8_t texelsPerBlock( vk::Format format ); Erholt die Anzahl der Texels in einem Texel -Block.std::array<uint8_t, 3> blockExtent( vk::Format format ); Erhält das dreidimensionale Ausmaß der Texelblöcke.char const * compressionScheme( vk::Format format ); Ruft eine Textbeschreibung des Komprimierungsschemas dieses Formats oder eines leeren Textes ab, wenn es nicht komprimiert ist.bool isCompressed( vk::Format format ); Wenn das Format ein komprimiertes Format ist, sonst falsch.uint8_t packed( vk::Format format ); Ruft die Anzahl der Bits ab, in die das Format gepackt ist. Ein einzelnes Bildelement in diesem Format kann im selben Raum wie ein Skalartyp dieser Bitbreite gespeichert werden.uint8_t componentCount( vk::Format format ); Ruft die Anzahl der Komponenten dieses Formats ab.bool componentsAreCompressed( vk::Format format ); Es ist wahr, wenn die Komponenten dieses Formats komprimiert sind, ansonsten falsch.uint8_t componentBits( vk::Format format, uint8_t component ); Ruft die Anzahl der Bits in dieser Komponente ab, wenn nicht komprimiert, sonst 0.char const * componentName( vk::Format format, uint8_t component ); Ruft den Namen dieser Komponente als C-String ab.char const * componentNumericFormat( vk::Format format, uint8_t component ); Ruft das numerische Format dieser Komponente als C-String ab.uint8_t componentPlaneIndex( vk::Format format, uint8_t component ); Erhält den Ebenenindex, diese Komponente liegt in.uint8_t planeCount( vk::Format format ); Ruft die Anzahl der Bildebenen dieses Formats ab.vk::Format planeCompatibleFormat( vk::Format format, uint8_t plane ); Ruft ein einweichensem Format ab, das mit dieser Ebene kompatibel ist.uint8_t planeHeightDivisor( vk::Format format, uint8_t plane ); Erhält die relative Höhe dieser Ebene. Ein Wert von k bedeutet, dass diese Ebene 1/k die Höhe des Gesamtformats beträgt.uint8_t planeWidthDivisor( vk::Format format, uint8_t plane ); Erhält die relative Breite dieser Ebene. Ein Wert von k bedeutet, dass diese Ebene 1/k die Breite des Gesamtformats beträgt. Mit dem zusätzlichen Header vulkan_hash.hpp erhalten Sie Spezialisierungen von std::hash für die Handlungs -Wrapper -Klassen und mit C ++ 14 für die Strukturverpackungen. Mit VULKAN_HPP_HASH_COMBINE können Sie Ihren eigenen Hash definieren, der Algorithmus für die Strukturelemente kombiniert.
Mit dem zusätzlichen Header vulkan_extension_inspection.hpp werden einige Funktionen zur Überprüfung von Erweiterungen bereitgestellt. Mit C ++ 20 und höher werden einige dieser Funktionen als constexpr markiert, dh mit geeigneten Argumenten werden sie zum Kompilierungszeit gelöst. Jede Erweiterung wird durch eine Zeichenfolge identifiziert, die ihren Namen enthält. Beachten Sie, dass für jede Erweiterung ein Definieren mit diesem Namen vorhanden ist. Einige Funktionen könnten Informationen liefern, die von der Vulkan -Version abhängt. Da alle Funktionen hier ausschließlich auf Strings funktionieren, werden die Vulkan -Versionen von einer Zeichenfolge codiert, die mit "vk_version_" beginnt, gefolgt von der Major und der kleinen Version, die von einem Untermesser getrennt ist, wie folgt: "vk_version_1_0".
std::set<std::string> const & getDeviceExtensions(); Erhält alle für die aktuellen Plattform angegebenen Geräteerweiterungen. Beachten Sie, dass nicht alle von den tatsächlichen Geräten unterstützt werden könnten.std::set<std::string> const & getInstanceExtensions(); Erhält alle für die aktuellen Plattform angegebenen Instanzverlängerungen. Beachten Sie, dass nicht alle von den tatsächlichen Instanzen unterstützt werden könnten.std::map<std::string, std::string> const & getDeprecatedExtensions(); Holen Sie sich eine Karte aller veralteten Erweiterungen in die Erweiterung oder Vulkan -Version, die diese Funktionalität ersetzen soll.std::map<std::string, std::vector<std::vector<std::string>>> const & getExtensionDepends( std::string const & extension ); Einige Erweiterungen hängen von anderen Erweiterungen ab. Diese Abhängigkeiten können sich für verschiedene Vulkan -Versionen unterscheiden, und es kann unterschiedliche Abhängigkeiten für die gleiche Vulkan -Version geben. Diese Funktion erhält einen Vektor von Vektoren von Erweiterungen pro Vulkan -Version, von denen die angegebene Erweiterung abhängt.std::pair<bool, std::vector<std::vector<std::string>> const &> getExtensionDepends( std::string const & version, std::string const & extension ); Das first Mitglied des zurückgegebenen std::pair ist wahr, wenn die angegebene Erweiterung für die angegebene Vulkan -Version angegeben ist, ansonsten false . Das second Mitglied des zurückgegebenen std::pair ist ein Vektor von Erweiterungsvektoren und listet die separaten Erweiterungssätze auf, von der die angegebene Erweiterung für die angegebene Vulkan -Version abhängt.std::map<std::string, std::string> const & getObsoletedExtensions(); Erhält eine Karte aller veralteten Erweiterungen in die Erweiterung oder Vulkan -Version, die diese Erweiterung veraltet hat.std::map<std::string, std::string> const & getPromotedExtensions(); Erhält eine Karte aller Erweiterungen, die zu einer anderen Erweiterung oder zu einer Vulkan -Version zu dieser Erweiterung der Vulkan -Version gefördert wurden.VULKAN_HPP_CONSTEXPR_20 std::string getExtensionDeprecatedBy( std::string const & extension ); Erhält die Erweiterung oder die Vulkan -Version, die die angegebene Erweiterung veraltet ist.VULKAN_HPP_CONSTEXPR_20 std::string getExtensionObsoletedBy( std::string const & extension ); Erhält die Erweiterung oder die Vulkan -Version Die angegebene Erweiterung wird veraltet.VULKAN_HPP_CONSTEXPR_20 std::string getExtensionPromotedTo( std::string const & extension ); Erhält die Erweiterung oder Vulkan -Version, zu der die angegebene Erweiterung befördert wird.VULKAN_HPP_CONSTEXPR_20 bool isDeprecatedExtension( std::string const & extension ); Gibt true zurück, wenn die angegebene Erweiterung durch eine andere Erweiterung oder Vulkan -Version veraltet wird.VULKAN_HPP_CONSTEXPR_20 bool isDeviceExtension( std::string const & extension ); Gibt true zurück, wenn die angegebene Erweiterung eine Geräteerweiterung ist.VULKAN_HPP_CONSTEXPR_20 bool isInstanceExtension( std::string const & extension ); Gibt true zurück, wenn die angegebene Erweiterung eine Instanzerweiterung ist.VULKAN_HPP_CONSTEXPR_20 bool isObsoletedExtension( std::string const & extension ); Gibt true zurück, wenn die angegebene Erweiterung durch eine andere Erweiterung oder Vulkan -Version veraltet wird.VULKAN_HPP_CONSTEXPR_20 bool isPromotedExtension( std::string const & extension ); Gibt true zurück, wenn die angegebene Erweiterung zu einer anderen Erweiterung oder Vulkan -Version gefördert wird.Warnung
Die aktuelle Version von Microsoft Visual Studio 2022 ist nicht in der Lage, das Modul vulkan.cppm zu verarbeiten. Ein Fehler wird eingereicht (https://developerity.visualstudio.com/t/on-building-a-c20-module:-fatal-angeror/10469799#t-nd10485943). Sie können diese Funktion zumindest verwenden, wenn Sie vk::UniqueHandle oder vk::SharedHandle nicht benötigen oder verwenden möchten, indem Sie VULKAN_HPP_NO_SMART_HANDLE definieren.
Vulkan-HPP bietet ein C ++ -Modul mit dem Namen vulkan_hpp in vulkan.cppm . C ++ - Module sollen Header -Dateien ersetzen. Module haben das Potenzial, die Kompilierungszeiten für große Projekte drastisch zu verbessern, da Deklarationen und Definitionen leicht über Übersetzungseinheiten hinweg geteilt werden können, ohne wiederholt Header zu analysieren. Vulkan-HPP verfügt über einige extrem lange Header (z. B. vulkan_structs.hpp ), und das C ++-Modul wird wahrscheinlich die Kompilierzeiten für Projekte verkürzen, die es derzeit verwenden.
Diese Funktion erfordert einen aktuellen Compiler mit vollständiger C ++ 20 -Unterstützung:
cl.exe 19.28 oder höher)Wenn Sie beabsichtigen, die C ++ - Modulunterstützung von CMake (und möglicherweise Ninja) zu verwenden, sind neuere Tools erforderlich:
cl.exe 19.34 oder höher)Warnung
Das Vulkan-HPP C ++ -Modul ist immer noch experimentell. Einige empfohlene Möglichkeiten, es in Ihren Projekten zu verwenden, finden Sie unten. The long-term goal is to submit patches to the CMake FindVulkan module so that users may transparently configure the named module, without needing to declare it as an additional library in consumer CMake code.
CMake is recommended for use with the Vulkan-Hpp named module, as it provides a convenient platform-agnostic way to configure your project. CMake version 3.28 or later is required to support C++ modules. Refer to the CMake documentation on the topic.
CMake provides the FindVulkan module, which may be used to source the Vulkan SDK and Vulkan headers on your system.
# find Vulkan SDK
find_package ( Vulkan REQUIRED )
# Require Vulkan version ≥ 1.3.256 (earliest version when the Vulkan module was available)
if ( ${Vulkan_VERSION} VERSION_LESS "1.3.256" )
message ( FATAL_ERROR "Minimum required Vulkan version for C++ modules is 1.3.256. "
"Found ${Vulkan_VERSION} ."
)
endif ()
# set up Vulkan C++ module as a library
add_library ( VulkanHppModule )
target_sources ( VulkanHppModule PRIVATE
FILE_SET CXX_MODULES
BASE_DIRS ${Vulkan_INCLUDE_DIR}
FILES ${Vulkan_INCLUDE_DIR} /vulkan/vulkan.cppm
)
target_compile_features ( VulkanHppModule PUBLIC cxx_std_20 )
target_link_libraries ( VulkanHppModule PUBLIC Vulkan::Vulkan )
# link Vulkan C++ module into your project
add_executable ( YourProject main.cpp )
target_link_libraries ( YourProject PRIVATE VulkanHppModule ) Configuring the named module is straightforward; add any required Vulkan-Hpp feature macros (listed in Configuration Options) to target_compile_definitions . Zum Beispiel:
# Disable exceptions, disable smart handles, disable constructors
target_compile_definitions ( VulkanHppModule PRIVATE
VULKAN_HPP_NO_EXCEPTIONS
VULKAN_HPP_NO_SMART_HANDLE
VULKAN_HPP_NO_CONSTRUCTORS
) It is important to have VULKAN_HPP_DISPATCH_LOADER_DYNAMIC defined equally for both the module and an importing project. To use the dynamic dispatcher, set it to 1 ; otherwise, leave it undefined or set it to 0 . In CMake, do this in a single line with target_compile_definitions and the PUBLIC scope:
target_compile_definitions ( VulkanHppModule PUBLIC
VULKAN_HPP_DISPATCH_LOADER_DYNAMIC=1
)
# ...
target_link_libraries ( YourProject PRIVATE VulkanHppModule ) Furthermore, you may also prefer linking VulkanHppModule to just the Vulkan::Headers target with the PUBLIC scope instead of Vulkan::Vulkan , so that the vulkan-1 library is not linked in, and the Vulkan headers are available to your consuming project, as detailed further below.
target_link_libraries ( VulkanHppModule PUBLIC Vulkan::Headers ) Finally, supply the macro VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE exactly once in your source code, just as in the non-module case. In order to have that macro available, include vulkan_hpp_macros.hpp , a lightweight header providing all Vulkan-Hpp related macros and defines. And as explained above, you need to initialize that dispatcher in two or three steps:
import vulkan_hpp;
# include < vulkan/vulkan_hpp_macros.hpp >
# if VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1
VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE
# endif
auto main ( int argc, char * const argv[]) -> int
{
# if ( VULKAN_HPP_DISPATCH_LOADER_DYNAMIC == 1 )
// initialize minimal set of function pointers
VULKAN_HPP_DEFAULT_DISPATCHER. init ();
# endif
auto appInfo = vk::ApplicationInfo ( " My App " , 1 , " My Engine " , 1 , vk::makeApiVersion ( 1 , 0 , 0 , 0 ));
// ...
} An example is provided in tests/Cpp20Modules/Cpp20Modules.cpp .
Finally, you can configure and build your project as usual. Note that CMake currently only supports the Ninja and Visual Studio generators for C++ modules.
If you want to use the Vulkan-Hpp C++ module without CMake, you must first pre-compile it, and then import it into your project. You will also need to define any macros that control various features of Vulkan-Hpp, such as VULKAN_HPP_NO_EXCEPTIONS and VULKAN_HPP_NO_SMART_HANDLE . Different compilers have different command-lines for module pre-compilation; however, for initial use, some examples are provided below, assuming the same main.cpp consumer as above.
For MSVC, source vcvars64.bat or use a Developer Command Prompt/Developer PowerShell instance, and run the following:
cl.exe /std:c++20 /interface /TP < path-to-vulkan-hpp > vulkan.cppm
cl.exe /std:c++20 /reference vulkan=vulkan.ifc main.cpp vulkan.obj
.main.exeFor Clang, run the following:
clang++ -std=c++20 < path-to-vulkan-hpp > /vulkan.cppm -precompile -o vulkan.pcm
clang++ -std=c++20 -fprebuilt-module-path=. main.cpp vulkan.pcm -o main
./mainMore information about module compilation may be found at the respective compiler's documentation:
When you configure your project using CMake, you can enable SAMPLES_BUILD to add some sample projects to your solution. Most of them are ports from the LunarG samples, but there are some more, like CreateDebugUtilsMessenger, InstanceVersion, PhysicalDeviceDisplayProperties, PhysicalDeviceExtensions, PhysicalDeviceFeatures, PhysicalDeviceGroups, PhysicalDeviceMemoryProperties, PhysicalDeviceProperties, PhysicalDeviceQueueFamilyProperties, and RayTracing. All those samples should just compile and run. When you configure your project using CMake, you can enable TESTS_BUILD to add some test projects to your solution. Those tests are just compilation tests and are not required to run.
As vulkan.hpp is pretty big, some compilers might need some time to digest all that stuff. In order to potentially reduce the time needed to compile that header, a couple of defines will be introduced, that allow you to hide certain features. Whenever you don't need that corresponding feature, defining that value might improve your compile time. Currently, there are just a couple of such defines:
VULKAN_HPP_NO_SPACESHIP_OPERATOR , which removes the spaceship operator on structures (available with C++20)VULKAN_HPP_NO_TO_STRING , which removes the various vk::to_string functions on enums and bitmasks.VULKAN_HPP_USE_REFLECT , this one needs to be defined to use the reflection function on structures. It's very slow to compile, though! As Vulkan-Hpp often needs to switch between C++ vk-types and corresponding bit-identical C-types, using reinterpret_cast , it is highly recommended to use the compile option -fno-strict-aliasing to prevent potentially breaking compile optimizations.
There are a couple of defines you can use to control the feature set and behaviour of vulkan.hpp :
At various places in vulkan.hpp an assertion statement is used. By default, the standard assert funtions from <cassert> is called. By defining VULKAN_HPP_ASSERT before including vulkan.hpp , you can change that to any function with the very same interface.
If there are no exceptions enabled (see VULKAN_HPP_NO_EXCEPTIONS ), an assertion statement checks for a valid success code returned from every vulkan call. By default, this is the very same assert function as defined by VULKAN_HPP_ASSERT , but by defining VULKAN_HPP_ASSERT_ON_RESULT you can replace just those assertions with your own function, using the very same interface.
Every vk-function gets a Dispatcher as its very last argument, which defaults to VULKAN_HPP_DEFAULT_DISPATCHER . If VULKAN_HPP_DISPATCH_LOADER_DYNAMIC is defined to be 1 , it is defaultDispatchLoaderDynamic . This in turn is the dispatcher instance, which is defined by VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE , which has to be used exactly once in your sources. If, on the other hand, VULKAN_HPP_DISPATCH_LOADER_DYNAMIC is defined to something different from 1 , VULKAN_HPP_DEFAULT_DISPATCHER is set to be DispatchLoaderStatic() . You can use your own default dispatcher by setting VULKAN_HPP_DEFAULT_DISPATCHER to an object that provides the same API. If you explicitly set VULKAN_HPP_DEFAULT_DISPATCHER , you need to set VULKAN_HPP_DEFAULT_DISPATCHER_TYPE accordingly as well.
This names the default dispatcher type, as specified by VULKAN_HPP_DEFAULT_DISPATCHER . Per default, it is DispatchLoaderDynamic or DispatchLoaderStatic, depending on VULKAN_HPP_DISPATCH_LOADER_DYNAMIC being 1 or not 1 , respectively. If you explicitly set VULKAN_HPP_DEFAULT_DISPATCHER , you need to set VULKAN_HPP_DEFAULT_DISPATCHER_TYPE accordingly as well.
If you have not defined your own VULKAN_HPP_DEFAULT_DISPATCHER , and have VULKAN_HPP_DISPATCH_LOADER_DYNAMIC defined to be 1 (the default), you need to have the macro VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE exactly once in any of your source files to provide storage for that default dispatcher. VULKAN_HPP_STORAGE_API then controls the import/export status of that default dispatcher.
When this is defined before including vulkan.hpp , you essentially disable all enhanced functionality. All you then get is:
vk::Flags for bitmasks;vk::StructureChain for compile-time construction of structure chains.If this is not defined, you additionally get:
vk::ArrayProxy<> ), simplifying handling of array data; returning requested data; throwing exceptions on errors (as long as VULKAN_HPP_NO_EXCEPTIONS is not defined);VULKAN_HPP_NO_STRUCT_CONSTRUCTORS is not defined) (consuming vk::ArrayProxyNoTemporaries<> );vk::ArrayProxyNoTemporaries<> );vk::ArrayProxy<> and vk::ArrayProxyNoTemporaries<>vulkan_raii.hpp This either selects the dynamic (when it's 1 ) or the static (when it's not 1 ) DispatchLoader as the default one, as long as it's not explicitly specified by VULKAN_HPP_DEFAULT_DISPATCHER . By default, this is defined to be 1 if VK_NO_PROTOTYPES is defined, otherwise 0 .
By default, a little helper class DynamicLoader is used to dynamically load the vulkan library. If you set it to something different than 1 before including vulkan.hpp , this helper is not available, and you need to explicitly provide your own loader type for the function DispatchLoaderDynamic::init() .
When this is not externally defined and VULKAN_HPP_CPP_VERSION is at least 23 , VULKAN_HPP_EXPECTED is defined to be std::expected , and VULKAN_HPP_UNEXPECTED is defined to be std::unexpected .
By default, the member m_mask of the Flags class template is private. This is to prevent accidentally setting a Flags with some inappropriate value. But it also prevents using a Flags , or a structure holding a Flags , to be used as a non-type template parameter. If you really need that functionality, and accept the reduced security, you can use this define to change the access specifier for m_mask from private to public, which allows using a Flags as a non-type template parameter.
This define can be used to enable m_handle = exchange( rhs.m_handle, {} ) in move constructors of Vulkan-Hpp handles, which default-initializes the rhs underlying value. By default Vulkan-Hpp handles behave like trivial types -- move constructors copying value.
This define can be used to specify your own hash combiner function. In order to determine the hash of a vk-structure, the hashes of the members of that struct are to be combined. This is done by this define, which by default is identical to what the function boost::hash_combine() does. It gets the type of the to-be-combined value, the seed, which is the combined value up to that point, and finally the to-be-combined value. This hash calculation determines a "shallow" hash, as it takes the hashes of any pointer in a structure, and not the hash of a pointed-to value.
This is set to be the compiler-dependent attribute used to mark functions as inline. If your compiler happens to need some different attribute, you can set this define accordingly before including vulkan.hpp .
By default, the namespace used with vulkan.hpp is vk . By defining VULKAN_HPP_NAMESPACE before including vulkan.hpp , you can adjust this.
By default, the file vulkan_to_string.hpp is included by vulkan.hpp and provides functions vk::to_string for enums and bitmasks. If you don't need those functions, you can define VULKAN_HPP_NO_TO_STRING to prevent that inclusion. If you have certain files where you want to use those functions nevertheless, you can explicitly include vulkan_to_string.hpp there.
With C++20, designated initializers are available. Their use requires the absence of any user-defined constructors. Define VULKAN_HPP_NO_CONSTRUCTORS to remove constructors from structs and unions.
When a vulkan function returns an error code that is not specified to be a success code, an exception is thrown unless VULKAN_HPP_NO_EXCEPTIONS is defined before including vulkan.hpp .
With C++17, all vk-functions returning something are declared with the attribute [[nodiscard]] . This can be removed by defining VULKAN_HPP_NO_NODISCARD_WARNINGS before including vulkan.hpp .
By defining VULKAN_HPP_NO_SETTERS before including vulkan.hpp , setter member functions will not be available within structs and unions. Modifying their data members will then only be possible via direct assignment.
By defining VULKAN_HPP_NO_SMART_HANDLE before including vulkan.hpp , the helper class vk::UniqueHandle and all the unique handle types are not available.
With C++20, the so-called spaceship-operator <=> is introduced. If that operator is supported, all the structs and classes in vulkan.hpp use the default implementation of it. As currently some implementations of this operator are very slow, and others seem to be incomplete, by defining VULKAN_HPP_NO_SPACESHIP_OPERATOR before including vulkan.hpp you can remove that operator from those structs and classes.
By default, if VULKAN_HPP_ENABLE_DYNAMIC_LOADER_TOOL is enabled on Win32, vulkan.hpp declares HINSTANCE , LoadLibraryA , and other required symbols. It could cause conflicts with the Windows.h alternatives, such as WindowsHModular . With this define, you can disable these declarations, but you will have to declare them before the vulkan.hpp is included.
If both, VULKAN_HPP_NO_EXCEPTIONS and VULKAN_HPP_EXPECTED are defined, the vk::raii-classes don't throw exceptions. That is, the actual constructors are not available, but the creation-functions must be used. For more details have a look at the vk_raii_ProgrammingGuide.md .
Even though vk::UniqueHandle and vk::SharedHandle are semantically close to pointers, an implicit cast operator to the underlying vk::Handle might be handy. You can add that implicit cast operator by defining VULKAN_HPP_SMART_HANDLE_IMPLICIT_CAST .
With this define you can specify whether the DispatchLoaderDynamic is imported or exported (see VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE ). If VULKAN_HPP_STORAGE_API is not defined externally, and VULKAN_HPP_STORAGE_SHARED is defined, depending on the VULKAN_HPP_STORAGE_SHARED_EXPORT being defined, VULKAN_HPP_STORAGE_API is either set to __declspec( dllexport ) (for MSVC) / __attribute__( ( visibility( "default" ) ) ) (for gcc or clang) or __declspec( dllimport ) (for MSVC), respectively. For other compilers, you might specify the corresponding storage by defining VULKAN_HPP_STORAGE_API on your own.
32-bit vulkan is not typesafe for non-dispatchable handles, so we don't allow copy constructors on this platform by default. To enable this feature on 32-bit platforms, #define VULKAN_HPP_TYPESAFE_CONVERSION 1 . To disable this feature on 64-bit platforms, #define VULKAN_HPP_TYPESAFE_CONVERSION 0 .
See VULKAN_HPP_EXPECTED .
With this define you can include a reflection mechanism on the vk-structures. It adds a function reflect that returns a tuple-version of the structure. That tuple then could easily be iterated. But at least for now, that feature takes lots of compile-time resources, so currently it is recommended to enable that feature only if you're willing to pay that price.
Feel free to submit a PR to add to this list.
Copyright 2015-2020 The Khronos Group Inc.
Lizenziert unter der Apache -Lizenz, Version 2.0 (der "Lizenz"); Sie dürfen diese Datei nur in Übereinstimmung mit der Lizenz verwenden. Sie können eine Kopie der Lizenz bei erhalten
http://www.apache.org/licenses/LICENSE-2.0
Sofern nicht nach geltendem Recht oder schriftlich zu vereinbart wird, wird die im Rahmen der Lizenz verteilte Software auf "As is" -Basis ohne Gewährleistung oder Bedingungen jeglicher Art ausdrücklich oder impliziert verteilt. Siehe die Lizenz für die spezifischen Sprachberechtigungen und Einschränkungen im Rahmen der Lizenz.