mirror of https://github.com/mosra/magnum.git
15 changed files with 1524 additions and 9 deletions
@ -0,0 +1,49 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "Arguments.h" |
||||||
|
|
||||||
|
#include <Corrade/Utility/Arguments.h> |
||||||
|
|
||||||
|
namespace Magnum { namespace Vk { namespace Implementation { |
||||||
|
|
||||||
|
Utility::Arguments arguments() { |
||||||
|
Utility::Arguments args{"magnum"}; |
||||||
|
args.addOption("disable-layers").setHelp("disable-layers", "Vulkan layers to disable", "LIST") |
||||||
|
.addOption("disable-extensions").setHelp("disable-extensions", "Vulkan extensions to disable", "LIST") |
||||||
|
.addOption("enable-layers").setHelp("enable-layers", "Vulkan layers to enable in addition to the defaults and what the application requests", "LIST") |
||||||
|
.addOption("enable-instance-extensions").setHelp("enable-instance-extensions", "Vulkan instance extensions to enable in addition to the defaults and what the application requests", "LIST") |
||||||
|
.addOption("vulkan-version").setHelp("vulkan-version", "force Vulkan version", "X.Y") |
||||||
|
.addOption("log", "default").setHelp("log", "console logging", "default|quiet|verbose") |
||||||
|
.setFromEnvironment("disable-layers") |
||||||
|
.setFromEnvironment("disable-extensions") |
||||||
|
.setFromEnvironment("enable-layers") |
||||||
|
.setFromEnvironment("enable-instance-extensions") |
||||||
|
.setFromEnvironment("vulkan-version") |
||||||
|
.setFromEnvironment("log"); |
||||||
|
return args; |
||||||
|
} |
||||||
|
|
||||||
|
}}} |
||||||
@ -0,0 +1,40 @@ |
|||||||
|
#ifndef Magnum_Vk_Implementation_Arguments_h |
||||||
|
#define Magnum_Vk_Implementation_Arguments_h |
||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <Corrade/Utility/Utility.h> |
||||||
|
|
||||||
|
#include "Magnum/Magnum.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace Vk { namespace Implementation { |
||||||
|
|
||||||
|
/* Used by both InstanceCreateInfo and DeviceCreateInfo, each takes a subset
|
||||||
|
of the arguments */ |
||||||
|
Utility::Arguments arguments(); |
||||||
|
|
||||||
|
}}} |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,32 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "InstanceState.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace Vk { namespace Implementation { |
||||||
|
|
||||||
|
InstanceState::InstanceState(Instance&, Int argc, const char** argv): argc{argc}, argv{argv} {} |
||||||
|
|
||||||
|
}}} |
||||||
@ -0,0 +1,42 @@ |
|||||||
|
#ifndef Magnum_Vk_Implementation_InstanceState_h |
||||||
|
#define Magnum_Vk_Implementation_InstanceState_h |
||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "Magnum/Vk/Vk.h" |
||||||
|
#include "Magnum/Vk/Vulkan.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace Vk { namespace Implementation { |
||||||
|
|
||||||
|
struct InstanceState { |
||||||
|
explicit InstanceState(Instance& instance, Int argc, const char** argv); |
||||||
|
|
||||||
|
Int argc; |
||||||
|
const char** argv; |
||||||
|
}; |
||||||
|
|
||||||
|
}}} |
||||||
|
|
||||||
|
#endif |
||||||
@ -0,0 +1,348 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include "Instance.h" |
||||||
|
|
||||||
|
#include <algorithm> |
||||||
|
#include <Corrade/Containers/GrowableArray.h> |
||||||
|
#include <Corrade/Containers/String.h> |
||||||
|
#include <Corrade/Containers/StringView.h> |
||||||
|
#include <Corrade/Utility/Arguments.h> |
||||||
|
|
||||||
|
#include "Magnum/Vk/Extensions.h" |
||||||
|
#include "Magnum/Vk/Handle.h" |
||||||
|
#include "Magnum/Vk/Result.h" |
||||||
|
#include "Magnum/Vk/Version.h" |
||||||
|
#include "Magnum/Vk/Implementation/Arguments.h" |
||||||
|
#include "Magnum/Vk/Implementation/InstanceState.h" |
||||||
|
#include "MagnumExternal/Vulkan/flextVkGlobal.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace Vk { |
||||||
|
|
||||||
|
struct InstanceCreateInfo::State { |
||||||
|
Containers::String applicationName; |
||||||
|
Containers::Array<Containers::String> ownedStrings; |
||||||
|
Containers::Array<const char*> layers; |
||||||
|
Containers::Array<const char*> extensions; |
||||||
|
|
||||||
|
Containers::String disabledLayersStorage, disabledExtensionsStorage; |
||||||
|
Containers::Array<Containers::StringView> disabledLayers, disabledExtensions; |
||||||
|
bool quietLog = false; |
||||||
|
Version version = Version::None; |
||||||
|
Int argc; |
||||||
|
const char** argv; |
||||||
|
}; |
||||||
|
|
||||||
|
InstanceCreateInfo::InstanceCreateInfo(const Int argc, const char** const argv, const LayerProperties* const layerProperties, const InstanceExtensionProperties* const extensionProperties, const Flags flags): _info{}, _applicationInfo{} { |
||||||
|
Utility::Arguments args = Implementation::arguments(); |
||||||
|
args.parse(argc, argv); |
||||||
|
|
||||||
|
if(args.value("log") == "quiet") |
||||||
|
_state.emplace().quietLog = true; |
||||||
|
if(argc && argv) { |
||||||
|
if(!_state) _state.emplace(); |
||||||
|
_state->argc = argc; |
||||||
|
_state->argv = argv; |
||||||
|
} |
||||||
|
|
||||||
|
_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO; |
||||||
|
/** @todo filter out magnum-specific flags once there are any */ |
||||||
|
_info.flags = VkInstanceCreateFlags(flags); |
||||||
|
_info.pApplicationInfo = &_applicationInfo; |
||||||
|
_applicationInfo.pEngineName = "Magnum"; |
||||||
|
/** @todo magnum version? 2020 can't fit into Vulkan's version
|
||||||
|
representation, sigh */ |
||||||
|
|
||||||
|
/* If there's a forced Vulkan version, use that, otherwise use the reported
|
||||||
|
instance version */ |
||||||
|
Containers::StringView version = args.value<Containers::StringView>("vulkan-version"); |
||||||
|
if(!version.isEmpty()) { |
||||||
|
if(!_state) _state.emplace(); |
||||||
|
|
||||||
|
if((_state->version = args.value<Version>("vulkan-version")) == Version::None) |
||||||
|
Warning{} << "Invalid --magnum-vulkan-version" << args.value<Containers::StringView>("vulkan-version") << Debug::nospace << ", ignoring"; |
||||||
|
} |
||||||
|
if(_state && _state->version == Version::None) |
||||||
|
_state->version = enumerateInstanceVersion(); |
||||||
|
_applicationInfo.apiVersion = UnsignedInt(_state ? _state->version : enumerateInstanceVersion()); |
||||||
|
|
||||||
|
/* If there are any disabled layers or extensions, sort them and save for
|
||||||
|
later -- we'll use them to filter the ones added by the app */ |
||||||
|
Containers::String disabledLayers = args.value<Containers::String>("disable-layers"); |
||||||
|
Containers::String disabledExtensions = args.value<Containers::String>("disable-extensions"); |
||||||
|
if(!disabledLayers.isEmpty()) { |
||||||
|
if(!_state) _state.emplace(); |
||||||
|
|
||||||
|
_state->disabledLayersStorage = std::move(disabledLayers); |
||||||
|
_state->disabledLayers = Containers::StringView{_state->disabledLayersStorage}.splitWithoutEmptyParts(); |
||||||
|
std::sort(_state->disabledLayers.begin(), _state->disabledLayers.end()); |
||||||
|
} |
||||||
|
if(!disabledExtensions.isEmpty()) { |
||||||
|
if(!_state) _state.emplace(); |
||||||
|
|
||||||
|
_state->disabledExtensionsStorage = std::move(disabledExtensions); |
||||||
|
_state->disabledExtensions = Containers::StringView{_state->disabledExtensionsStorage}.splitWithoutEmptyParts(); |
||||||
|
std::sort(_state->disabledExtensions.begin(), _state->disabledExtensions.end()); |
||||||
|
} |
||||||
|
|
||||||
|
/* Add all layers and extensions enabled on command-line. The blacklist is
|
||||||
|
applied on those as well. */ |
||||||
|
/** @todo use a generator split() so we can avoid the growing allocation
|
||||||
|
of the output array */ |
||||||
|
/** @todo unfortunately even though the split and value retrieval is mostly
|
||||||
|
allocation-free, the strings will be turned into owning copies because |
||||||
|
none of them is null-terminated or global -- could be a better idea to |
||||||
|
just grow one giant string internally (once we have growable strings) */ |
||||||
|
addEnabledLayers(args.value<Containers::StringView>("enable-layers").splitWithoutEmptyParts()); |
||||||
|
addEnabledExtensions(args.value<Containers::StringView>("enable-instance-extensions").splitWithoutEmptyParts()); |
||||||
|
|
||||||
|
/** @todo use this (enabling debug layers etc.) */ |
||||||
|
static_cast<void>(layerProperties); |
||||||
|
static_cast<void>(extensionProperties); |
||||||
|
} |
||||||
|
|
||||||
|
InstanceCreateInfo::InstanceCreateInfo(NoInitT) noexcept {} |
||||||
|
|
||||||
|
InstanceCreateInfo::InstanceCreateInfo(const VkInstanceCreateInfo& info): _info{info} {} |
||||||
|
|
||||||
|
InstanceCreateInfo::~InstanceCreateInfo() = default; |
||||||
|
|
||||||
|
InstanceCreateInfo& InstanceCreateInfo::setApplicationInfo(const Containers::StringView name, const Version version) { |
||||||
|
/* Keep an owned copy of the name if it's not global / null-terminated;
|
||||||
|
Use nullptr if the view is empty */ |
||||||
|
if(!name.isEmpty()) { |
||||||
|
if(!_state) _state.emplace(); |
||||||
|
|
||||||
|
_state->applicationName = Containers::String::nullTerminatedGlobalView(name); |
||||||
|
_applicationInfo.pApplicationName = _state->applicationName.data(); |
||||||
|
} else { |
||||||
|
if(_state) _state->applicationName = nullptr; |
||||||
|
_applicationInfo.pApplicationName = nullptr; |
||||||
|
} |
||||||
|
|
||||||
|
_applicationInfo.applicationVersion = UnsignedInt(version); |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
InstanceCreateInfo& InstanceCreateInfo::addEnabledLayers(const Containers::ArrayView<const Containers::StringView> layers) { |
||||||
|
if(layers.empty()) return *this; |
||||||
|
if(!_state) _state.emplace(); |
||||||
|
|
||||||
|
/* Add null-terminated strings to the layer array */ |
||||||
|
arrayReserve(_state->layers, _state->layers.size() + layers.size()); |
||||||
|
for(const Containers::StringView layer: layers) { |
||||||
|
/* If the layer is blacklisted, skip it */ |
||||||
|
if(std::binary_search(_state->disabledLayers.begin(), _state->disabledLayers.end(), layer)) continue; |
||||||
|
|
||||||
|
/* Keep an owned *allocated* copy of the string if it's not global or
|
||||||
|
null-terminated -- ideally, if people use string view literals, |
||||||
|
those will be, so this won't allocate. Allocated so the pointers |
||||||
|
don't get invalidated when the array gets reallocated. */ |
||||||
|
const char* data; |
||||||
|
if(!(layer.flags() >= (Containers::StringViewFlag::NullTerminated|Containers::StringViewFlag::Global))) |
||||||
|
data = arrayAppend(_state->ownedStrings, Containers::InPlaceInit, |
||||||
|
Containers::AllocatedInit, layer).data(); |
||||||
|
else data = layer.data(); |
||||||
|
|
||||||
|
arrayAppend(_state->layers, data); |
||||||
|
} |
||||||
|
|
||||||
|
/* Update the layer count, re-route the pointer to the layers array in case
|
||||||
|
it got reallocated */ |
||||||
|
_info.enabledLayerCount = _state->layers.size(); |
||||||
|
_info.ppEnabledLayerNames = _state->layers.data(); |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
InstanceCreateInfo& InstanceCreateInfo::addEnabledLayers(const std::initializer_list<Containers::StringView> layers) { |
||||||
|
return addEnabledLayers(Containers::arrayView(layers)); |
||||||
|
} |
||||||
|
|
||||||
|
InstanceCreateInfo& InstanceCreateInfo::addEnabledExtensions(const Containers::ArrayView<const Containers::StringView> extensions) { |
||||||
|
if(extensions.empty()) return *this; |
||||||
|
if(!_state) _state.emplace(); |
||||||
|
|
||||||
|
/* Add null-terminated strings to the extension array */ |
||||||
|
arrayReserve(_state->extensions, _state->extensions.size() + extensions.size()); |
||||||
|
for(const Containers::StringView extension: extensions) { |
||||||
|
/* If the extension is blacklisted, skip it */ |
||||||
|
if(std::binary_search(_state->disabledExtensions.begin(), _state->disabledExtensions.end(), extension)) continue; |
||||||
|
|
||||||
|
/* Keep an owned *allocated* copy of the string if it's not global or
|
||||||
|
null-terminated -- ideally, if people use string view literals, |
||||||
|
those will be, so this won't allocate. Allocated so the pointers |
||||||
|
don't get invalidated when the array gets reallocated. */ |
||||||
|
const char* data; |
||||||
|
if(!(extension.flags() >= (Containers::StringViewFlag::NullTerminated|Containers::StringViewFlag::Global))) |
||||||
|
data = arrayAppend(_state->ownedStrings, Containers::InPlaceInit, |
||||||
|
Containers::AllocatedInit, extension).data(); |
||||||
|
else data = extension.data(); |
||||||
|
|
||||||
|
arrayAppend(_state->extensions, data); |
||||||
|
} |
||||||
|
|
||||||
|
/* Update the extension count, re-route the pointer to the layers array in
|
||||||
|
case it got reallocated */ |
||||||
|
_info.enabledExtensionCount = _state->extensions.size(); |
||||||
|
_info.ppEnabledExtensionNames = _state->extensions.data(); |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
InstanceCreateInfo& InstanceCreateInfo::addEnabledExtensions(const std::initializer_list<Containers::StringView> extensions) { |
||||||
|
return addEnabledExtensions(Containers::arrayView(extensions)); |
||||||
|
} |
||||||
|
|
||||||
|
InstanceCreateInfo& InstanceCreateInfo::addEnabledExtensions(const Containers::ArrayView<const InstanceExtension> extensions) { |
||||||
|
if(extensions.empty()) return *this; |
||||||
|
if(!_state) _state.emplace(); |
||||||
|
|
||||||
|
arrayReserve(_state->extensions, _state->extensions.size() + extensions.size()); |
||||||
|
for(const InstanceExtension& extension: extensions) { |
||||||
|
/* If the extension is blacklisted, skip it */ |
||||||
|
if(std::binary_search(_state->disabledExtensions.begin(), _state->disabledExtensions.end(), extension.string())) continue; |
||||||
|
|
||||||
|
arrayAppend(_state->extensions, extension.string().data()); |
||||||
|
} |
||||||
|
|
||||||
|
/* Update the extension count, re-route the pointer to the layers array in
|
||||||
|
case it got reallocated */ |
||||||
|
_info.enabledExtensionCount = _state->extensions.size(); |
||||||
|
_info.ppEnabledExtensionNames = _state->extensions.data(); |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
InstanceCreateInfo& InstanceCreateInfo::addEnabledExtensions(const std::initializer_list<InstanceExtension> extensions) { |
||||||
|
return addEnabledExtensions(Containers::arrayView(extensions)); |
||||||
|
} |
||||||
|
|
||||||
|
Instance Instance::wrap(const VkInstance handle, const Version version, const Containers::ArrayView<const Containers::StringView> enabledExtensions, const HandleFlags flags) { |
||||||
|
/* Compared to the constructor nothing is printed here as it would be just
|
||||||
|
repeating what was passed to the constructor */ |
||||||
|
Instance out{NoCreate}; |
||||||
|
out._handle = handle; |
||||||
|
out._flags = flags; |
||||||
|
out.initializeExtensions(enabledExtensions); |
||||||
|
out.initialize(version, 0, nullptr); |
||||||
|
return out; |
||||||
|
} |
||||||
|
|
||||||
|
Instance Instance::wrap(const VkInstance handle, const Version version, const std::initializer_list<Containers::StringView> enabledExtensions, const HandleFlags flags) { |
||||||
|
return wrap(handle, version, Containers::arrayView(enabledExtensions), flags); |
||||||
|
} |
||||||
|
|
||||||
|
Instance::Instance(const InstanceCreateInfo& info): _flags{HandleFlag::DestroyOnDestruction} { |
||||||
|
const Version version = info._state && info._state->version != Version::None ? info._state->version : enumerateInstanceVersion(); |
||||||
|
|
||||||
|
/* Print all enabled layers and extensions if we're not told to be quiet */ |
||||||
|
if(!info._state || !info._state->quietLog) { |
||||||
|
Debug{} << "Instance version:" << version; |
||||||
|
|
||||||
|
if(info->enabledLayerCount) { |
||||||
|
Debug{} << "Enabled layers:"; |
||||||
|
for(std::size_t i = 0, max = info->enabledLayerCount; i != max; ++i) |
||||||
|
Debug{} << " " << info->ppEnabledLayerNames[i]; |
||||||
|
} |
||||||
|
|
||||||
|
if(info->enabledExtensionCount) { |
||||||
|
Debug{} << "Enabled instance extensions:"; |
||||||
|
for(std::size_t i = 0, max = info->enabledExtensionCount; i != max; ++i) |
||||||
|
Debug{} << " " << info->ppEnabledExtensionNames[i]; |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
MAGNUM_VK_INTERNAL_ASSERT_RESULT(vkCreateInstance(info, nullptr, &_handle)); |
||||||
|
|
||||||
|
initializeExtensions<const char*>({info->ppEnabledExtensionNames, info->enabledExtensionCount}); |
||||||
|
if(info._state) |
||||||
|
initialize(version, info._state->argc, info._state->argv); |
||||||
|
else |
||||||
|
initialize(version, 0, nullptr); |
||||||
|
} |
||||||
|
|
||||||
|
Instance::Instance(NoCreateT): _handle{}, _functionPointers{} {} |
||||||
|
|
||||||
|
Instance::Instance(Instance&& other) noexcept: _handle{other._handle}, _flags{other._flags}, _version{other._version}, _extensionStatus{other._extensionStatus}, _state{std::move(other._state)}, _functionPointers{other._functionPointers} { |
||||||
|
other._handle = nullptr; |
||||||
|
other._functionPointers = {}; |
||||||
|
} |
||||||
|
|
||||||
|
Instance::~Instance() { |
||||||
|
if(_handle && (_flags & HandleFlag::DestroyOnDestruction)) |
||||||
|
_functionPointers.DestroyInstance(_handle, nullptr); |
||||||
|
} |
||||||
|
|
||||||
|
Instance& Instance::operator=(Instance&& other) noexcept { |
||||||
|
using std::swap; |
||||||
|
swap(other._handle, _handle); |
||||||
|
swap(other._flags, _flags); |
||||||
|
swap(other._version, _version); |
||||||
|
swap(other._extensionStatus, _extensionStatus); |
||||||
|
swap(other._state, _state); |
||||||
|
swap(other._functionPointers, _functionPointers); |
||||||
|
return *this; |
||||||
|
} |
||||||
|
|
||||||
|
template<class T> void Instance::initializeExtensions(const Containers::ArrayView<const T> enabledExtensions) { |
||||||
|
/* Mark all known extensions as enabled */ |
||||||
|
for(const T extension: enabledExtensions) { |
||||||
|
for(Containers::ArrayView<const InstanceExtension> knownExtensions: { |
||||||
|
InstanceExtension::extensions(Version::None), |
||||||
|
/*InstanceExtension::extensions(Version::Vk10), is empty */ |
||||||
|
InstanceExtension::extensions(Version::Vk11), |
||||||
|
/*InstanceExtension::extensions(Version::Vk12) is empty */ |
||||||
|
}) { |
||||||
|
auto found = std::lower_bound(knownExtensions.begin(), knownExtensions.end(), extension, [](const InstanceExtension& a, const T& b) { |
||||||
|
return a.string() < static_cast<const Containers::StringView&>(b); |
||||||
|
}); |
||||||
|
if(found->string() != extension) continue; |
||||||
|
_extensionStatus.set(found->index(), true); |
||||||
|
} |
||||||
|
} |
||||||
|
} |
||||||
|
|
||||||
|
void Instance::initialize(const Version version, const Int argc, const char** const argv) { |
||||||
|
/* Init version, function pointers */ |
||||||
|
_version = version; |
||||||
|
flextVkInitInstance(_handle, &_functionPointers); |
||||||
|
|
||||||
|
/* Set up extension-dependent functionality */ |
||||||
|
_state.emplace(*this, argc, argv); |
||||||
|
} |
||||||
|
|
||||||
|
VkInstance Instance::release() { |
||||||
|
const VkInstance handle = _handle; |
||||||
|
_handle = nullptr; |
||||||
|
return handle; |
||||||
|
} |
||||||
|
|
||||||
|
bool Instance::isExtensionEnabled(const InstanceExtension& extension) const { |
||||||
|
return _extensionStatus[extension.index()]; |
||||||
|
} |
||||||
|
|
||||||
|
void Instance::populateGlobalFunctionPointers() { |
||||||
|
flextVkInstance = _functionPointers; |
||||||
|
} |
||||||
|
|
||||||
|
}} |
||||||
@ -0,0 +1,93 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <new> |
||||||
|
#include <Corrade/TestSuite/Tester.h> |
||||||
|
|
||||||
|
#include "Magnum/Vk/Instance.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace Vk { namespace Test { namespace { |
||||||
|
|
||||||
|
struct InstanceTest: TestSuite::Tester { |
||||||
|
explicit InstanceTest(); |
||||||
|
|
||||||
|
void createInfoConstructNoInit(); |
||||||
|
void createInfoConstructFromVk(); |
||||||
|
|
||||||
|
void constructNoCreate(); |
||||||
|
void constructCopy(); |
||||||
|
}; |
||||||
|
|
||||||
|
InstanceTest::InstanceTest() { |
||||||
|
addTests({&InstanceTest::createInfoConstructNoInit, |
||||||
|
&InstanceTest::createInfoConstructFromVk, |
||||||
|
|
||||||
|
&InstanceTest::constructNoCreate, |
||||||
|
&InstanceTest::constructCopy}); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceTest::createInfoConstructNoInit() { |
||||||
|
InstanceCreateInfo info; |
||||||
|
info->sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; |
||||||
|
new(&info) InstanceCreateInfo{NoInit}; |
||||||
|
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2); |
||||||
|
|
||||||
|
CORRADE_VERIFY((std::is_nothrow_constructible<InstanceCreateInfo, NoInitT>::value)); |
||||||
|
|
||||||
|
/* Implicit construction is not allowed */ |
||||||
|
CORRADE_VERIFY(!(std::is_convertible<NoInitT, InstanceCreateInfo>::value)); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceTest::createInfoConstructFromVk() { |
||||||
|
VkInstanceCreateInfo vkInfo; |
||||||
|
vkInfo.sType = VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2; |
||||||
|
|
||||||
|
InstanceCreateInfo info{vkInfo}; |
||||||
|
CORRADE_COMPARE(info->sType, VK_STRUCTURE_TYPE_FORMAT_PROPERTIES_2); |
||||||
|
|
||||||
|
/* Implicit construction is not allowed */ |
||||||
|
CORRADE_VERIFY(!(std::is_convertible<VkInstanceCreateInfo, InstanceCreateInfo>::value)); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceTest::constructNoCreate() { |
||||||
|
{ |
||||||
|
Instance instance{NoCreate}; |
||||||
|
CORRADE_VERIFY(!instance.handle()); |
||||||
|
/* Instance function pointers should be null */ |
||||||
|
CORRADE_VERIFY(!instance->CreateDevice); |
||||||
|
} |
||||||
|
|
||||||
|
/* Implicit construction is not allowed */ |
||||||
|
CORRADE_VERIFY(!(std::is_convertible<NoCreateT, Instance>::value)); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceTest::constructCopy() { |
||||||
|
CORRADE_VERIFY(!(std::is_constructible<Instance, const Instance&>{})); |
||||||
|
CORRADE_VERIFY(!(std::is_assignable<Instance, const Instance&>{})); |
||||||
|
} |
||||||
|
|
||||||
|
}}}} |
||||||
|
|
||||||
|
CORRADE_TEST_MAIN(Magnum::Vk::Test::InstanceTest) |
||||||
@ -0,0 +1,508 @@ |
|||||||
|
/*
|
||||||
|
This file is part of Magnum. |
||||||
|
|
||||||
|
Copyright © 2010, 2011, 2012, 2013, 2014, 2015, 2016, 2017, 2018, 2019, |
||||||
|
2020 Vladimír Vondruš <mosra@centrum.cz> |
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a |
||||||
|
copy of this software and associated documentation files (the "Software"), |
||||||
|
to deal in the Software without restriction, including without limitation |
||||||
|
the rights to use, copy, modify, merge, publish, distribute, sublicense, |
||||||
|
and/or sell copies of the Software, and to permit persons to whom the |
||||||
|
Software is furnished to do so, subject to the following conditions: |
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included |
||||||
|
in all copies or substantial portions of the Software. |
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
||||||
|
THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
||||||
|
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
||||||
|
DEALINGS IN THE SOFTWARE. |
||||||
|
*/ |
||||||
|
|
||||||
|
#include <sstream> |
||||||
|
#include <Corrade/Containers/StringStl.h> |
||||||
|
#include <Corrade/TestSuite/Tester.h> |
||||||
|
#include <Corrade/TestSuite/Compare/Numeric.h> |
||||||
|
#include <Corrade/Utility/DebugStl.h> |
||||||
|
#include <Corrade/Utility/FormatStl.h> |
||||||
|
|
||||||
|
#include "Magnum/Vk/Extensions.h" |
||||||
|
#include "Magnum/Vk/ExtensionProperties.h" |
||||||
|
#include "Magnum/Vk/Handle.h" |
||||||
|
#include "Magnum/Vk/LayerProperties.h" |
||||||
|
#include "Magnum/Vk/Instance.h" |
||||||
|
#include "Magnum/Vk/Result.h" |
||||||
|
#include "Magnum/Vk/Version.h" |
||||||
|
|
||||||
|
#include "MagnumExternal/Vulkan/flextVkGlobal.h" |
||||||
|
|
||||||
|
namespace Magnum { namespace Vk { namespace Test { namespace { |
||||||
|
|
||||||
|
struct InstanceVkTest: TestSuite::Tester { |
||||||
|
explicit InstanceVkTest(); |
||||||
|
|
||||||
|
void createInfoConstructDefault(); |
||||||
|
void createInfoApplicationInfo(); |
||||||
|
void createInfoLayers(); |
||||||
|
void createInfoExtensions(); |
||||||
|
void createInfoCopiedStrings(); |
||||||
|
|
||||||
|
void construct(); |
||||||
|
void constructLayerExtension(); |
||||||
|
void constructCommandLineDisable(); |
||||||
|
void constructCommandLineEnable(); |
||||||
|
void constructMove(); |
||||||
|
void constructUnknownLayer(); |
||||||
|
void constructUnknownExtension(); |
||||||
|
void wrap(); |
||||||
|
void populateGlobalFunctionPointers(); |
||||||
|
}; |
||||||
|
|
||||||
|
struct { |
||||||
|
const char* nameDisable; |
||||||
|
const char* nameEnable; |
||||||
|
Containers::Array<const char*> argsDisable, argsEnable; |
||||||
|
bool driverVersionSupported, debugReportEnabled, validationFeaturesEnabled; |
||||||
|
const char* log; |
||||||
|
} ConstructCommandLineData[] { |
||||||
|
/* Shouldn't print anything about version, enabled layers/exts if quiet
|
||||||
|
output is enabled. */ |
||||||
|
{"quiet", "quiet, enabled layer + both extensions", |
||||||
|
Containers::array({"", "--magnum-log", "quiet"}), |
||||||
|
Containers::array({"", "--magnum-log", "quiet", |
||||||
|
"--magnum-enable-layers", "VK_LAYER_KHRONOS_validation", |
||||||
|
"--magnum-enable-instance-extensions", "VK_EXT_debug_report VK_EXT_validation_features"}), |
||||||
|
true, true, true, |
||||||
|
""}, |
||||||
|
{"", "enabled layer + both extensions", nullptr, |
||||||
|
Containers::array({"", |
||||||
|
"--magnum-enable-layers", "VK_LAYER_KHRONOS_validation", |
||||||
|
"--magnum-enable-instance-extensions", "VK_EXT_debug_report VK_EXT_validation_features"}), |
||||||
|
true, true, true, |
||||||
|
"Instance version: Vulkan {}.{}{}\n" |
||||||
|
"Enabled layers:\n" |
||||||
|
" VK_LAYER_KHRONOS_validation\n" |
||||||
|
"Enabled instance extensions:\n" |
||||||
|
" VK_EXT_debug_report\n" |
||||||
|
" VK_EXT_validation_features\n"}, |
||||||
|
{"forced invalid version", "forced invalid version, enabled layer + both extensions", |
||||||
|
Containers::array({"", "--magnum-vulkan-version", "eh"}), |
||||||
|
Containers::array({"", "--magnum-vulkan-version", "eh", |
||||||
|
"--magnum-enable-layers", "VK_LAYER_KHRONOS_validation", |
||||||
|
"--magnum-enable-instance-extensions", "VK_EXT_debug_report VK_EXT_validation_features"}), |
||||||
|
true, true, true, |
||||||
|
"Invalid --magnum-vulkan-version eh, ignoring\n" |
||||||
|
"Instance version: Vulkan {}.{}{}\n" |
||||||
|
"Enabled layers:\n" |
||||||
|
" VK_LAYER_KHRONOS_validation\n" |
||||||
|
"Enabled instance extensions:\n" |
||||||
|
" VK_EXT_debug_report\n" |
||||||
|
" VK_EXT_validation_features\n"}, |
||||||
|
{"forced version", "forced version, enabled layer + both extensions", |
||||||
|
Containers::array({"", "--magnum-vulkan-version", "1.0"}), |
||||||
|
Containers::array({"", "--magnum-vulkan-version", "1.0", |
||||||
|
"--magnum-enable-layers", "VK_LAYER_KHRONOS_validation", |
||||||
|
"--magnum-enable-instance-extensions", "VK_EXT_debug_report VK_EXT_validation_features"}), |
||||||
|
false, true, true, |
||||||
|
"Instance version: Vulkan 1.0\n" |
||||||
|
"Enabled layers:\n" |
||||||
|
" VK_LAYER_KHRONOS_validation\n" |
||||||
|
"Enabled instance extensions:\n" |
||||||
|
" VK_EXT_debug_report\n" |
||||||
|
" VK_EXT_validation_features\n"}, |
||||||
|
{"disabled layer + layer-only extension", "enabled extension", |
||||||
|
Containers::array({"", |
||||||
|
"--magnum-disable-layers", "VK_LAYER_KHRONOS_validation", |
||||||
|
"--magnum-disable-extensions", "VK_EXT_validation_features"}), |
||||||
|
Containers::array({"", |
||||||
|
"--magnum-enable-instance-extensions", "VK_EXT_debug_report"}), |
||||||
|
true, true, false, |
||||||
|
"Instance version: Vulkan {}.{}{}\n" |
||||||
|
"Enabled instance extensions:\n" |
||||||
|
" VK_EXT_debug_report\n"}, |
||||||
|
{"disabled extension", "enabled layer + one extension", |
||||||
|
Containers::array({"", |
||||||
|
"--magnum-disable-extensions", "VK_EXT_debug_report"}), |
||||||
|
Containers::array({"", |
||||||
|
"--magnum-enable-layers", "VK_LAYER_KHRONOS_validation", |
||||||
|
"--magnum-enable-instance-extensions", "VK_EXT_validation_features"}), |
||||||
|
true, false, true, |
||||||
|
"Instance version: Vulkan {}.{}{}\n" |
||||||
|
"Enabled layers:\n" |
||||||
|
" VK_LAYER_KHRONOS_validation\n" |
||||||
|
"Enabled instance extensions:\n" |
||||||
|
" VK_EXT_validation_features\n"}, |
||||||
|
{"disabled extensions + layer", "", |
||||||
|
Containers::array({"", |
||||||
|
"--magnum-disable-layers", "VK_LAYER_KHRONOS_validation", |
||||||
|
"--magnum-disable-extensions", "VK_EXT_debug_report VK_EXT_validation_features"}), |
||||||
|
nullptr, |
||||||
|
true, false, false, |
||||||
|
"Instance version: Vulkan {}.{}{}\n"}, |
||||||
|
}; |
||||||
|
|
||||||
|
InstanceVkTest::InstanceVkTest() { |
||||||
|
addTests({&InstanceVkTest::createInfoConstructDefault, |
||||||
|
&InstanceVkTest::createInfoApplicationInfo, |
||||||
|
&InstanceVkTest::createInfoLayers, |
||||||
|
&InstanceVkTest::createInfoExtensions, |
||||||
|
&InstanceVkTest::createInfoCopiedStrings, |
||||||
|
|
||||||
|
&InstanceVkTest::construct, |
||||||
|
&InstanceVkTest::constructLayerExtension}); |
||||||
|
|
||||||
|
addInstancedTests({&InstanceVkTest::constructCommandLineDisable, |
||||||
|
&InstanceVkTest::constructCommandLineEnable}, |
||||||
|
Containers::arraySize(ConstructCommandLineData)); |
||||||
|
|
||||||
|
addTests({&InstanceVkTest::constructMove, |
||||||
|
&InstanceVkTest::constructUnknownLayer, |
||||||
|
&InstanceVkTest::constructUnknownExtension, |
||||||
|
&InstanceVkTest::wrap, |
||||||
|
&InstanceVkTest::populateGlobalFunctionPointers}); |
||||||
|
} |
||||||
|
|
||||||
|
using namespace Containers::Literals; |
||||||
|
|
||||||
|
void InstanceVkTest::createInfoConstructDefault() { |
||||||
|
InstanceCreateInfo info; |
||||||
|
CORRADE_VERIFY(info->sType); |
||||||
|
CORRADE_VERIFY(!info->pNext); |
||||||
|
CORRADE_VERIFY(!info->ppEnabledLayerNames); |
||||||
|
CORRADE_COMPARE(info->enabledLayerCount, 0); |
||||||
|
CORRADE_VERIFY(!info->ppEnabledExtensionNames); |
||||||
|
CORRADE_COMPARE(info->enabledExtensionCount, 0); |
||||||
|
|
||||||
|
CORRADE_VERIFY(info->pApplicationInfo); |
||||||
|
CORRADE_COMPARE(Version(info->pApplicationInfo->apiVersion), enumerateInstanceVersion()); |
||||||
|
CORRADE_COMPARE(info->pApplicationInfo->applicationVersion, 0); |
||||||
|
CORRADE_COMPARE(info->pApplicationInfo->engineVersion, 0); |
||||||
|
CORRADE_COMPARE(info->pApplicationInfo->pEngineName, "Magnum"_s); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::createInfoApplicationInfo() { |
||||||
|
Containers::StringView name = "Magnum::Vk::Test::InstanceVkTest"_s; |
||||||
|
|
||||||
|
InstanceCreateInfo info; |
||||||
|
CORRADE_VERIFY(info->pApplicationInfo); |
||||||
|
CORRADE_VERIFY(!info->pApplicationInfo->pApplicationName); |
||||||
|
CORRADE_COMPARE(Version(info->pApplicationInfo->applicationVersion), Version{}); |
||||||
|
|
||||||
|
/* Setting an empty name should do nothing */ |
||||||
|
info.setApplicationInfo({}, {}); |
||||||
|
CORRADE_VERIFY(!info->pApplicationInfo->pApplicationName); |
||||||
|
CORRADE_COMPARE(Version(info->pApplicationInfo->applicationVersion), Version{}); |
||||||
|
|
||||||
|
info.setApplicationInfo(name, version(0, 0, 1)); |
||||||
|
/* The pointer should be to the global data */ |
||||||
|
CORRADE_COMPARE(static_cast<const void*>(info->pApplicationInfo->pApplicationName), name.data()); |
||||||
|
CORRADE_COMPARE(Version(info->pApplicationInfo->applicationVersion), version(0, 0, 1)); |
||||||
|
|
||||||
|
/* Setting an empty view should put nullptr back */ |
||||||
|
info.setApplicationInfo({}, {}); |
||||||
|
CORRADE_VERIFY(!info->pApplicationInfo->pApplicationName); |
||||||
|
CORRADE_COMPARE(Version(info->pApplicationInfo->applicationVersion), Version{}); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::createInfoLayers() { |
||||||
|
Containers::StringView layer = "VK_LAYER_KHRONOS_validation"_s; |
||||||
|
Containers::StringView another = "VK_LAYER_this_doesnt_exist"_s; |
||||||
|
|
||||||
|
InstanceCreateInfo info; |
||||||
|
CORRADE_VERIFY(!info->ppEnabledLayerNames); |
||||||
|
CORRADE_COMPARE(info->enabledLayerCount, 0); |
||||||
|
|
||||||
|
info.addEnabledLayers({layer}); |
||||||
|
CORRADE_VERIFY(info->ppEnabledLayerNames); |
||||||
|
CORRADE_COMPARE(info->enabledLayerCount, 1); |
||||||
|
/* The pointer should be to the global data */ |
||||||
|
CORRADE_COMPARE(static_cast<const void*>(info->ppEnabledLayerNames[0]), layer.data()); |
||||||
|
|
||||||
|
info.addEnabledLayers({another, layer}); |
||||||
|
CORRADE_COMPARE(info->enabledLayerCount, 3); |
||||||
|
/* The pointer should be to the global data */ |
||||||
|
CORRADE_COMPARE(static_cast<const void*>(info->ppEnabledLayerNames[0]), layer.data()); |
||||||
|
CORRADE_COMPARE(static_cast<const void*>(info->ppEnabledLayerNames[1]), another.data()); |
||||||
|
CORRADE_COMPARE(static_cast<const void*>(info->ppEnabledLayerNames[2]), layer.data()); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::createInfoExtensions() { |
||||||
|
InstanceCreateInfo info; |
||||||
|
CORRADE_VERIFY(!info->ppEnabledExtensionNames); |
||||||
|
CORRADE_COMPARE(info->enabledExtensionCount, 0); |
||||||
|
|
||||||
|
info.addEnabledExtensions<Extensions::KHR::external_fence_capabilities>(); |
||||||
|
CORRADE_VERIFY(info->ppEnabledExtensionNames); |
||||||
|
CORRADE_COMPARE(info->enabledExtensionCount, 1); |
||||||
|
/* The pointer should be to the global data */ |
||||||
|
CORRADE_COMPARE(static_cast<const void*>(info->ppEnabledExtensionNames[0]), |
||||||
|
Extensions::KHR::external_fence_capabilities::string().data()); |
||||||
|
|
||||||
|
info.addEnabledExtensions( |
||||||
|
{Extensions::KHR::external_semaphore_capabilities{}, |
||||||
|
Extensions::KHR::get_physical_device_properties2{}}); |
||||||
|
CORRADE_COMPARE(info->enabledExtensionCount, 3); |
||||||
|
/* The pointer should be to the global data */ |
||||||
|
CORRADE_COMPARE(static_cast<const void*>(info->ppEnabledExtensionNames[0]), |
||||||
|
Extensions::KHR::external_fence_capabilities::string().data()); |
||||||
|
CORRADE_COMPARE(static_cast<const void*>(info->ppEnabledExtensionNames[1]), |
||||||
|
Extensions::KHR::external_semaphore_capabilities::string().data()); |
||||||
|
CORRADE_COMPARE(static_cast<const void*>(info->ppEnabledExtensionNames[2]), |
||||||
|
Extensions::KHR::get_physical_device_properties2::string().data()); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::createInfoCopiedStrings() { |
||||||
|
Containers::StringView globalButNotNullTerminated = "VK_LAYER_KHRONOS_validation3"_s.except(1); |
||||||
|
Containers::String localButNullTerminated = Extensions::KHR::external_memory_capabilities::string(); |
||||||
|
|
||||||
|
InstanceCreateInfo info; |
||||||
|
info.setApplicationInfo(localButNullTerminated, {}) |
||||||
|
.addEnabledLayers({globalButNotNullTerminated}) |
||||||
|
.addEnabledExtensions({localButNullTerminated}); |
||||||
|
CORRADE_COMPARE(info->enabledLayerCount, 1); |
||||||
|
CORRADE_COMPARE(info->enabledExtensionCount, 1); |
||||||
|
|
||||||
|
CORRADE_COMPARE(info->pApplicationInfo->pApplicationName, localButNullTerminated); |
||||||
|
CORRADE_VERIFY(info->pApplicationInfo->pApplicationName != localButNullTerminated.data()); |
||||||
|
|
||||||
|
CORRADE_COMPARE(info->ppEnabledLayerNames[0], globalButNotNullTerminated); |
||||||
|
CORRADE_VERIFY(info->ppEnabledLayerNames[0] != globalButNotNullTerminated.data()); |
||||||
|
|
||||||
|
CORRADE_COMPARE(info->ppEnabledExtensionNames[0], localButNullTerminated); |
||||||
|
CORRADE_VERIFY(info->ppEnabledExtensionNames[0] != localButNullTerminated.data()); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::construct() { |
||||||
|
{ |
||||||
|
Instance instance; |
||||||
|
CORRADE_VERIFY(instance.handle()); |
||||||
|
/* Instance function pointers should be populated */ |
||||||
|
CORRADE_VERIFY(instance->CreateDevice); |
||||||
|
CORRADE_COMPARE(instance.handleFlags(), HandleFlag::DestroyOnDestruction); |
||||||
|
CORRADE_COMPARE(instance.version(), enumerateInstanceVersion()); |
||||||
|
/* Instance version is supported */ |
||||||
|
CORRADE_VERIFY(instance.isVersionSupported(enumerateInstanceVersion())); |
||||||
|
CORRADE_VERIFY(!instance.isVersionSupported(Version::None)); |
||||||
|
/* No extensions are enabled by default ... */ |
||||||
|
CORRADE_VERIFY(!instance.isExtensionEnabled<Extensions::EXT::debug_report>()); |
||||||
|
/* ... and thus also no function pointers loaded */ |
||||||
|
CORRADE_VERIFY(!instance->CreateDebugReportCallbackEXT); |
||||||
|
} |
||||||
|
|
||||||
|
/* Shouldn't crash or anything */ |
||||||
|
CORRADE_VERIFY(true); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::constructLayerExtension() { |
||||||
|
if(!enumerateLayerProperties().isSupported("VK_LAYER_KHRONOS_validation")) |
||||||
|
CORRADE_SKIP("VK_LAYER_KHRONOS_validation not supported, can't test"); |
||||||
|
if(!enumerateInstanceExtensionProperties({"VK_LAYER_KHRONOS_validation"}).isSupported<Extensions::EXT::debug_report>()) |
||||||
|
CORRADE_SKIP("VK_EXT_debug_report not supported, can't test"); |
||||||
|
|
||||||
|
Instance instance{InstanceCreateInfo{} |
||||||
|
.setApplicationInfo("InstanceVkTest", version(0, 0, 1)) |
||||||
|
.addEnabledLayers({"VK_LAYER_KHRONOS_validation"_s}) |
||||||
|
.addEnabledExtensions({ |
||||||
|
Extensions::EXT::debug_report::string(), |
||||||
|
"VK_EXT_validation_features"_s |
||||||
|
})}; |
||||||
|
CORRADE_VERIFY(instance.handle()); |
||||||
|
|
||||||
|
/* Extensions should be reported as enabled ... */ |
||||||
|
CORRADE_VERIFY(instance.isExtensionEnabled<Extensions::EXT::debug_report>()); |
||||||
|
CORRADE_VERIFY(instance.isExtensionEnabled(Extensions::EXT::validation_features{})); |
||||||
|
/* ... and function pointers loaded */ |
||||||
|
CORRADE_VERIFY(instance->CreateDebugReportCallbackEXT); |
||||||
|
/* no entrypoints to test for EXT_validation_features */ |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::constructCommandLineDisable() { |
||||||
|
auto&& data = ConstructCommandLineData[testCaseInstanceId()]; |
||||||
|
setTestCaseDescription(data.nameDisable); |
||||||
|
|
||||||
|
if(!enumerateLayerProperties().isSupported("VK_LAYER_KHRONOS_validation")) |
||||||
|
CORRADE_SKIP("VK_LAYER_KHRONOS_validation not supported, can't test"); |
||||||
|
if(!enumerateInstanceExtensionProperties({"VK_LAYER_KHRONOS_validation"}).isSupported<Extensions::EXT::validation_features>()) |
||||||
|
CORRADE_SKIP("VK_EXT_validation_features not supported, can't test"); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Warning redirectWarning{&out}; |
||||||
|
Debug redirectOutput{&out}; |
||||||
|
Instance instance{InstanceCreateInfo{Int(data.argsDisable.size()), data.argsDisable} |
||||||
|
.setApplicationInfo("InstanceVkTest", version(0, 0, 1)) |
||||||
|
.addEnabledLayers({"VK_LAYER_KHRONOS_validation"_s}) |
||||||
|
.addEnabledExtensions<Extensions::EXT::debug_report, |
||||||
|
Extensions::EXT::validation_features>()}; |
||||||
|
CORRADE_VERIFY(instance.handle()); |
||||||
|
CORRADE_COMPARE(instance.isVersionSupported(enumerateInstanceVersion()), data.driverVersionSupported); |
||||||
|
CORRADE_COMPARE(instance.isExtensionEnabled<Extensions::EXT::debug_report>(), data.debugReportEnabled); |
||||||
|
CORRADE_COMPARE(instance.isExtensionEnabled<Extensions::EXT::validation_features>(), data.validationFeaturesEnabled); |
||||||
|
|
||||||
|
/** @todo cleanup when Debug::toString() or some similar utility exists */ |
||||||
|
UnsignedInt major = versionMajor(enumerateInstanceVersion()); |
||||||
|
UnsignedInt minor = versionMinor(enumerateInstanceVersion()); |
||||||
|
UnsignedInt patch = versionPatch(enumerateInstanceVersion()); |
||||||
|
/* Vulkan 1.0 instances report no patch version, special-case that */ |
||||||
|
CORRADE_COMPARE(out.str(), Utility::formatString(data.log, major, minor, patch ? Utility::formatString(".{}", patch) : "")); |
||||||
|
|
||||||
|
/* Verify that the entrypoint is actually (not) loaded as expected, to
|
||||||
|
avoid all the above reporting being just smoke & mirrors */ |
||||||
|
CORRADE_COMPARE(!!instance->CreateDebugReportCallbackEXT, data.debugReportEnabled); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::constructCommandLineEnable() { |
||||||
|
auto&& data = ConstructCommandLineData[testCaseInstanceId()]; |
||||||
|
setTestCaseDescription(data.nameEnable); |
||||||
|
|
||||||
|
if(!enumerateLayerProperties().isSupported("VK_LAYER_KHRONOS_validation")) |
||||||
|
CORRADE_SKIP("VK_LAYER_KHRONOS_validation not supported, can't test"); |
||||||
|
if(!enumerateInstanceExtensionProperties({"VK_LAYER_KHRONOS_validation"}).isSupported<Extensions::EXT::validation_features>()) |
||||||
|
CORRADE_SKIP("VK_EXT_validation_features not supported, can't test"); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Warning redirectWarning{&out}; |
||||||
|
Debug redirectOutput{&out}; |
||||||
|
Instance instance{InstanceCreateInfo{Int(data.argsEnable.size()), data.argsEnable} |
||||||
|
/* Nothing enabled by the application */ |
||||||
|
}; |
||||||
|
CORRADE_VERIFY(instance.handle()); |
||||||
|
CORRADE_COMPARE(instance.isVersionSupported(enumerateInstanceVersion()), data.driverVersionSupported); |
||||||
|
CORRADE_COMPARE(instance.isExtensionEnabled<Extensions::EXT::debug_report>(), data.debugReportEnabled); |
||||||
|
CORRADE_COMPARE(instance.isExtensionEnabled<Extensions::EXT::validation_features>(), data.validationFeaturesEnabled); |
||||||
|
|
||||||
|
/** @todo cleanup when Debug::toString() or some similar utility exists */ |
||||||
|
UnsignedInt major = versionMajor(enumerateInstanceVersion()); |
||||||
|
UnsignedInt minor = versionMinor(enumerateInstanceVersion()); |
||||||
|
UnsignedInt patch = versionPatch(enumerateInstanceVersion()); |
||||||
|
/* Vulkan 1.0 instances report no patch version, special-case that */ |
||||||
|
CORRADE_COMPARE(out.str(), Utility::formatString(data.log, major, minor, patch ? Utility::formatString(".{}", patch) : "")); |
||||||
|
|
||||||
|
/* Verify that the entrypoint is actually (not) loaded as expected, to
|
||||||
|
avoid all the above reporting being just smoke & mirrors */ |
||||||
|
CORRADE_COMPARE(!!instance->CreateDebugReportCallbackEXT, data.debugReportEnabled); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::constructMove() { |
||||||
|
InstanceExtensionProperties extensions = enumerateInstanceExtensionProperties(); |
||||||
|
if(!extensions.isSupported<Extensions::KHR::get_physical_device_properties2>()) |
||||||
|
CORRADE_SKIP("VK_KHR_get_physical_device_properties2 not supported, can't test"); |
||||||
|
|
||||||
|
Instance a{InstanceCreateInfo{} |
||||||
|
.setApplicationInfo("InstanceVkTest", version(0, 0, 1)) |
||||||
|
.addEnabledExtensions<Extensions::KHR::get_physical_device_properties2>()}; |
||||||
|
VkInstance handle = a.handle(); |
||||||
|
Version version = a.version(); |
||||||
|
CORRADE_VERIFY(handle); |
||||||
|
CORRADE_VERIFY(version != Version{}); |
||||||
|
|
||||||
|
Instance b = std::move(a); |
||||||
|
CORRADE_VERIFY(!a.handle()); |
||||||
|
CORRADE_COMPARE(b.handleFlags(), HandleFlag::DestroyOnDestruction); |
||||||
|
CORRADE_COMPARE(b.handle(), handle); |
||||||
|
CORRADE_COMPARE(b.version(), version); |
||||||
|
CORRADE_VERIFY(b.isExtensionEnabled<Extensions::KHR::get_physical_device_properties2>()); |
||||||
|
/* Function pointers in a are left in whatever state they were before, as
|
||||||
|
that doesn't matter */ |
||||||
|
CORRADE_VERIFY(b->CreateDevice); |
||||||
|
|
||||||
|
Instance c{NoCreate}; |
||||||
|
c = std::move(b); |
||||||
|
CORRADE_VERIFY(!b.handle()); |
||||||
|
CORRADE_COMPARE(b.handleFlags(), HandleFlags{}); |
||||||
|
CORRADE_COMPARE(c.handleFlags(), HandleFlag::DestroyOnDestruction); |
||||||
|
CORRADE_COMPARE(c.handle(), handle); |
||||||
|
CORRADE_COMPARE(c.version(), version); |
||||||
|
CORRADE_VERIFY(c.isExtensionEnabled<Extensions::KHR::get_physical_device_properties2>()); |
||||||
|
/* Everything is swapped, including function pointers */ |
||||||
|
CORRADE_VERIFY(!b->CreateDevice); |
||||||
|
CORRADE_VERIFY(c->CreateDevice); |
||||||
|
|
||||||
|
CORRADE_VERIFY(std::is_nothrow_move_constructible<Instance>::value); |
||||||
|
CORRADE_VERIFY(std::is_nothrow_move_assignable<Instance>::value); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::constructUnknownLayer() { |
||||||
|
CORRADE_SKIP("Currently this hits an internal assert, which can't be tested."); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error redirectError{&out}; |
||||||
|
Instance instance{InstanceCreateInfo{} |
||||||
|
.addEnabledLayers({"VK_LAYER_this_doesnt_exist"_s})}; |
||||||
|
CORRADE_COMPARE(out.str(), "TODO"); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::constructUnknownExtension() { |
||||||
|
CORRADE_SKIP("Currently this hits an internal assert, which can't be tested."); |
||||||
|
|
||||||
|
std::ostringstream out; |
||||||
|
Error redirectError{&out}; |
||||||
|
Instance instance{InstanceCreateInfo{} |
||||||
|
.addEnabledExtensions({"VK_this_doesnt_exist"_s})}; |
||||||
|
CORRADE_COMPARE(out.str(), "TODO"); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::wrap() { |
||||||
|
InstanceExtensionProperties properties = enumerateInstanceExtensionProperties(); |
||||||
|
if(!properties.isSupported<Extensions::EXT::debug_report>()) |
||||||
|
CORRADE_SKIP("VK_EXT_debug_report not supported, can't test"); |
||||||
|
if(!properties.isSupported<Extensions::KHR::get_physical_device_properties2>()) |
||||||
|
CORRADE_SKIP("VK_KHR_get_physical_device_properties2 not supported, can't test"); |
||||||
|
|
||||||
|
InstanceCreateInfo info; |
||||||
|
info.addEnabledExtensions< |
||||||
|
Extensions::EXT::debug_report, |
||||||
|
Extensions::KHR::get_physical_device_properties2>(); |
||||||
|
|
||||||
|
VkInstance instance; |
||||||
|
CORRADE_COMPARE(Result(vkCreateInstance(info, nullptr, &instance)), Result::Success); |
||||||
|
CORRADE_VERIFY(instance); |
||||||
|
|
||||||
|
{ |
||||||
|
/* Wrapping should load the basic function pointers */ |
||||||
|
auto wrapped = Instance::wrap(instance, Version::Vk11, { |
||||||
|
Extensions::EXT::debug_report::string() |
||||||
|
}, HandleFlag::DestroyOnDestruction); |
||||||
|
CORRADE_VERIFY(wrapped->DestroyInstance); |
||||||
|
|
||||||
|
/* Specified version should be reported as supported but higher not
|
||||||
|
regardless of the actual driver version */ |
||||||
|
CORRADE_VERIFY(wrapped.isVersionSupported(Version::Vk11)); |
||||||
|
CORRADE_VERIFY(!wrapped.isVersionSupported(Version::Vk12)); |
||||||
|
|
||||||
|
/* Listed extensions should be reported as enabled and function
|
||||||
|
pointers loaded as well */ |
||||||
|
CORRADE_VERIFY(wrapped.isExtensionEnabled<Extensions::EXT::debug_report>()); |
||||||
|
CORRADE_VERIFY(wrapped->CreateDebugReportCallbackEXT); |
||||||
|
|
||||||
|
/* Unlisted not, but function pointers should still be loaded as the
|
||||||
|
actual instance does have the extension enabled */ |
||||||
|
CORRADE_VERIFY(!wrapped.isExtensionEnabled<Extensions::KHR::get_physical_device_properties2>()); |
||||||
|
CORRADE_VERIFY(wrapped->GetPhysicalDeviceProperties2KHR); |
||||||
|
|
||||||
|
/* Releasing won't destroy anything ... */ |
||||||
|
CORRADE_COMPARE(wrapped.release(), instance); |
||||||
|
} |
||||||
|
|
||||||
|
/* ...so we can wrap it again, non-owned, and then destroy it manually */ |
||||||
|
auto wrapped = Instance::wrap(instance, Version::Vk10, {}); |
||||||
|
CORRADE_VERIFY(wrapped->DestroyInstance); |
||||||
|
wrapped->DestroyInstance(instance, nullptr); |
||||||
|
} |
||||||
|
|
||||||
|
void InstanceVkTest::populateGlobalFunctionPointers() { |
||||||
|
vkDestroyInstance = nullptr; |
||||||
|
|
||||||
|
Instance instance; |
||||||
|
CORRADE_VERIFY(!vkDestroyInstance); |
||||||
|
instance.populateGlobalFunctionPointers(); |
||||||
|
CORRADE_VERIFY(vkDestroyInstance); |
||||||
|
CORRADE_VERIFY(vkDestroyInstance == instance->DestroyInstance); |
||||||
|
} |
||||||
|
|
||||||
|
}}}} |
||||||
|
|
||||||
|
CORRADE_TEST_MAIN(Magnum::Vk::Test::InstanceVkTest) |
||||||
Loading…
Reference in new issue