O objetivo do Vulkan-HPP é fornecer apenas ligações C ++ para a API da Vulkan C para melhorar a experiência dos desenvolvedores Vulkan sem apresentar o custo de tempo de execução da CPU. Ele adiciona recursos como a segurança do tipo para enumes e campos de bits, suporte de contêineres STL, exceções e enumerações simples.
| Plataforma | Construir status |
|---|---|
| Linux |
Vulkan-HPP faz parte do SDK Lunarg Vulkan desde a versão 1.0.24. Apenas #include <vulkan/vulkan.hpp> e você está pronto para usar as ligações C ++. Se você estiver usando uma versão Vulkan ainda não suportada pelo Vulkan SDK, poderá encontrar a versão mais recente dos cabeçalhos aqui.
O Vulkan-HPP requer um compilador capaz C ++ 11 para compilar. Sabe -se que os seguintes compiladores funcionam:
Para construir as amostras e testes locais, você terá que clonar este repositório e executar o CMake para gerar os arquivos de construção necessários
Instalar dependências.
Abra um shell que fornece Git e clone o repositório com:
git clone --recurse-submodules https://github.com/KhronosGroup/Vulkan-Hpp.git
Altere o diretório atual para o recém-criado diretório Vulkan-HPP.
Crie um ambiente de construção com 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
Pode ser necessário especificar um gerador via -G , para uma lista completa de geradores executar cmake -G .
vulkan.hpp do arquivo de registro vk.xml xml, adicione a -DVULKAN_HPP_RUN_GENERATOR=ON opção na linha de comando cmake. Abra o projeto gerado com um IDE, por exemplo, o Visual Studio ou inicie o processo de construção com cmake --build build --parallel .
Opcional: Atualizar o Vulkan-HPP e seus submódulos executam git pull --recurse-submodules .
Você pode baixar e instalar Vulkan-HPP usando o gerenciador de dependência VCPKG:
git clone https://github.com/Microsoft/vcpkg.git
cd vcpkg
./bootstrap-vcpkg.sh
./vcpkg integrate install
./vcpkg install vulkan-headersA porta Vulkan-HPP no VCPKG é mantida atualizada pelos membros da equipe da Microsoft e pelos colaboradores da comunidade. Se a versão estiver desatualizada, crie uma solicitação de problema ou puxe no repositório VCPKG.
Se o programa Clang-format for encontrado pelo CMake, o CLANG_FORMAT_EXECUTABLE define será definido de acordo. Nesse caso, o vulkan.hpp gerado é formatado usando o arquivo .clang-format localizado no diretório raiz deste projeto. Caso contrário, é formatado como codificado no gerador.
O arquivo VulkanHpp.natvis fornece uma visualização personalizada no vk::Flags para o Visual Studio. Se você adicionar esse arquivo ao diretório NATVIS específico do usuário da sua instalação do Visual Studio (%UserProfile% Documents Visual Studio 2022 Visualizadores), você obterá vk::Flags bem formatados em seu depurador com todos os seus projetos de estúdio visual.
Para evitar colisões de nomes com a API Vulkan C, as ligações C ++ residem no espaço para nome vk . As seguintes regras se aplicam à nova nomeação:
Vk removido. Além disso, a primeira letra de funções é a minúscula.vkCreateInstance pode ser acessado como vk::createInstance .VkImageTiling pode ser acessado como vk::ImageTiling .VkImageCreateInfo pode ser acessado como vk::ImageCreateInfo .VK_ e o tipo de tipo removido. Se o tipo de enumeração for uma extensão, o sufixo de extensão foi removido dos valores da enumeração.Em todos os outros casos, o sufixo de extensão não foi removido.
VK_IMAGETYPE_2D agora é vk::ImageType::e2D .VK_COLOR_SPACE_SRGB_NONLINEAR_KHR agora é vk::ColorSpaceKHR::eSrgbNonlinear .VK_STRUCTURE_TYPE_PRESENT_INFO_KHR agora é vk::StructureType::ePresentInfoKHR ._BIT também foi removido. Em alguns casos, pode ser necessário mover Vulkan-HPP para um espaço para nome personalizado. Isso pode ser alcançado definindo VULKAN_HPP_NAMESPACE antes de incluir Vulkan-HPP.
Vulkan-HPP declara uma classe para todas as alças para garantir a segurança do tipo total e adicionar suporte para funções de membros nas alças. Uma função de membro foi adicionada a uma classe de identificação para cada função que aceita o identificador correspondente como o primeiro parâmetro. Em vez de vkBindBufferMemory(device, ...) pode -se escrever device.bindBufferMemory(...) ou vk::bindBufferMemory(device, ...) .
Há um cabeçalho adicional chamado vulkan_raii.hpp gerado. Esse cabeçalho contém classes de invólucros compatíveis com RAII para os tipos de alça. Isto é, por exemplo, o tipo de alça VkInstance , há um invólucro compatível com RAII vk::raii::Instance . Por favor, dê uma olhada nas amostras usando essas classes no diretório RAII_samples.
Em plataformas de 64 bits, a Vulkan-HPP suporta conversões implícitas entre as alças C ++ Vulkan e as alças C Vulkan. Em plataformas de 32 bits, todas as alças não disputáveis são definidas como uint64_t , impedindo assim verificações de conversão de tipo no tempo de compilação, o que captaria atribuições entre os tipos de identificação incompatíveis. Devido a que o Vulkan-HPP não permite a conversão implícita para plataformas de 32 bits por padrão e é recomendável usar um static_cast para a conversão como esta: VkImage = static_cast<VkImage>(cppImage) para evitar a conversão de algum intbitrary para um alça ou vice-versa por acidente. Se você estiver desenvolvendo seu código em uma plataforma de 64 bits, mas deseja compilar seu código para uma plataforma de 32 bits sem adicionar os elencos explícitos, você pode definir VULKAN_HPP_TYPESAFE_CONVERSION a 1 em seu sistema de construção ou antes de incluir vulkan.hpp . Nas plataformas de 64 bits, esse define é definido como 1 por padrão e pode ser definido como 0 para desativar conversões implícitas.
O recurso de enum do escopo adiciona segurança ao Type aos sinalizadores, mas também evita o uso dos bits de bandeira como entrada para operações bitwise, como & e | .
Como a solução Vulkan-HPP fornece um modelo de classe vk::Flags que traz as operações padrão como &= , |= , & e | para nossas enumes com escopo. Exceto pela inicialização com 0 esta classe se comporta exatamente como uma máscara normal de bits com a melhoria de que é impossível definir bits não especificados pela enumeração correspondente por acidente. Aqui estão alguns exemplos para o manuseio de máscara de bits:
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 */ , ...); Ao construir uma alça no Vulkan, geralmente precisa criar alguma estrutura CreateInfo que descreva o novo identificador. Isso pode resultar em código bastante longo, como pode ser visto no seguinte exemplo Vulkan C:
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); Existem dois problemas típicos que os desenvolvedores da Vulkan encontram ao preencher um campo CreateInfo Struct por campo:
sType está incorreto.Especialmente o primeiro é difícil de detectar.
O Vulkan-HPP fornece construtores para todos os objetos CreateInfo que aceitam um parâmetro para cada variável de membro. Dessa forma, o compilador lança um erro do compilador se um valor tiver sido esquecido. Além deste sType , é automaticamente preenchido com o valor correto e pNext definido como um nullptr por padrão. Veja como o mesmo código parece com um construtor:
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); Com os construtores de estruturas CreateInfo , também é possível passar temporários para funções vulkan como esta:
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}); Começando com C ++ 20, o C ++ suporta inicializadores designados. Como esse recurso exige para não ter nenhum construtores declarados pelo usuário ou herdado, você precisa #define VULKAN_HPP_NO_CONSTRUCTORS , que remove toda a estrutura e os construtores de união do vulkan.hpp . Em vez disso, você pode usar a inicialização agregada. As primeiras linhas de VK em sua fonte podem então parecer:
// 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 };em vez de
// 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); Observe que o pedido do designador precisa corresponder à ordem de declaração. Observe também que agora você pode definir explicitamente o membro sType das estruturas VK. Isso não é necessário (como eles são inicializados corretamente por padrão) nem recomendados.
A API Vulkan possui vários lugares que exigem (contagem, ponteiro), pois dois argumentos de função e C ++ possui alguns recipientes que mapeiam perfeitamente para este par. Para simplificar o desenvolvimento, as ligações Vulkan-HPP substituíram esses pares de argumentos pelo modelo de classe vk::ArrayProxy , que aceita matrizes vazias e um único valor, bem como os contêineres STL std::initializer_list , std::array e std::vector como argumento para construção. Dessa forma, uma única versão vulkan gerada pode aceitar uma variedade de entradas sem ter a explosão combinatória que ocorreria ao criar uma função para cada tipo de contêiner.
Aqui estão algumas amostras de código sobre como usar o 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 gera referências para ponteiros para estruturas. Essa conversão permite passar estruturas temporárias para funções que podem resultar em código mais curto. Caso a entrada seja opcional e, assim, aceitar um ponteiro nulo, o tipo de parâmetro será vk::Optional<T> const& . Este tipo aceita uma referência a T ou nullptr como entrada e, portanto, permite estruturas temporárias opcionais.
// 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 permite o encadeamento de estruturas através do ponteiro pNext . O Vulkan-HPP possui um modelo de classe variada que permite a construção de essas cadeias de estrutura com esforços mínimos. Além disso, verifica no momento da compilação se a especificação permitir a construção de uma cadeia pNext .
// 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>(); O Vulkan-HPP fornece um construtor para essas cadeias semelhantes aos objetos CreateInfo que aceita uma lista de todas as estruturas parte da cadeia. O campo pNext é definido automaticamente para o valor correto:
vk::StructureChain<vk::MemoryAllocateInfo, vk::MemoryDedicatedAllocateInfo> c = {
vk::MemoryAllocateInfo (size, type),
vk::MemoryDedicatedAllocateInfo (image)
}; Se uma das estruturas de um StructureCain for removida, talvez devido a algumas configurações opcionais, você pode usar a função vk::StructureChain::unlink<ClassType>() . Ele modifica a StructureChain de modo que a estrutura especificada não faz mais parte da cadeia pnext. Observe que o layout de memória real do StructureChain não é modificado por essa função. Caso essa mesma estrutura deva ser re-adiada para o StructureChain novamente, use vk::StructureChain::relink<ClassType>() .
Às vezes, o usuário precisa passar uma cadeia de estrutura pré -alocada para consultar informações. Para esses casos, existem duas funções getter correspondentes. Um com um modelo variúdico gerando uma cadeia de estrutura de pelo menos dois elementos para construir o valor de retorno:
// 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>();Para obter apenas a estrutura base, sem encadear, a outra função getter fornecida não precisa de um argumento de modelo para a estrutura obter:
// Query just vk::MemoryRequirements2KHR
vk::MemoryRequirements2KHR memoryRequirements = device.getBufferMemoryRequirements2KHR({}); Por padrão, Vulkan-HPP tem exceções ativadas. Isso significa que o Vulkan-HPP verifica o código de retorno de cada chamada de função que retorna um vk::Result . Se vk::Result é uma falha, um std::runtime_error será jogado. Como não há necessidade de retornar mais o código de erro, as ligações C ++ agora podem retornar o valor de retorno desejado real, ou seja, uma alça Vulkan. Nesses casos vk::ResultValue<SomeType>::type é definido como o tipo retornado.
Para criar um dispositivo, agora você pode apenas escrever:
vk::Device device = physicalDevice.createDevice(createInfo); Algumas funções permitem que mais do que apenas vk::Result::eSuccess sejam consideradas como um código de sucesso. Para essas funções, sempre retornamos um vk::ResultValue<SomeType> . Um exemplo é acquireNextImage2KHR , que pode ser usado assim:
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 ;
} À medida que o tempo passa, algumas funções vulkan podem mudar, de modo que elas comecem a suportar mais códigos de resultados do que vk::Result::eSuccess como um código de sucesso. Essa mudança lógica não seria visível na API C, mas na API C ++, pois essa função agora retornaria um vk::ResultValue<SomeType> em vez de apenas SomeType . Nes casos (raros), você teria que ajustar suas fontes de CPP para refletir essa mudança de API.
Se o manuseio de exceções estiver desativado, definindo VULKAN_HPP_NO_EXCEPTIONS , o tipo de vk::ResultValue<SomeType>::type é uma estrutura que segura um vk::Result e um SomeType . Essa estrutura suporta descompactar os valores de retorno usando std::tie .
Caso você não queira usar a transformação vk::ArrayProxy e Return Value, você ainda pode chamar a função simples do estilo C. Abaixo estão três exemplos mostrando as três maneiras de usar a API:
O primeiro trecho mostra como usar a API sem exceções e a transformação do valor de retorno:
// 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 ?
}O segundo snippet mostra como usar a API usando a transformação do valor de retorno, mas sem exceções. Já é um pouco mais curto que o código original:
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 ?
}Uma maneira mais agradável de descompactar o resultado é usar ligações estruturadas em C ++ 17. Eles nos permitirão obter o resultado com uma única linha de código:
auto [result, shaderModule2] = device.createShaderModule({...} /* createInfo temporary */ );Finalmente, o último exemplo de código está usando exceções e transformação de valor de retorno. Este é o modo padrão da API.
vk::ShaderModule shader1;
vk::ShaderModule shader2;
try
{
shader1 = device. createShaderModule ({...});
shader2 = device. createShaderModule ({...});
}
catch (std:: exception const &e)
{
// handle error and free resources
}Importante
O Vulkan lida no vk -Namespace não suporta RAII; portanto, você precisa limpar seus recursos no manipulador de erros! Em vez disso, você pode usar as classes Wrapper no vk::raii -Namespace.
Com C ++ 17 e acima, algumas funções são atribuídas a [[nodiscard]] , resultando em um aviso se você não usar o valor de retorno de forma alguma. Você pode desligar esses avisos definindo VULKAN_HPP_NO_NODISCARD_WARNINGS .
Para a transformação do valor de retorno, há uma classe especial de valores de retorno que requerem manuseio especial: enumerações. Para enumerações, você geralmente precisa escrever código como este:
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);Desde que escrever esse loop repetidamente é tedioso e os erros propensam a ligação C ++ cuida da enumeração para que você possa apenas escrever:
std::vector<LayerProperties> properties = physicalDevice.enumerateDeviceLayerProperties(); Vulkan-HPP fornece uma interface vk::UniqueHandle<Type, Deleter> . Para cada tipo de alça vulkan vk::Type existe um identificador exclusivo vk::UniqueType , que excluirá o recurso vulkan subjacente após a destruição, por exemplo, vk::UniqueBuffer é o identificador exclusivo para vk::Buffer .
Para cada função que constrói um cabo Vulkan do tipo vk::Type Vulkan-HPP fornece uma segunda versão que retorna um vk::UniqueType . Por exemplo, para vk::Device::createBuffer existe vk::Device::createBufferUnique e para vk::allocateCommandBuffers existe vk::allocateCommandBuffersUnique .
Observe que o uso vk::UniqueHandle tem um custo, pois a maioria dos deleteres precisa armazenar o vk::AllocationCallbacks e o identificador dos pais usados para construção, porque são necessários para a destruição automática.
Vulkan-HPP fornece uma interface vk::SharedHandle<Type> . Para cada tipo de alça vulkan vk::Type existe um identificador compartilhado vk::SharedType que excluirá o recurso vulkan subjacente após a destruição, por exemplo, vk::SharedBuffer é o identificador compartilhado para vk::Buffer .
Diferentemente vk::UniqueHandle , vk::SharedHandle assume a propriedade compartilhada do recurso e de seus pais. Isso significa que o identificador pai não será destruído até que todos os recursos da criança sejam excluídos. Isso é útil para recursos compartilhados entre vários threads ou objetos.
Esse mecanismo garante uma ordem de destruição correta, mesmo que o pai vk::SharedHandle seja destruído antes do manuseio da criança. Caso contrário, o identificador se comporta como std::shared_ptr . vk::SharedInstance ou qualquer um de seu objeto filho deve ser o último para excluir (primeiro criado, primeiro declaração de classe).
Ainda não há funções que retornem um vk::SharedHandle ainda. Em vez disso, você pode construir um vk::SharedHandle a partir de um vk::Handle :
vk::Buffer buffer = device.createBuffer(...);
vk::SharedBuffer sharedBuffer (buffer, device); // sharedBuffer now owns the buffer Existem várias especializações de vk::SharedHandle para diferentes tipos de identificação. Por exemplo, vk::SharedImage pode levar um argumento adicional para especificar se a imagem é de propriedade do Swapchain:
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 Há também uma especialização para vk::SwapchainKHR que leva um argumento adicional para especificar uma superfície:
vk::SwapchainKHR swapchain = device.createSwapchainKHR(...);
vk::SharedSwapchainKHR sharedSwapchain (swapchain, device, surface); // sharedSwapchain now owns the swapchain and surface Você pode criar uma sobrecarga vk::SharedHandle para o seu próprio tipo de alça ou alças compartilhadas, fornecendo vários argumentos de modelo à SharedHandleBase :
Com isso, forneça uma função de destruição estática personalizada internalDestroy , que abre uma alça pai e uma alça para destruir. Não se esqueça de adicionar uma declaração de amigo para a classe base.
// 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);
}
};A API será estendida para fornecer funções de criação no futuro.
Além de vk::UniqueHandles e vk::SharedHandles , há um conjunto de classes de wrapper para todos os tipos de identificação que seguem o RAII-Paradigm (aquisição de recursos é inicialização), fornecida no espaço para nome vk::raii .
Enquanto um vk::UniqueHandle imita uma alça embrulhada por um std::unique_ptr , e um vk::SharedHandle imita uma alça embrulhada por um std::shared_ptr , incluindo informações dos pais, um vk::raii::Handle é apenas uma classe que adquire o destaque em vk. Assim, você é livre para usá -los como valores ou envolvê -los com um ponteiro inteligente.
Além das vk::Handles , todas essas classes de wrapper precisam de contribuir dados adicionais e, portanto, não são binários idênticos aos vulkan C-Handles.
Como os vk::UniqueHandles e os vk::SharedHandles usam o mesmo despachante que o vk::Handles , eles podem ser facilmente misturados e combinados. Os vk::raii::Handles usam alguns despachantes ligeiramente diferentes e, portanto, não são compatíveis com as outras alças! Ou seja, para os vk-Handles , o vk::UniqueHandles e o vk::SharedHandles , você precisa instanciar um despachante global, conforme descrito em https://github.com/khronosgroup/vulkan-hpp#extensions-per-device-punction-pinter-pinters. Para as vk::raii-Handles , isso não é necessário, pois eles mantêm seus próprios despachantes. A grande vantagem aqui é quando você tem vários dispositivos: as funções chamadas através das vk::raii-Handles sempre chamam as funções específicas do dispositivo.
Às vezes, é necessário usar std::vector com alocadores personalizados. O Vulkan-HPP suporta vetores com alocadores personalizados como entrada para vk::ArrayProxy e para funções que retornam um vetor. Para este último caso, adicione seu alocador personalizado favorito como argumento de modelo à chamada de função assim:
std::vector<LayerProperties, MyCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties<MyCustomAllocator>(); Você também pode usar um alocador personalizado com estado, fornecendo -o como um argumento a essas funções. Infelizmente, para deixar os compiladores felizes, você também precisa definir explicitamente o argumento de despacho. Para obter o padrão lá, um {} simples seria suficiente:
MyStatefulCustomAllocator allocator;
std::vector<LayerProperties, MyStatefulCustomAllocator> properties = physicalDevice.enumerateDeviceLayerProperties(allocator, {}); Em todo vulkan.hpp , há algumas chamadas para uma função assert. Ao definir VULKAN_HPP_ASSERT , você pode especificar sua própria função de afirmação personalizada a ser chamada.
Por padrão, VULKAN_HPP_ASSERT_ON_RESULT será usado para verificar os resultados quando VULKAN_HPP_NO_EXCEPTIONS for definido. Se você deseja lidar com erros sozinho, pode desativar/personalizá -lo como VULKAN_HPP_ASSERT .
Existem algumas afirmações estáticas para cada classe de identificação e cada estrutura no arquivo vulkan_static_assertions.hpp . Você pode incluir esse arquivo em pelo menos um de seus arquivos de origem. Ao definir VULKAN_HPP_STATIC_ASSERT , você pode especificar sua própria afirmação estática personalizada a ser usada para esses casos. Ou seja, definindo -o para ser um pouco, você pode reduzir um pouco o tempo de compilação.
O carregador Vulkan expõe apenas as funções do vulkan e um número limitado de extensões. Para usar o Vulkan-HPP com extensões, é necessário ter uma biblioteca que forneça stubs a todas as funções vulkan usadas ou para dizer a Vulkan-HPP para despachar esses ponteiros de funções. O Vulkan-HPP fornece um mecanismo de despacho por função, aceitando uma classe de despacho como último parâmetro em cada chamada de função. A classe de despacho deve fornecer um tipo chamável para cada função vulkan usada. O Vulkan-HPP fornece uma implementação, DispatchLoaderDynamic , que busca todos os ponteiros de função conhecidos pela biblioteca.
// 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); Para usar o vk::DispatchLoaderDynamic como o despachante padrão (significa: você não precisa adicioná -lo explicitamente a todas as chamadas de funções), você precisa #define VULKAN_HPP_DISPATCH_LOADER_DYNAMIC 1 e ter o Macro vulkan_hpp_default_dispation_dynamic 1 e ter o Macro VULKAN_HPP_DEFAULT_DISPATCH_LOADER_DYNAMIC_STORAGE para que o Speater_Dynic_Storming exatamente no seu Speater_dathert_dystert. Em seguida, você pode usá -lo pelo macro VULKAN_HPP_DEFAULT_DISPATCHER , como é mostrado nos trechos de código abaixo. Criar um vk::DispatchLoaderDynamic completo é um processo de duas a três etapas, onde você tem três opções para a primeira etapa:
vk::DynamicLoader : VULKAN_HPP_DEFAULT_DISPATCHER.init();getProcAddress (compare com vk::DynamicLoader em vulkan.hpp ): YourDynamicLoader ydl;
VULKAN_HPP_DEFAULT_DISPATCHER.init(ydl);Observação
Você precisa manter o objeto dinâmico do carregador dinâmico até depois da última chamada para uma função vulkan em seu programa. Por exemplo, tornando -o estático ou armazenando globalmente.
PFN_vkGetInstanceProcAddr : PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr = your_own_function_pointer_getter();
VULKAN_HPP_DEFAULT_DISPATCHER.init(vkGetInstanceProcAddr);vk::Instance para obter todas as outras dicas de função: vk::Instance instance = vk::createInstance({}, nullptr );
VULKAN_HPP_DEFAULT_DISPATCHER.init(instance);vk::Device para obter ponteiros de função específicos do dispositivo std::vector<vk::PhysicalDevice> physicalDevices = instance.enumeratePhysicalDevices();
assert (!physicalDevices.empty());
vk::Device device = physicalDevices[ 0 ].createDevice({}, nullptr );
VULKAN_HPP_DEFAULT_DISPATCHER.init(device);Após o segundo passo acima, o despachante está totalmente funcional. Adicionar a terceira etapa pode resultar em código mais eficiente. Mas se você pretende usar vários dispositivos, poderá omitir a terceira etapa e deixar o driver fazer a disputa de dispositivo.
Em alguns casos, o armazenamento para o DispatchLoaderDynamic deve ser incorporado em uma DLL. Para esses casos, você precisa definir VULKAN_HPP_STORAGE_SHARED para dizer a Vulkan-HPP que o armazenamento reside em uma DLL. Ao compilar a DLL com o armazenamento, também é necessário definir VULKAN_HPP_STORAGE_SHARED_EXPORT para exportar os símbolos necessários.
Para todas as funções, esse VULKAN_HPP_DEFAULT_DISPATCHER é o padrão para o último argumento para essa função. Se você deseja fornecer explicitamente o despachante para cada chamada de função (quando você tem vários despachantes para diferentes dispositivos, por exemplo) e deseja ter certeza de que não perde acidentalmente nenhuma chamada de função, pode definir VULKAN_HPP_NO_DEFAULT_DISPATCHER antes de incluir vulkan.hpp para remover esse argumento default.
vulkan.hpp fornece algumas características de tipo, o modelo de alcance metaprograma:
template <typename EnumType, EnumType value> struct CppType Maps IndexType Valores ( IndexType::eUint16 , IndexType::eUint32 , ...) para o tipo correspondente ( uint16_t , uint32_t , ...) pelo Type de membro; MAPS ObjectType Valores ( ObjectType::eInstance , ObjectType::eDevice , ...) para o tipo correspondente ( vk::Instance , vk::Device , ...) pelo Type de membro; DebugReportObjectTypeEXT::eInstance DebugReportObjectType DebugReportObjectTypeEXT::eDevice vk::Instance vk::Device Typetemplate <typename T> struct IndexTypeValue Tipos escalares ( uint16_t , uint32_t , ...) para o valor correspondente IndexType ( IndexType::eUint16 , IndexType::eUint32 , ...).template <typename T> struct isVulkanHandleType mapeia um tipo para true se e somente se for uma classe de identificação ( vk::Instance , vk::Device , ...) pelo value estático do membro.HandleClass::CType mapeia uma classe de identificação ( vk::Instance , vk::Device , ...) para o tipo c correspondente ( VkInstance , VkDevice , ...) pelo tipo de membro CType .HandleClass::objectType mapeia uma classe de identificação ( vk::Instance , vk::Device , ...) para o correspondente ObjectType Value ( ObjectType::eInstance , ObjectType::eDevice , ...) pelo membro estático objectType .HandleClass::debugReportObjectType mapeia uma classe de identificação ( vk::Instance , vk::Device , ...) para o correspondente DebugReportObjectTypeEXT Valor ( DebugReportObjectTypeEXT::eInstance , DebugReportObjectTypeEXT::eDevice , ...) Por debugReportObjectType Com o cabeçalho adicional vulkan_format_traits.hpp , são fornecidas algumas funções de característica no vk::Format . Com o C ++ 14 e acima, todas essas funções são marcadas como constexpr , ou seja, com argumentos apropriados, eles são resolvidos no momento da compilação.
uin8_t blockSize( vk::Format format ); Obtém o tamanho do bloco Texel deste formato em bytes.uint8_t texelsPerBlock( vk::Format format ); Obtém o número de Texels em um bloco Texel.std::array<uint8_t, 3> blockExtent( vk::Format format ); Obtém a extensão tridimensional dos blocos de Texel.char const * compressionScheme( vk::Format format ); Obtém uma descrição textual do esquema de compactação deste formato, ou um texto vazio, se não for comprimido.bool isCompressed( vk::Format format ); É verdade que se o formato for um formato compactado, caso contrário, falsa.uint8_t packed( vk::Format format ); Obtém o número de bits nos quais o formato está embalado. Um único elemento de imagem neste formato pode ser armazenado no mesmo espaço que um tipo escalar dessa largura de bits.uint8_t componentCount( vk::Format format ); Obtém o número de componentes deste formato.bool componentsAreCompressed( vk::Format format ); É verdade que se os componentes deste formato forem compactados, caso contrário, falsos.uint8_t componentBits( vk::Format format, uint8_t component ); Obtém o número de bits neste componente, se não for compactado, caso contrário 0.char const * componentName( vk::Format format, uint8_t component ); Obtém o nome deste componente como uma corda C.char const * componentNumericFormat( vk::Format format, uint8_t component ); Obtém o formato numérico deste componente como uma cordão C.uint8_t componentPlaneIndex( vk::Format format, uint8_t component ); Obtém o índice de avião, este componente está.uint8_t planeCount( vk::Format format ); Obtém o número de planos de imagem desse formato.vk::Format planeCompatibleFormat( vk::Format format, uint8_t plane ); Obtém um formato de plano único compatível com este plano.uint8_t planeHeightDivisor( vk::Format format, uint8_t plane ); Recebe a altura relativa deste plano. Um valor de k significa que este plano é 1/k a altura do formato geral.uint8_t planeWidthDivisor( vk::Format format, uint8_t plane ); Recebe a largura relativa deste plano. Um valor de k significa que este plano é 1/k a largura do formato geral. Com o cabeçalho adicional vulkan_hash.hpp , você recebe especializações de std::hash para as classes de wrapper Handle e, com C ++ 14, para os invólucros da estrutura. Com VULKAN_HPP_HASH_COMBINE , você pode definir seu próprio algoritmo de combinação de hash para os elementos da estrutura.
Com o cabeçalho adicional vulkan_extension_inspection.hpp , são fornecidas algumas funções para inspecionar extensões. Com o C ++ 20 e acima, algumas dessas funções são marcadas como constexpr , ou seja, com argumentos apropriados, eles são resolvidos no momento da compilação. Cada extensão é identificada por uma string segurando seu nome. Observe que existe uma definição com esse nome para cada extensão. Algumas funções podem fornecer informações que dependem da versão Vulkan. Como todas as funções aqui funcionam apenas em cordas, as versões Vulkan são codificadas por uma string que começa com "vk_version_", seguida pela versão major e a menor, separada por um Undersore, assim: "vk_version_1_0".
std::set<std::string> const & getDeviceExtensions(); Obtém todas as extensões de dispositivo especificadas para a plataforma atual. Observe que nem todos eles podem ser suportados pelos dispositivos reais.std::set<std::string> const & getInstanceExtensions(); Obtém todas as extensões de instância especificadas para a plataforma atual. Observe que nem todos eles podem ser suportados pelas instâncias reais.std::map<std::string, std::string> const & getDeprecatedExtensions(); Obtém um mapa de todas as extensões depreciadas para a extensão ou versão vulkan que deve substituir essa funcionalidade.std::map<std::string, std::vector<std::vector<std::string>>> const & getExtensionDepends( std::string const & extension ); Algumas extensões dependem de outras extensões. Que dependências podem diferir para diferentes versões vulkan, e pode haver diferentes conjuntos de dependências para a mesma versão Vulkan. Esta função obtém um vetor de vetores de extensões por versão Vulkan da qual a extensão fornecida depende.std::pair<bool, std::vector<std::vector<std::string>> const &> getExtensionDepends( std::string const & version, std::string const & extension ); O first membro do std::pair devolvido é verdadeiro, se a extensão fornecida for especificada para a versão vulkan fornecida, caso contrário, false . O second membro do std::pair devolvido é um vetor de vetores de extensões, listando os conjuntos separados de extensões da qual a extensão fornecida depende da versão vulkan dada.std::map<std::string, std::string> const & getObsoletedExtensions(); Obtém um mapa de todas as extensões obsoletas da extensão ou da versão Vulkan que obsoletou essa extensão.std::map<std::string, std::string> const & getPromotedExtensions(); Obtém um mapa de todas as extensões que foram promovidas a outra extensão ou a uma versão Vulkan para essa extensão da versão Vulkan.VULKAN_HPP_CONSTEXPR_20 std::string getExtensionDeprecatedBy( std::string const & extension ); Obtém a extensão ou a versão vulkan A extensão fornecida é descontinuada por.VULKAN_HPP_CONSTEXPR_20 std::string getExtensionObsoletedBy( std::string const & extension ); Obtém a extensão ou a versão vulkan que a extensão fornecida é obsoleta por.VULKAN_HPP_CONSTEXPR_20 std::string getExtensionPromotedTo( std::string const & extension ); Obtém a extensão ou a versão vulkan a que a extensão fornecida é promovida.VULKAN_HPP_CONSTEXPR_20 bool isDeprecatedExtension( std::string const & extension ); Retorna true se a extensão fornecida for descontinuada por alguma outra extensão ou versão vulkan.VULKAN_HPP_CONSTEXPR_20 bool isDeviceExtension( std::string const & extension ); Retorna true se a extensão fornecida for uma extensão do dispositivo.VULKAN_HPP_CONSTEXPR_20 bool isInstanceExtension( std::string const & extension ); Retorna true se a extensão fornecida for uma extensão de instância.VULKAN_HPP_CONSTEXPR_20 bool isObsoletedExtension( std::string const & extension ); Retorna true se a extensão fornecida for obsoleta por alguma outra versão de extensão ou vulkan.VULKAN_HPP_CONSTEXPR_20 bool isPromotedExtension( std::string const & extension ); Retorna true se a extensão fornecida for promovida a alguma outra extensão ou versão vulkan.Aviso
A versão atual do Microsoft Visual Studio 2022 não pode lidar com o módulo Vulkan.cppm. Um bug é arquivado (https://develoCommunity.visualstudio.com/t/on-building-a-c20-module:-fatal-error/10469799 #nd10485943). Você pode pelo menos usar esse recurso se não precisar ou quiser usar vk::UniqueHandle ou vk::SharedHandle , definindo VULKAN_HPP_NO_SMART_HANDLE .
Vulkan-HPP fornece um módulo C ++ chamado, vulkan_hpp em vulkan.cppm . Os módulos C ++ destinam -se a substituir os arquivos de cabeçalho. Os módulos têm potencial para melhorar drasticamente os tempos de compilação para grandes projetos, pois declarações e definições podem ser facilmente compartilhadas entre as unidades de tradução sem analisar repetidamente cabeçalhos. O vulkan-hpp possui alguns cabeçalhos extremamente longos (por exemplo, vulkan_structs.hpp ), e o módulo C ++ provavelmente reduzirá os tempos de compilação para projetos atualmente usando-o.
Este recurso requer um compilador recente com suporte completo de C ++ 20:
cl.exe 19.28 ou posterior)Se você pretende usar o suporte ao módulo C ++ da CMake (e possivelmente ninja), são necessárias ferramentas mais recentes:
cl.exe 19.34 ou posterior)Aviso
O módulo vulkan-hpp c ++ ainda é experimental. Algumas maneiras sugeridas de usá -lo em seus projetos estão abaixo. 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 . Por exemplo:
# 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.
Licenciado sob a licença Apache, versão 2.0 (a "licença"); Você não pode usar esse arquivo, exceto em conformidade com a licença. Você pode obter uma cópia da licença em
http://www.apache.org/licenses/LICENSE-2.0
A menos que exigido pela lei aplicável ou acordada por escrito, o software distribuído pela licença é distribuído "como está", sem garantias ou condições de qualquer tipo, expressa ou implícita. Consulte a licença para o idioma específico que rege as permissões e limitações sob a licença.