Program Listing for File vulkan-create-info-modifier.h
↰ Return to documentation for file (include\utility\vulkan-create-info-modifier.h
)
/******************************************************************************
(C) Intel Corporation.
This software and the related documents are Intel copyrighted materials,
and your use of them is governed by the express license under which they
were provided to you ("License"). Unless the License provides otherwise,
you may not use, modify, copy, publish, distribute, disclose or transmit
this software or the related documents without Intel's prior written
permission.
This software and the related documents are provided as is, with no express
or implied warranties, other than those that are expressly stated in the
License.
******************************************************************************/
#pragma once
#include "igpa-config.h"
#include "utility/assert.h"
#include "gvk-environment.hpp"
#include "gvk-string.hpp"
#include <map>
#include <set>
#include <string>
#include <vector>
namespace gpa {
namespace utility {
namespace vulkan {
namespace detail {
template<typename VkCreateInfoStructureType>
class LayerExtensionCollectionModifier
{
public:
inline LayerExtensionCollectionModifier() = default;
inline virtual ~LayerExtensionCollectionModifier() = 0;
inline const std::set<std::string>& GetAvailableLayers() const
{
return mAvailableLayers;
}
inline const std::set<std::string>& GetAvailableExtensions() const
{
return mAvailableExtensions;
}
inline const std::vector<const char*>& GetEnabledLayers() const
{
return mEnabledLayers;
}
inline const std::vector<const char*>& GetEnabledExtensions() const
{
return mEnabledExtensions;
}
inline void SetCreateInfo(VkCreateInfoStructureType* pCreateInfo, bool autoRevert = true)
{
AutoRevert();
mCreateInfo = pCreateInfo;
mAutoRevert = autoRevert;
mStashedCreateInfo = {};
if (mCreateInfo) {
mStashedCreateInfo = *mCreateInfo;
PopulateEntries(mCreateInfo->enabledLayerCount, mCreateInfo->ppEnabledLayerNames, mEnabledLayers);
PopulateEntries(mCreateInfo->enabledExtensionCount, mCreateInfo->ppEnabledExtensionNames, mEnabledExtensions);
ApplyCustomEntries();
}
}
inline bool ApplyCustomLayer(const char* layerName)
{
return ApplyCustomEntry(layerName, mAvailableLayers, mEnabledLayers);
}
inline bool ApplyCustomExtension(const char* extensionName)
{
return ApplyCustomEntry(extensionName, mAvailableExtensions, mEnabledExtensions);
}
inline void Validate()
{
ValidateEntries(mAvailableLayers, mEnabledLayers);
ValidateEntries(mAvailableExtensions, mEnabledExtensions);
ApplyCustomEntries();
}
inline void Revert()
{
if (mCreateInfo) {
*mCreateInfo = mStashedCreateInfo;
}
}
inline void Clear()
{
AutoRevert();
mAvailableLayers = {};
mEnabledLayers = {};
mAvailableExtensions = {};
mEnabledExtensions = {};
mStashedCreateInfo = {};
mCreateInfo = nullptr;
mAutoRevert = false;
}
protected:
inline void PopulateEntries(uint32_t enabledEntryCount, const char* const* ppEnabledEntryNames, std::vector<const char*>& enabledEntries)
{
if (enabledEntryCount && ppEnabledEntryNames) {
enabledEntries.assign(ppEnabledEntryNames, ppEnabledEntryNames + enabledEntryCount);
}
}
inline bool ApplyCustomEntry(const char* entryName, const std::set<std::string>& availableEntries, std::vector<const char*>& enabledEntries)
{
if (entryName && mCreateInfo) {
if (availableEntries.find(entryName) != availableEntries.end()) {
enabledEntries.push_back(entryName);
ApplyCustomEntries();
return true;
}
}
return false;
}
inline void ApplyCustomEntries()
{
if (mCreateInfo) {
mCreateInfo->enabledLayerCount = (uint32_t)mEnabledLayers.size();
mCreateInfo->ppEnabledLayerNames = mEnabledLayers.empty() ? nullptr : mEnabledLayers.data();
mCreateInfo->enabledExtensionCount = (uint32_t)mEnabledExtensions.size();
mCreateInfo->ppEnabledExtensionNames = mEnabledExtensions.empty() ? nullptr : mEnabledExtensions.data();
}
}
inline void ValidateEntries(const std::set<std::string>& availableEntries, std::vector<const char*>& enabledEntries)
{
for (auto itr = enabledEntries.begin(); itr != enabledEntries.end();) {
if (availableEntries.find(*itr) == availableEntries.end()) {
itr = enabledEntries.erase(itr);
} else {
++itr;
}
}
}
inline void AutoRevert()
{
if (mAutoRevert) {
Revert();
}
}
std::set<std::string> mAvailableLayers;
std::vector<const char*> mEnabledLayers;
std::set<std::string> mAvailableExtensions;
std::vector<const char*> mEnabledExtensions;
VkCreateInfoStructureType mStashedCreateInfo{};
VkCreateInfoStructureType* mCreateInfo{nullptr};
bool mAutoRevert{false};
LayerExtensionCollectionModifier(const LayerExtensionCollectionModifier&) = delete;
LayerExtensionCollectionModifier& operator=(const LayerExtensionCollectionModifier&) = delete;
LayerExtensionCollectionModifier(LayerExtensionCollectionModifier&&) = delete;
LayerExtensionCollectionModifier& operator=(LayerExtensionCollectionModifier&&) = delete;
};
template<typename VkCreateInfoStructureType>
inline LayerExtensionCollectionModifier<VkCreateInfoStructureType>::~LayerExtensionCollectionModifier()
{
AutoRevert();
}
} // namespace detail
class InstanceCreateInfoModifier final
: public detail::LayerExtensionCollectionModifier<VkInstanceCreateInfo>
{
public:
inline void EnumerateLayersAndExtensions(PFN_vkEnumerateInstanceLayerProperties enumerateInstanceLayerProperties, PFN_vkEnumerateInstanceExtensionProperties enumerateInstanceExtensionProperties)
{
mAvailableLayers.clear();
if (enumerateInstanceLayerProperties) {
uint32_t propertyCount = 0;
enumerateInstanceLayerProperties(&propertyCount, nullptr);
std::vector<VkLayerProperties> layerProperties(propertyCount);
enumerateInstanceLayerProperties(&propertyCount, layerProperties.data());
for (const auto& layerProperty : layerProperties) {
mAvailableLayers.insert(layerProperty.layerName);
}
}
mAvailableExtensions.clear();
if (enumerateInstanceExtensionProperties) {
auto populateAvailableExtensions =
[&](const char* pLayerName) {
uint32_t propertyCount = 0;
enumerateInstanceExtensionProperties(pLayerName, &propertyCount, nullptr);
std::vector<VkExtensionProperties> extensionProperties(propertyCount);
enumerateInstanceExtensionProperties(pLayerName, &propertyCount, extensionProperties.data());
for (const auto& extensionProperty : extensionProperties) {
mAvailableExtensions.insert(extensionProperty.extensionName);
}
};
populateAvailableExtensions(nullptr);
for (const auto& availableLayer : mAvailableLayers) {
populateAvailableExtensions(availableLayer.c_str());
}
}
}
inline static void RemoveVkStateTrackerCreateInfo(VkInstanceCreateInfo* pInstanceCreateInfo)
{
// TODO : Replace with generic remove_pnext(VkStructureType)
auto pApplicationInfo = pInstanceCreateInfo ? pInstanceCreateInfo->pApplicationInfo : nullptr;
auto pPrevious = (VkBaseInStructure*)pApplicationInfo;
auto pNext = (VkBaseInStructure*)(pApplicationInfo ? pApplicationInfo->pNext : nullptr);
while (pNext) {
if (pNext->sType == VK_STRUCTURE_TYPE_APPLICATION_INFO) {
pPrevious->pNext = nullptr;
break;
}
pPrevious = pNext;
pNext = (VkBaseInStructure*)pNext->pNext;
}
}
};
class DeviceCreateInfoModifier final
: public detail::LayerExtensionCollectionModifier<VkDeviceCreateInfo>
{
public:
inline void EnumerateExtensions(uint32_t enabledLayerCount, const char* const* ppEnabledLayerNames, VkPhysicalDevice vkPhysicalDevice, PFN_vkEnumerateDeviceExtensionProperties enumerateDeviceExtensionProperties)
{
mAvailableExtensions.clear();
if (enumerateDeviceExtensionProperties) {
auto populateAvailableExtensions =
[&](const char* pLayerName) {
uint32_t propertyCount = 0;
enumerateDeviceExtensionProperties(vkPhysicalDevice, pLayerName, &propertyCount, nullptr);
std::vector<VkExtensionProperties> extensionProperties(propertyCount);
enumerateDeviceExtensionProperties(vkPhysicalDevice, pLayerName, &propertyCount, extensionProperties.data());
for (const auto& extensionProperty : extensionProperties) {
mAvailableExtensions.insert(extensionProperty.extensionName);
}
};
populateAvailableExtensions(nullptr);
if (enabledLayerCount && ppEnabledLayerNames) {
for (uint32_t i = 0; i < enabledLayerCount; ++i) {
populateAvailableExtensions(ppEnabledLayerNames[i]);
}
}
}
}
};
class NamedEntryCollection final
{
public:
inline std::set<std::string> Validate(uint32_t layerPropertyCount, VkLayerProperties const* pLayerProperties)
{
std::set<std::string> availableEntries;
for (uint32_t i = 0; i < layerPropertyCount; ++i) {
availableEntries.insert(pLayerProperties[i].layerName);
}
return Validate(availableEntries);
}
inline std::set<std::string> Validate(uint32_t extensionPropertyCount, VkExtensionProperties const* pExtensionProperties)
{
std::set<std::string> availableEntries;
for (uint32_t i = 0; i < extensionPropertyCount; ++i) {
availableEntries.insert(pExtensionProperties[i].extensionName);
}
return Validate(availableEntries);
}
inline void Add(const char* pEntry, bool force = false)
{
GPA_ASSERT(pEntry);
if (force) {
Erase(pEntry);
}
if (mEntryIndices.insert({pEntry, (uint32_t)mEntries.size()}).second) {
mEntries.push_back(pEntry);
}
}
inline void Add(uint32_t entryCount, const char* const* pEntries, bool force = false)
{
if (pEntries) {
for (uint32_t i = 0; i < entryCount; ++i) {
Add(pEntries[i], force);
}
}
}
inline void Erase(const char* pEntry)
{
if (pEntry) {
auto itr = mEntryIndices.find(pEntry);
if (itr != mEntryIndices.end()) {
auto index = itr->second;
GPA_ASSERT(index < mEntries.size());
GPA_ASSERT(mEntries[index]);
GPA_ASSERT(!strcmp(mEntries[index], pEntry));
mEntryIndices.erase(itr);
mEntries.erase(mEntries.begin() + index);
for (; index < mEntries.size(); ++index) {
itr = mEntryIndices.find(mEntries[index]);
GPA_ASSERT(itr != mEntryIndices.end());
itr->second = index;
}
}
}
}
inline bool Contains(const char* pEntry) const
{
return pEntry ? mEntryIndices.count(pEntry) : 0;
}
inline void Clear()
{
mEntryIndices.clear();
mEntries.clear();
}
inline uint32_t Count() const
{
return (uint32_t)mEntries.size();
}
inline const char* const* Data() const
{
return !mEntries.empty() ? mEntries.data() : nullptr;
}
private:
inline std::set<std::string> Validate(std::set<std::string> const& availableEntries)
{
std::set<std::string> invalidEntries;
for (uint32_t i = 0; i < mEntries.size();) {
GPA_ASSERT(mEntries[i]);
if (!availableEntries.count(mEntries[i])) {
invalidEntries.insert(mEntries[i]);
Erase(mEntries[i]);
} else {
++i;
}
}
return invalidEntries;
}
std::map<std::string, uint32_t> mEntryIndices;
std::vector<char const*> mEntries;
};
using LayerCollection = NamedEntryCollection;
using ExtensionCollection = NamedEntryCollection;
inline std::vector<VkLayerProperties> GetInstanceLayerProperties(PFN_vkEnumerateInstanceLayerProperties pfnEnumerateInstanceLayerProperties)
{
GPA_ASSERT(pfnEnumerateInstanceLayerProperties);
uint32_t propertyCount = 0;
auto vkResult = pfnEnumerateInstanceLayerProperties(&propertyCount, nullptr);
(void)vkResult;
GPA_ASSERT(vkResult == VK_SUCCESS);
std::vector<VkLayerProperties> properties(propertyCount);
vkResult = pfnEnumerateInstanceLayerProperties(&propertyCount, properties.data());
GPA_ASSERT(vkResult == VK_SUCCESS);
return properties;
}
inline std::vector<VkExtensionProperties> GetInstanceExtensionProperties(PFN_vkEnumerateInstanceExtensionProperties pfnEnumerateInstanceExtensionProperties)
{
GPA_ASSERT(pfnEnumerateInstanceExtensionProperties);
uint32_t propertyCount = 0;
auto vkResult = pfnEnumerateInstanceExtensionProperties(nullptr, &propertyCount, nullptr);
(void)vkResult;
GPA_ASSERT(vkResult == VK_SUCCESS);
std::vector<VkExtensionProperties> properties(propertyCount);
vkResult = pfnEnumerateInstanceExtensionProperties(nullptr, &propertyCount, properties.data());
GPA_ASSERT(vkResult == VK_SUCCESS);
return properties;
}
inline std::vector<VkExtensionProperties> GetDeviceExtensionProperties(VkPhysicalDevice physicalDevice, PFN_vkEnumerateDeviceExtensionProperties pfnEnumerateDeviceExtensionProperties)
{
GPA_ASSERT(pfnEnumerateDeviceExtensionProperties);
uint32_t propertyCount = 0;
auto vkResult = pfnEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &propertyCount, nullptr);
(void)vkResult;
GPA_ASSERT(vkResult == VK_SUCCESS);
std::vector<VkExtensionProperties> properties(propertyCount);
vkResult = pfnEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &propertyCount, properties.data());
GPA_ASSERT(vkResult == VK_SUCCESS);
return properties;
}
inline std::set<std::string> RemoveLayerEnvVarValues(const std::string& key, const std::set<std::string>& layerValuesToRemove)
{
#if VK_USE_PLATFORM_WIN32_KHR
auto delimiter = ";";
#else
auto delimiter = ":";
#endif
std::string value;
std::set<std::string> removedLayerValues;
for (const auto& layer : gvk::string::split(gvk::get_env_var(key), delimiter)) {
if (layerValuesToRemove.count(layer)) {
removedLayerValues.insert(layer);
} else {
value += layer + delimiter;
}
}
gvk::set_env_var(key, value);
return removedLayerValues;
}
inline std::set<std::string> RemoveApiDumpAndValidationLayersFromEnvironment()
{
std::set<std::string> layerValuesToRemove{"VK_LAYER_LUNARG_api_dump", "api_dump", "VK_LAYER_KHRONOS_validation", "validation"};
auto instanceLayers = RemoveLayerEnvVarValues("VK_INSTANCE_LAYERS", layerValuesToRemove);
auto loaderLayers = RemoveLayerEnvVarValues("VK_LOADER_LAYERS_ENABLE", layerValuesToRemove);
instanceLayers.insert(loaderLayers.begin(), loaderLayers.end());
return instanceLayers;
}
inline const std::vector<std::string>& GetValidationLayerSettingNames()
{
static const std::vector<std::string> sValidationLayerSettingNames{
/* BOOL : true */ "VK_LAYER_FINE_GRAINED_LOCKING",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_VALIDATE_CORE",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_CHECK_IMAGE_LAYOUT",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_CHECK_COMMAND_BUFFER",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_CHECK_OBJECT_IN_USE",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_CHECK_QUERY",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_CHECK_SHADERS",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_CHECK_SHADERS_CACHING",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_UNIQUE_HANDLES",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_OBJECT_LIFETIME",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_STATELESS_PARAM",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_THREAD_SAFETY",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_VALIDATE_SYNC",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_SYNC_QUEUE_SUBMIT",
/* ENUM : GPU_BASED_NONE */ // "VK_KHRONOS_VALIDATION_VALIDATE_GPU_BASED",
/* BOOL : true */ // "VK_KHRONOS_VALIDATION_PRINTF_TO_STDOUT",
/* BOOL : false */ // "VK_KHRONOS_VALIDATION_PRINTF_VERBOSE",
/* INT : 1024 */ // "VK_KHRONOS_VALIDATION_PRINTF_BUFFER_SIZE",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_RESERVE_BINDING_SLOT",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_VMA_LINEAR_OUTPUT",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_GPUAV_DESCRIPTOR_CHECKS",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_WARN_ON_ROBUST_OOB",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_VALIDATE_INDIRECT_BUFFER",
/* BOOL : true */ "VK_KHRONOS_VALIDATION_USE_INSTRUMENTED_SHADER_CACHE",
/* BOOL : false */ // "VK_KHRONOS_VALIDATION_SELECT_INSTRUMENTED_SHADERS",
/* INT : 10000 */ // "VK_KHRONOS_VALIDATION_GPUAV_MAX_BUFFER_DEVICE_ADDRESSES",
/* BOOL : false */ // "VK_KHRONOS_VALIDATION_VALIDATE_BEST_PRACTICES",
/* BOOL : false */ // "VK_KHRONOS_VALIDATION_VALIDATE_BEST_PRACTICES_ARM",
/* BOOL : false */ // "VK_KHRONOS_VALIDATION_VALIDATE_BEST_PRACTICES_AMD",
/* BOOL : false */ // "VK_KHRONOS_VALIDATION_VALIDATE_BEST_PRACTICES_IMG",
/* BOOL : false */ // "VK_KHRONOS_VALIDATION_VALIDATE_BEST_PRACTICES_NVIDIA",
/* FLAGS : VK_DBG_LAYER_ACTION_LOG_MSG */ // "VK_KHRONOS_VALIDATION_DEBUG_ACTION",
/* SAVE_FILE : stdout */ // "VK_KHRONOS_VALIDATION_LOG_FILENAME",
/* FLAGS : error */ // "VK_KHRONOS_VALIDATION_REPORT_FLAGS",
/* BOOL : true */ // "VK_KHRONOS_VALIDATION_ENABLE_MESSAGE_LIMIT",
/* INT : 10 */ // "VK_LAYER_DUPLICATE_MESSAGE_LIMIT",
/* LIST : */ // "VK_LAYER_MESSAGE_ID_FILTER",
/* FLAGS : VK_VALIDATION_FEATURE_DISABLE_THREAD_SAFETY_EXT */ // "VK_LAYER_DISABLES",
/* FLAGS : */ // "VK_LAYER_ENABLES",
};
return sValidationLayerSettingNames;
}
} // namespace vulkan
} // namespace utility
} // namespace gpa