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