|
|
|
|
/*
|
|
|
|
|
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/Optional.h>
|
|
|
|
|
#include <Corrade/Containers/StringStl.h>
|
|
|
|
|
#include <Corrade/TestSuite/Compare/Numeric.h>
|
|
|
|
|
#include <Corrade/Utility/DebugStl.h>
|
|
|
|
|
#include <Corrade/Utility/FormatStl.h>
|
|
|
|
|
|
|
|
|
|
#include "Magnum/Vk/DeviceCreateInfo.h"
|
|
|
|
|
#include "Magnum/Vk/DeviceFeatures.h"
|
|
|
|
|
#include "Magnum/Vk/DeviceProperties.h"
|
|
|
|
|
#include "Magnum/Vk/Extensions.h"
|
|
|
|
|
#include "Magnum/Vk/ExtensionProperties.h"
|
|
|
|
|
#include "Magnum/Vk/Handle.h"
|
|
|
|
|
#include "Magnum/Vk/InstanceCreateInfo.h"
|
|
|
|
|
#include "Magnum/Vk/LayerProperties.h"
|
|
|
|
|
#include "Magnum/Vk/Queue.h"
|
|
|
|
|
#include "Magnum/Vk/Result.h"
|
|
|
|
|
#include "Magnum/Vk/Version.h"
|
|
|
|
|
#include "Magnum/Vk/VulkanTester.h"
|
|
|
|
|
|
|
|
|
|
#include "MagnumExternal/Vulkan/flextVkGlobal.h"
|
|
|
|
|
|
|
|
|
|
namespace Magnum { namespace Vk { namespace Test { namespace {
|
|
|
|
|
|
|
|
|
|
struct DeviceVkTest: VulkanTester {
|
|
|
|
|
explicit DeviceVkTest();
|
|
|
|
|
|
|
|
|
|
void createInfoConstruct();
|
|
|
|
|
void createInfoConstructNoImplicitExtensions();
|
|
|
|
|
void createInfoExtensions();
|
|
|
|
|
void createInfoExtensionsCopiedStrings();
|
|
|
|
|
void createInfoFeatures();
|
|
|
|
|
void createInfoFeaturesReplaceExternal();
|
|
|
|
|
void createInfoFeaturesReplacePrevious();
|
|
|
|
|
void createInfoFeaturesEnableAllResetAll();
|
|
|
|
|
void createInfoFeaturesNothingInCoreFeatures();
|
|
|
|
|
void createInfoNoQueuePriorities();
|
|
|
|
|
void createInfoWrongQueueOutputCount();
|
|
|
|
|
void createInfoConstructCopy();
|
|
|
|
|
void createInfoConstructMove();
|
|
|
|
|
void createInfoRvalue();
|
|
|
|
|
|
|
|
|
|
void construct();
|
|
|
|
|
void constructQueueFromFlags();
|
|
|
|
|
void constructExtensions();
|
|
|
|
|
void constructFeatures();
|
|
|
|
|
void constructFeaturesFromExtensions();
|
|
|
|
|
void constructDeviceCreateInfoConstReference();
|
|
|
|
|
void constructTransferDeviceProperties();
|
|
|
|
|
void constructExtensionsCommandLineDisable();
|
|
|
|
|
void constructExtensionsCommandLineEnable();
|
|
|
|
|
void constructMultipleQueues();
|
|
|
|
|
void constructRawQueue();
|
|
|
|
|
void constructMove();
|
|
|
|
|
void constructUnknownExtension();
|
|
|
|
|
void constructFeatureNotSupported();
|
|
|
|
|
void constructFeatureWithoutExtension();
|
|
|
|
|
void constructNoQueue();
|
|
|
|
|
|
|
|
|
|
void wrap();
|
|
|
|
|
|
|
|
|
|
void populateGlobalFunctionPointers();
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
struct {
|
|
|
|
|
const char* nameDisable;
|
|
|
|
|
const char* nameEnable;
|
|
|
|
|
Containers::Array<const char*> argsDisable, argsEnable;
|
|
|
|
|
bool driverVersionSupported, debugMarkerEnabled, maintenance1Enabled;
|
|
|
|
|
const char* log;
|
|
|
|
|
} ConstructCommandLineData[] {
|
|
|
|
|
/* Shouldn't print anything about version, enabled layers/exts if quier
|
|
|
|
|
output is enabled. */
|
|
|
|
|
{"quiet", "quiet, enabled extensions",
|
|
|
|
|
Containers::array({"", "--magnum-log", "quiet"}),
|
|
|
|
|
Containers::array({"", "--magnum-log", "quiet",
|
|
|
|
|
"--magnum-enable-extensions", "VK_EXT_debug_marker VK_KHR_maintenance1"}),
|
|
|
|
|
true, true, true,
|
|
|
|
|
""},
|
|
|
|
|
{"", "enabled extensions", nullptr,
|
|
|
|
|
Containers::array({"",
|
|
|
|
|
"--magnum-enable-extensions", "VK_EXT_debug_marker VK_KHR_maintenance1"}),
|
|
|
|
|
true, true, true,
|
|
|
|
|
"Device: {}\n"
|
|
|
|
|
"Device version: Vulkan {}.{}{}\n"
|
|
|
|
|
"Enabled device extensions:\n"
|
|
|
|
|
" VK_EXT_debug_marker\n"
|
|
|
|
|
" VK_KHR_maintenance1\n"},
|
|
|
|
|
{"forced version", "forced version, enabled extensions",
|
|
|
|
|
Containers::array({"",
|
|
|
|
|
"--magnum-vulkan-version", "1.0"}),
|
|
|
|
|
Containers::array({"",
|
|
|
|
|
"--magnum-vulkan-version", "1.0",
|
|
|
|
|
"--magnum-enable-extensions", "VK_EXT_debug_marker VK_KHR_maintenance1"}),
|
|
|
|
|
false, true, true,
|
|
|
|
|
"Device: {}\n"
|
|
|
|
|
"Device version: Vulkan 1.0\n"
|
|
|
|
|
"Enabled device extensions:\n"
|
|
|
|
|
" VK_EXT_debug_marker\n"
|
|
|
|
|
" VK_KHR_maintenance1\n"},
|
|
|
|
|
{"disabled one extension", "enabled one extension",
|
|
|
|
|
Containers::array({"",
|
|
|
|
|
"--magnum-disable-extensions", "VK_EXT_debug_marker"}),
|
|
|
|
|
Containers::array({"",
|
|
|
|
|
"--magnum-enable-extensions", "VK_KHR_maintenance1"}),
|
|
|
|
|
true, false, true,
|
|
|
|
|
"Device: {}\n"
|
|
|
|
|
"Device version: Vulkan {}.{}{}\n"
|
|
|
|
|
"Enabled device extensions:\n"
|
|
|
|
|
" VK_KHR_maintenance1\n"},
|
|
|
|
|
{"disabled extensions", "",
|
|
|
|
|
Containers::array({"",
|
|
|
|
|
"--magnum-disable-extensions", "VK_EXT_debug_marker VK_KHR_maintenance1"}),
|
|
|
|
|
nullptr,
|
|
|
|
|
true, false, false,
|
|
|
|
|
"Device: {}\n"
|
|
|
|
|
"Device version: Vulkan {}.{}{}\n"},
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
DeviceVkTest::DeviceVkTest(): VulkanTester{NoCreate} {
|
|
|
|
|
addTests({&DeviceVkTest::createInfoConstruct,
|
|
|
|
|
&DeviceVkTest::createInfoConstructNoImplicitExtensions,
|
|
|
|
|
&DeviceVkTest::createInfoExtensions,
|
|
|
|
|
&DeviceVkTest::createInfoExtensionsCopiedStrings,
|
|
|
|
|
&DeviceVkTest::createInfoFeatures,
|
|
|
|
|
&DeviceVkTest::createInfoFeaturesReplaceExternal,
|
|
|
|
|
&DeviceVkTest::createInfoFeaturesReplacePrevious,
|
|
|
|
|
&DeviceVkTest::createInfoFeaturesEnableAllResetAll,
|
|
|
|
|
&DeviceVkTest::createInfoFeaturesNothingInCoreFeatures,
|
|
|
|
|
&DeviceVkTest::createInfoNoQueuePriorities,
|
|
|
|
|
&DeviceVkTest::createInfoWrongQueueOutputCount,
|
|
|
|
|
&DeviceVkTest::createInfoConstructCopy,
|
|
|
|
|
&DeviceVkTest::createInfoConstructMove,
|
|
|
|
|
&DeviceVkTest::createInfoRvalue,
|
|
|
|
|
|
|
|
|
|
&DeviceVkTest::construct,
|
|
|
|
|
&DeviceVkTest::constructQueueFromFlags,
|
|
|
|
|
&DeviceVkTest::constructExtensions,
|
|
|
|
|
&DeviceVkTest::constructFeatures,
|
|
|
|
|
&DeviceVkTest::constructFeaturesFromExtensions,
|
|
|
|
|
&DeviceVkTest::constructDeviceCreateInfoConstReference,
|
|
|
|
|
&DeviceVkTest::constructTransferDeviceProperties});
|
|
|
|
|
|
|
|
|
|
addInstancedTests({&DeviceVkTest::constructExtensionsCommandLineDisable,
|
|
|
|
|
&DeviceVkTest::constructExtensionsCommandLineEnable},
|
|
|
|
|
Containers::arraySize(ConstructCommandLineData));
|
|
|
|
|
|
|
|
|
|
addTests({&DeviceVkTest::constructMultipleQueues,
|
|
|
|
|
&DeviceVkTest::constructRawQueue,
|
|
|
|
|
|
|
|
|
|
&DeviceVkTest::constructMove,
|
|
|
|
|
&DeviceVkTest::constructUnknownExtension,
|
|
|
|
|
&DeviceVkTest::constructFeatureNotSupported,
|
|
|
|
|
&DeviceVkTest::constructFeatureWithoutExtension,
|
|
|
|
|
&DeviceVkTest::constructNoQueue,
|
|
|
|
|
|
|
|
|
|
&DeviceVkTest::wrap,
|
|
|
|
|
&DeviceVkTest::populateGlobalFunctionPointers});
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
using namespace Containers::Literals;
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoConstruct() {
|
|
|
|
|
DeviceCreateInfo info{pickDevice(instance())};
|
|
|
|
|
CORRADE_VERIFY(info->sType);
|
|
|
|
|
CORRADE_VERIFY(!info->pNext);
|
|
|
|
|
/* Extensions might or might not be enabled */
|
|
|
|
|
CORRADE_VERIFY(!info->pEnabledFeatures);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoConstructNoImplicitExtensions() {
|
|
|
|
|
DeviceCreateInfo info{pickDevice(instance()), DeviceCreateInfo::Flag::NoImplicitExtensions};
|
|
|
|
|
CORRADE_VERIFY(info->sType);
|
|
|
|
|
CORRADE_VERIFY(!info->pNext);
|
|
|
|
|
/* No extensions enabled as we explicitly disabled that */
|
|
|
|
|
CORRADE_VERIFY(!info->ppEnabledExtensionNames);
|
|
|
|
|
CORRADE_COMPARE(info->enabledExtensionCount, 0);
|
|
|
|
|
CORRADE_VERIFY(!info->pEnabledFeatures);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoExtensions() {
|
|
|
|
|
if(std::getenv("MAGNUM_DISABLE_EXTENSIONS"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_DISABLE_EXTENSIONS environment variable set");
|
|
|
|
|
|
|
|
|
|
DeviceCreateInfo info{pickDevice(instance()), DeviceCreateInfo::Flag::NoImplicitExtensions};
|
|
|
|
|
CORRADE_VERIFY(!info->ppEnabledExtensionNames);
|
|
|
|
|
CORRADE_COMPARE(info->enabledExtensionCount, 0);
|
|
|
|
|
|
|
|
|
|
info.addEnabledExtensions<Extensions::KHR::maintenance1>();
|
|
|
|
|
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::maintenance1::string().data());
|
|
|
|
|
|
|
|
|
|
info.addEnabledExtensions({
|
|
|
|
|
Extensions::KHR::draw_indirect_count{},
|
|
|
|
|
Extensions::KHR::get_memory_requirements2{}
|
|
|
|
|
});
|
|
|
|
|
CORRADE_COMPARE(info->enabledExtensionCount, 3);
|
|
|
|
|
/* The pointer should be to the global data */
|
|
|
|
|
CORRADE_COMPARE(static_cast<const void*>(info->ppEnabledExtensionNames[0]),
|
|
|
|
|
Extensions::KHR::maintenance1::string().data());
|
|
|
|
|
CORRADE_COMPARE(static_cast<const void*>(info->ppEnabledExtensionNames[1]),
|
|
|
|
|
Extensions::KHR::draw_indirect_count::string().data());
|
|
|
|
|
CORRADE_COMPARE(static_cast<const void*>(info->ppEnabledExtensionNames[2]),
|
|
|
|
|
Extensions::KHR::get_memory_requirements2::string().data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoExtensionsCopiedStrings() {
|
|
|
|
|
Containers::StringView globalButNotNullTerminated = "VK_KHR_maintenance25"_s.except(1);
|
|
|
|
|
Containers::String localButNullTerminated = Extensions::KHR::draw_indirect_count::string();
|
|
|
|
|
|
|
|
|
|
DeviceCreateInfo info{pickDevice(instance()), DeviceCreateInfo::Flag::NoImplicitExtensions};
|
|
|
|
|
info.addEnabledExtensions({
|
|
|
|
|
globalButNotNullTerminated,
|
|
|
|
|
localButNullTerminated
|
|
|
|
|
});
|
|
|
|
|
CORRADE_COMPARE(info->enabledExtensionCount, 2);
|
|
|
|
|
|
|
|
|
|
CORRADE_COMPARE(info->ppEnabledExtensionNames[0], globalButNotNullTerminated);
|
|
|
|
|
CORRADE_VERIFY(info->ppEnabledExtensionNames[0] != globalButNotNullTerminated.data());
|
|
|
|
|
|
|
|
|
|
CORRADE_COMPARE(info->ppEnabledExtensionNames[1], localButNullTerminated);
|
|
|
|
|
CORRADE_VERIFY(info->ppEnabledExtensionNames[1] != localButNullTerminated.data());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoFeatures() {
|
|
|
|
|
DeviceProperties properties = pickDevice(instance());
|
|
|
|
|
|
|
|
|
|
/* We don't use the structure for anything, so we don't need to check if
|
|
|
|
|
the structure is actually supported */
|
|
|
|
|
DeviceCreateInfo info{properties};
|
|
|
|
|
info.setEnabledFeatures(DeviceFeature::RobustBufferAccess|DeviceFeature::SamplerYcbcrConversion);
|
|
|
|
|
|
|
|
|
|
/* If we have Vulkan 1.1 on both instance and the device or KHR_gpdp2 is
|
|
|
|
|
enabled on the instance, pNext chain will be filled as appropriate */
|
|
|
|
|
if((instance().isVersionSupported(Version::Vk11) && properties.isVersionSupported(Version::Vk11)) || instance().isExtensionEnabled<Extensions::KHR::get_physical_device_properties2>()) {
|
|
|
|
|
CORRADE_VERIFY(!info->pEnabledFeatures);
|
|
|
|
|
CORRADE_VERIFY(info->pNext);
|
|
|
|
|
const auto& features2 = *static_cast<const VkPhysicalDeviceFeatures2*>(info->pNext);
|
|
|
|
|
CORRADE_COMPARE(features2.sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2);
|
|
|
|
|
CORRADE_VERIFY(features2.features.robustBufferAccess);
|
|
|
|
|
|
|
|
|
|
CORRADE_VERIFY(features2.pNext);
|
|
|
|
|
const auto& samplerYcbcrConversionFeatures = *static_cast<const VkPhysicalDeviceSamplerYcbcrConversionFeatures*>(features2.pNext);
|
|
|
|
|
CORRADE_COMPARE(samplerYcbcrConversionFeatures.sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES);
|
|
|
|
|
CORRADE_VERIFY(samplerYcbcrConversionFeatures.samplerYcbcrConversion);
|
|
|
|
|
|
|
|
|
|
/* Otherwise just the pEnabledFeatures will be enabled */
|
|
|
|
|
} else {
|
|
|
|
|
CORRADE_VERIFY(!info->pNext);
|
|
|
|
|
CORRADE_VERIFY(info->pEnabledFeatures);
|
|
|
|
|
CORRADE_VERIFY(info->pEnabledFeatures->robustBufferAccess);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoFeaturesNothingInCoreFeatures() {
|
|
|
|
|
DeviceProperties properties = pickDevice(instance());
|
|
|
|
|
|
|
|
|
|
DeviceCreateInfo info{properties};
|
|
|
|
|
info.setEnabledFeatures(DeviceFeature::SamplerYcbcrConversion|DeviceFeature::ImagelessFramebuffer);
|
|
|
|
|
|
|
|
|
|
/* If we have Vulkan 1.1 on both instance and the device or KHR_gpdp2 is
|
|
|
|
|
enabled on the instance, pNext chain will be filled as appropriate */
|
|
|
|
|
if((instance().isVersionSupported(Version::Vk11) && properties.isVersionSupported(Version::Vk11)) || instance().isExtensionEnabled<Extensions::KHR::get_physical_device_properties2>()) {
|
|
|
|
|
CORRADE_VERIFY(!info->pEnabledFeatures);
|
|
|
|
|
CORRADE_VERIFY(info->pNext);
|
|
|
|
|
const auto& imagelessFramebufferFeatures = *static_cast<const VkPhysicalDeviceImagelessFramebufferFeatures*>(info->pNext);
|
|
|
|
|
CORRADE_COMPARE(imagelessFramebufferFeatures.sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES);
|
|
|
|
|
CORRADE_VERIFY(imagelessFramebufferFeatures.imagelessFramebuffer);
|
|
|
|
|
|
|
|
|
|
const auto& samplerYcbcrConversionFeatures = *static_cast<const VkPhysicalDeviceSamplerYcbcrConversionFeatures*>(imagelessFramebufferFeatures.pNext);
|
|
|
|
|
CORRADE_COMPARE(samplerYcbcrConversionFeatures.sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_SAMPLER_YCBCR_CONVERSION_FEATURES);
|
|
|
|
|
CORRADE_VERIFY(samplerYcbcrConversionFeatures.samplerYcbcrConversion);
|
|
|
|
|
|
|
|
|
|
/* Otherwise nothing is enabled as there's nowhere to connect that */
|
|
|
|
|
} else {
|
|
|
|
|
CORRADE_VERIFY(!info->pNext);
|
|
|
|
|
CORRADE_VERIFY(!info->pEnabledFeatures);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoFeaturesReplaceExternal() {
|
|
|
|
|
DeviceProperties properties = pickDevice(instance());
|
|
|
|
|
|
|
|
|
|
VkPhysicalDeviceFeatures2 features{};
|
|
|
|
|
features.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2;
|
|
|
|
|
VkAttachmentReference2 somethingAfter{};
|
|
|
|
|
somethingAfter.pNext = &features;
|
|
|
|
|
|
|
|
|
|
DeviceCreateInfo info{properties};
|
|
|
|
|
info->pNext = &somethingAfter;
|
|
|
|
|
info->pEnabledFeatures = &features.features;
|
|
|
|
|
|
|
|
|
|
info.setEnabledFeatures(DeviceFeature::RobustBufferAccess);
|
|
|
|
|
|
|
|
|
|
/* Then, if we have Vulkan 1.1 on both instance and the device or KHR_gpdp2
|
|
|
|
|
is enabled on the instance, pNext will be filled and pEnabledFeatures
|
|
|
|
|
reset */
|
|
|
|
|
if((instance().isVersionSupported(Version::Vk11) && properties.isVersionSupported(Version::Vk11)) || instance().isExtensionEnabled<Extensions::KHR::get_physical_device_properties2>()) {
|
|
|
|
|
CORRADE_VERIFY(!info->pEnabledFeatures);
|
|
|
|
|
CORRADE_VERIFY(info->pNext);
|
|
|
|
|
const auto& features2 = *static_cast<const VkPhysicalDeviceFeatures2*>(info->pNext);
|
|
|
|
|
CORRADE_COMPARE(features2.sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2);
|
|
|
|
|
CORRADE_VERIFY(features2.features.robustBufferAccess);
|
|
|
|
|
|
|
|
|
|
/* The original chain should be preserved after */
|
|
|
|
|
CORRADE_COMPARE(features2.pNext, &somethingAfter);
|
|
|
|
|
|
|
|
|
|
/* Otherwise the pNext chain will be preserved and pEnabledFeatures
|
|
|
|
|
replaced with own instance */
|
|
|
|
|
} else {
|
|
|
|
|
CORRADE_VERIFY(info->pEnabledFeatures);
|
|
|
|
|
CORRADE_VERIFY(info->pEnabledFeatures != &features.features);
|
|
|
|
|
CORRADE_VERIFY(info->pEnabledFeatures->robustBufferAccess);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* No changes to the original chain, even though it has a features on its
|
|
|
|
|
own (that's user error) */
|
|
|
|
|
CORRADE_COMPARE(somethingAfter.pNext, &features);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoFeaturesReplacePrevious() {
|
|
|
|
|
DeviceProperties properties = pickDevice(instance());
|
|
|
|
|
|
|
|
|
|
VkAttachmentReference2 somethingAfter{};
|
|
|
|
|
|
|
|
|
|
DeviceCreateInfo info{properties};
|
|
|
|
|
info->pNext = &somethingAfter;
|
|
|
|
|
|
|
|
|
|
info.setEnabledFeatures(DeviceFeature::RobustBufferAccess);
|
|
|
|
|
|
|
|
|
|
/* If we have Vulkan 1.1 on both instance and the device or KHR_gpdp2 is
|
|
|
|
|
enabled on the instance, pNext chain will be filled as appropriate */
|
|
|
|
|
if((instance().isVersionSupported(Version::Vk11) && properties.isVersionSupported(Version::Vk11)) || instance().isExtensionEnabled<Extensions::KHR::get_physical_device_properties2>()) {
|
|
|
|
|
CORRADE_VERIFY(!info->pEnabledFeatures);
|
|
|
|
|
CORRADE_VERIFY(info->pNext);
|
|
|
|
|
const auto& features2 = *static_cast<const VkPhysicalDeviceFeatures2*>(info->pNext);
|
|
|
|
|
CORRADE_COMPARE(features2.sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2);
|
|
|
|
|
CORRADE_VERIFY(features2.features.robustBufferAccess);
|
|
|
|
|
|
|
|
|
|
/* The original chain should be preserved after */
|
|
|
|
|
CORRADE_COMPARE(features2.pNext, &somethingAfter);
|
|
|
|
|
|
|
|
|
|
/* Otherwise the pNext chain will be preserved and pEnabledFeatures
|
|
|
|
|
replaced with own instance */
|
|
|
|
|
} else {
|
|
|
|
|
CORRADE_COMPARE(info->pNext, &somethingAfter);
|
|
|
|
|
CORRADE_VERIFY(info->pEnabledFeatures);
|
|
|
|
|
CORRADE_VERIFY(info->pEnabledFeatures->robustBufferAccess);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Setting a different non-core feature */
|
|
|
|
|
info.setEnabledFeatures(DeviceFeature::ImagelessFramebuffer);
|
|
|
|
|
if((instance().isVersionSupported(Version::Vk11) && properties.isVersionSupported(Version::Vk11)) || instance().isExtensionEnabled<Extensions::KHR::get_physical_device_properties2>()) {
|
|
|
|
|
CORRADE_VERIFY(!info->pEnabledFeatures);
|
|
|
|
|
CORRADE_VERIFY(info->pNext);
|
|
|
|
|
const auto& imagelessFramebufferFeatures = *static_cast<const VkPhysicalDeviceImagelessFramebufferFeatures*>(info->pNext);
|
|
|
|
|
CORRADE_COMPARE(imagelessFramebufferFeatures.sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_IMAGELESS_FRAMEBUFFER_FEATURES);
|
|
|
|
|
CORRADE_VERIFY(imagelessFramebufferFeatures.imagelessFramebuffer);
|
|
|
|
|
|
|
|
|
|
/* The original chain should still be preserved after, without the
|
|
|
|
|
structures from the previous case getting in the way */
|
|
|
|
|
CORRADE_COMPARE(imagelessFramebufferFeatures.pNext, &somethingAfter);
|
|
|
|
|
|
|
|
|
|
/* Otherwise the pNext chain will still be preserved and pEnabledFeatures
|
|
|
|
|
empty */
|
|
|
|
|
} else {
|
|
|
|
|
CORRADE_COMPARE(info->pNext, &somethingAfter);
|
|
|
|
|
CORRADE_VERIFY(!info->pEnabledFeatures);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Setting no features, everything should be fully discarded, and the
|
|
|
|
|
original chain still kept. This doesn't have any difference between
|
|
|
|
|
versions. */
|
|
|
|
|
info.setEnabledFeatures({});
|
|
|
|
|
CORRADE_COMPARE(info->pNext, &somethingAfter);
|
|
|
|
|
CORRADE_VERIFY(!info->pEnabledFeatures);
|
|
|
|
|
CORRADE_VERIFY(!somethingAfter.pNext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoFeaturesEnableAllResetAll() {
|
|
|
|
|
DeviceProperties properties = pickDevice(instance());
|
|
|
|
|
|
|
|
|
|
if((!instance().isVersionSupported(Version::Vk11) || !properties.isVersionSupported(Version::Vk11)) && !instance().isExtensionEnabled<Extensions::KHR::get_physical_device_properties2>())
|
|
|
|
|
CORRADE_SKIP("Neither Vulkan 1.1 nor KHR_get_physical_device_properties2 is supported, can't test");
|
|
|
|
|
|
|
|
|
|
VkAttachmentDescription2 somethingAfter{};
|
|
|
|
|
somethingAfter.sType = VK_STRUCTURE_TYPE_ATTACHMENT_DESCRIPTION_2;
|
|
|
|
|
|
|
|
|
|
DeviceCreateInfo info{properties};
|
|
|
|
|
info->pNext = &somethingAfter;
|
|
|
|
|
|
|
|
|
|
/* This should populate a huge chain of structures */
|
|
|
|
|
info.setEnabledFeatures(~DeviceFeatures{});
|
|
|
|
|
CORRADE_VERIFY(info->pNext != &somethingAfter);
|
|
|
|
|
CORRADE_VERIFY(!somethingAfter.pNext);
|
|
|
|
|
|
|
|
|
|
/* And this should disconnect them all again. If this fails, it means the
|
|
|
|
|
resetting code path got out of sync with the structure list. Sorry,
|
|
|
|
|
there's not really a better way how to show *where* it got wrong. */
|
|
|
|
|
info.setEnabledFeatures({});
|
|
|
|
|
CORRADE_COMPARE(info->pNext, &somethingAfter);
|
|
|
|
|
CORRADE_VERIFY(!somethingAfter.pNext);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoNoQueuePriorities() {
|
|
|
|
|
#ifdef CORRADE_NO_ASSERT
|
|
|
|
|
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
std::ostringstream out;
|
|
|
|
|
Error redirectError{&out};
|
|
|
|
|
DeviceCreateInfo{pickDevice(instance())}.addQueues(0, {}, {});
|
|
|
|
|
CORRADE_COMPARE(out.str(), "Vk::DeviceCreateInfo::addQueues(): at least one queue priority has to be specified\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoWrongQueueOutputCount() {
|
|
|
|
|
#ifdef CORRADE_NO_ASSERT
|
|
|
|
|
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
std::ostringstream out;
|
|
|
|
|
Error redirectError{&out};
|
|
|
|
|
Queue a{NoCreate}, b{NoCreate};
|
|
|
|
|
DeviceCreateInfo{pickDevice(instance())}.addQueues(0, {0.0f, 1.0f, 0.3f}, {a, b});
|
|
|
|
|
CORRADE_COMPARE(out.str(), "Vk::DeviceCreateInfo::addQueues(): expected 3 outuput queue references but got 2\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoConstructCopy() {
|
|
|
|
|
CORRADE_VERIFY(!(std::is_copy_constructible<DeviceCreateInfo>{}));
|
|
|
|
|
CORRADE_VERIFY(!(std::is_copy_assignable<DeviceCreateInfo>{}));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoConstructMove() {
|
|
|
|
|
if(std::getenv("MAGNUM_DISABLE_EXTENSIONS"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_DISABLE_EXTENSIONS environment variable set");
|
|
|
|
|
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
DeviceCreateInfo a{pickDevice(instance()), DeviceCreateInfo::Flag::NoImplicitExtensions};
|
|
|
|
|
a.addQueues(0, {0.35f}, {queue})
|
|
|
|
|
.addEnabledExtensions<Extensions::KHR::get_memory_requirements2,
|
|
|
|
|
Extensions::KHR::bind_memory2>();
|
|
|
|
|
|
|
|
|
|
DeviceCreateInfo b{std::move(a)};
|
|
|
|
|
CORRADE_COMPARE(a->enabledExtensionCount, 0);
|
|
|
|
|
CORRADE_VERIFY(!a->ppEnabledExtensionNames);
|
|
|
|
|
CORRADE_COMPARE(a->queueCreateInfoCount, 0);
|
|
|
|
|
CORRADE_VERIFY(!a->pQueueCreateInfos);
|
|
|
|
|
CORRADE_COMPARE(b->enabledExtensionCount, 2);
|
|
|
|
|
CORRADE_VERIFY(b->ppEnabledExtensionNames);
|
|
|
|
|
CORRADE_COMPARE(b->ppEnabledExtensionNames[1], "VK_KHR_bind_memory2"_s);
|
|
|
|
|
CORRADE_COMPARE(b->queueCreateInfoCount, 1);
|
|
|
|
|
CORRADE_VERIFY(b->pQueueCreateInfos);
|
|
|
|
|
CORRADE_COMPARE(b->pQueueCreateInfos[0].pQueuePriorities[0], 0.35f);
|
|
|
|
|
|
|
|
|
|
DeviceCreateInfo c{{}, {}};
|
|
|
|
|
c = std::move(b);
|
|
|
|
|
CORRADE_COMPARE(b->enabledExtensionCount, 0);
|
|
|
|
|
CORRADE_VERIFY(!b->ppEnabledExtensionNames);
|
|
|
|
|
CORRADE_COMPARE(b->queueCreateInfoCount, 0);
|
|
|
|
|
CORRADE_VERIFY(!b->pQueueCreateInfos);
|
|
|
|
|
CORRADE_COMPARE(c->enabledExtensionCount, 2);
|
|
|
|
|
CORRADE_VERIFY(c->ppEnabledExtensionNames);
|
|
|
|
|
CORRADE_COMPARE(c->ppEnabledExtensionNames[1], "VK_KHR_bind_memory2"_s);
|
|
|
|
|
CORRADE_COMPARE(c->queueCreateInfoCount, 1);
|
|
|
|
|
CORRADE_VERIFY(c->pQueueCreateInfos);
|
|
|
|
|
CORRADE_COMPARE(c->pQueueCreateInfos[0].pQueuePriorities[0], 0.35f);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::createInfoRvalue() {
|
|
|
|
|
/* Verify that there actually are graphics queues so we don't exit inside
|
|
|
|
|
addQueues() */
|
|
|
|
|
CORRADE_VERIFY(pickDevice(instance()).tryPickQueueFamily(QueueFlag::Graphics));
|
|
|
|
|
|
|
|
|
|
Float zero[1]{};
|
|
|
|
|
Queue a{NoCreate}, b{NoCreate}, c{NoCreate}, d{NoCreate};
|
|
|
|
|
Containers::Reference<Queue> referenceA[1]{a};
|
|
|
|
|
Containers::Reference<Queue> referenceC[1]{c};
|
|
|
|
|
|
|
|
|
|
VkDeviceQueueCreateInfo rawQueueInfo{};
|
|
|
|
|
rawQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
|
|
rawQueueInfo.pQueuePriorities = zero;
|
|
|
|
|
rawQueueInfo.queueFamilyIndex = 0;
|
|
|
|
|
rawQueueInfo.queueCount = 1;
|
|
|
|
|
|
|
|
|
|
DeviceCreateInfo&& info = DeviceCreateInfo{pickDevice(instance())}
|
|
|
|
|
.addEnabledExtensions(Containers::ArrayView<const Containers::StringView>{})
|
|
|
|
|
.addEnabledExtensions(std::initializer_list<Containers::StringView>{})
|
|
|
|
|
.addEnabledExtensions(Containers::ArrayView<const Extension>{})
|
|
|
|
|
.addEnabledExtensions(std::initializer_list<Extension>{})
|
|
|
|
|
.addEnabledExtensions<>()
|
|
|
|
|
.addQueues(0, zero, referenceA)
|
|
|
|
|
.addQueues(0, {0.0f}, {b})
|
|
|
|
|
.addQueues(QueueFlag::Graphics, zero, referenceC)
|
|
|
|
|
.addQueues(QueueFlag::Graphics, {0.0f}, {d})
|
|
|
|
|
.addQueues(rawQueueInfo);
|
|
|
|
|
|
|
|
|
|
/* Just to test something, main point is that the above compiles, links and
|
|
|
|
|
returns a &&. Can't test anything related to the contents because the
|
|
|
|
|
destructor gets called at the end of the expression. */
|
|
|
|
|
CORRADE_VERIFY(&info);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::construct() {
|
|
|
|
|
if(std::getenv("MAGNUM_VULKAN_VERSION"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_VULKAN_VERSION environment variable set");
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
DeviceProperties deviceProperties = pickDevice(instance());
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
Device device{instance(), DeviceCreateInfo{deviceProperties}
|
|
|
|
|
.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
};
|
|
|
|
|
CORRADE_VERIFY(device.handle());
|
|
|
|
|
/* Device function pointers should be populated */
|
|
|
|
|
CORRADE_VERIFY(device->CreateBuffer);
|
|
|
|
|
CORRADE_COMPARE(device.handleFlags(), HandleFlag::DestroyOnDestruction);
|
|
|
|
|
CORRADE_COMPARE(device.version(), deviceProperties.version());
|
|
|
|
|
/* Device version is supported */
|
|
|
|
|
CORRADE_VERIFY(device.isVersionSupported(deviceProperties.version()));
|
|
|
|
|
CORRADE_VERIFY(!device.isVersionSupported(Version::None));
|
|
|
|
|
/* No extensions are enabled by default ... */
|
|
|
|
|
CORRADE_VERIFY(!device.isExtensionEnabled<Extensions::EXT::debug_marker>());
|
|
|
|
|
/* ... and thus also no function pointers loaded */
|
|
|
|
|
CORRADE_VERIFY(!device->CmdDebugMarkerInsertEXT);
|
|
|
|
|
|
|
|
|
|
/* The queue should be also filled in */
|
|
|
|
|
CORRADE_VERIFY(queue.handle());
|
|
|
|
|
|
|
|
|
|
/* Device properties should be lazy-populated and different from the
|
|
|
|
|
above instances because we didn't transfer the ownership */
|
|
|
|
|
CORRADE_COMPARE(device.properties().name(), deviceProperties.name());
|
|
|
|
|
CORRADE_VERIFY(&device.properties().properties() != &deviceProperties.properties());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Shouldn't crash or anything */
|
|
|
|
|
CORRADE_VERIFY(true);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructQueueFromFlags() {
|
|
|
|
|
DeviceProperties deviceProperties = pickDevice(instance());
|
|
|
|
|
|
|
|
|
|
/* Verify that there actually are graphics queues so we don't exit after */
|
|
|
|
|
CORRADE_VERIFY(deviceProperties.tryPickQueueFamily(QueueFlag::Graphics));
|
|
|
|
|
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
Device device{instance(), DeviceCreateInfo{deviceProperties}
|
|
|
|
|
.addQueues(QueueFlag::Graphics, {0.0f}, {queue})};
|
|
|
|
|
CORRADE_VERIFY(device.handle());
|
|
|
|
|
|
|
|
|
|
/* The queue should be filled in like usual */
|
|
|
|
|
CORRADE_VERIFY(queue.handle());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructExtensions() {
|
|
|
|
|
if(std::getenv("MAGNUM_DISABLE_EXTENSIONS"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_DISABLE_EXTENSIONS environment variable set");
|
|
|
|
|
|
|
|
|
|
if(!enumerateLayerProperties().isSupported("VK_LAYER_KHRONOS_validation"))
|
|
|
|
|
CORRADE_SKIP("VK_LAYER_KHRONOS_validation not supported, can't test");
|
|
|
|
|
|
|
|
|
|
/* Creating a dedicated instance so we can pass custom args and enable
|
|
|
|
|
layers & exts independently */
|
|
|
|
|
Instance instance{InstanceCreateInfo{}
|
|
|
|
|
.addEnabledLayers({"VK_LAYER_KHRONOS_validation"})
|
|
|
|
|
/* Needed by VK_EXT_debug_marker */
|
|
|
|
|
.addEnabledExtensions<Extensions::EXT::debug_report>()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
DeviceProperties deviceProperties = pickDevice(instance);
|
|
|
|
|
ExtensionProperties extensions = deviceProperties.enumerateExtensionProperties({"VK_LAYER_KHRONOS_validation"});
|
|
|
|
|
if(!extensions.isSupported<Extensions::EXT::debug_marker>())
|
|
|
|
|
CORRADE_SKIP("VK_EXT_debug_marker not supported, can't test");
|
|
|
|
|
if(!extensions.isSupported<Extensions::KHR::maintenance1>())
|
|
|
|
|
CORRADE_SKIP("VK_KHR_maintenance1 not supported, can't test");
|
|
|
|
|
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
Device device{instance, DeviceCreateInfo{deviceProperties}
|
|
|
|
|
.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
.addEnabledExtensions({
|
|
|
|
|
Extensions::EXT::debug_marker::string(),
|
|
|
|
|
"VK_KHR_maintenance1"_s
|
|
|
|
|
})};
|
|
|
|
|
CORRADE_VERIFY(device.handle());
|
|
|
|
|
|
|
|
|
|
/* Extensions should be reported as enabled ... */
|
|
|
|
|
CORRADE_VERIFY(device.isExtensionEnabled<Extensions::EXT::debug_marker>());
|
|
|
|
|
CORRADE_VERIFY(device.isExtensionEnabled(Extensions::KHR::maintenance1{}));
|
|
|
|
|
/* ... and function pointers loaded */
|
|
|
|
|
CORRADE_VERIFY(device->CmdDebugMarkerInsertEXT);
|
|
|
|
|
CORRADE_VERIFY(device->TrimCommandPoolKHR);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructFeatures() {
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
Device device{instance(), DeviceCreateInfo{pickDevice(instance())}
|
|
|
|
|
.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
/* RobustBufferAccess is guaranteed to be supported always, no need to
|
|
|
|
|
check anything */
|
|
|
|
|
.setEnabledFeatures(DeviceFeature::RobustBufferAccess)};
|
|
|
|
|
CORRADE_VERIFY(device.handle());
|
|
|
|
|
|
|
|
|
|
/* Features should be reported as enabled */
|
|
|
|
|
CORRADE_COMPARE(device.enabledFeatures(), DeviceFeature::RobustBufferAccess);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructFeaturesFromExtensions() {
|
|
|
|
|
DeviceProperties properties = pickDevice(instance());
|
|
|
|
|
|
|
|
|
|
if(!properties.enumerateExtensionProperties().isSupported<Extensions::KHR::sampler_ycbcr_conversion>())
|
|
|
|
|
CORRADE_SKIP("VK_KHR_sampler_ycbcr_conversion not supported, can't test");
|
|
|
|
|
if(!(properties.features() & DeviceFeature::SamplerYcbcrConversion))
|
|
|
|
|
CORRADE_SKIP("SamplerYcbcrConversion feature not supported, can't test");
|
|
|
|
|
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
Device device{instance(), DeviceCreateInfo{properties}
|
|
|
|
|
.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
.addEnabledExtensions<Extensions::KHR::sampler_ycbcr_conversion>()
|
|
|
|
|
/* RobustBufferAccess is guaranteed to be supported always, no need to
|
|
|
|
|
check anything */
|
|
|
|
|
.setEnabledFeatures(DeviceFeature::RobustBufferAccess|DeviceFeature::SamplerYcbcrConversion)};
|
|
|
|
|
CORRADE_VERIFY(device.handle());
|
|
|
|
|
|
|
|
|
|
/* Features should be reported as enabled */
|
|
|
|
|
CORRADE_COMPARE(device.enabledFeatures(), DeviceFeature::RobustBufferAccess|DeviceFeature::SamplerYcbcrConversion);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructDeviceCreateInfoConstReference() {
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
DeviceProperties deviceProperties = pickDevice(instance());
|
|
|
|
|
DeviceCreateInfo info{deviceProperties};
|
|
|
|
|
info.addQueues(0, {0.0f}, {queue});
|
|
|
|
|
|
|
|
|
|
/* Just to verify the overload taking const DeviceProperties& works as
|
|
|
|
|
well (most of the above tests verified a move) */
|
|
|
|
|
Device device{instance(), info};
|
|
|
|
|
CORRADE_VERIFY(device.handle());
|
|
|
|
|
|
|
|
|
|
/* Device properties should be lazy-populated and different from the
|
|
|
|
|
above instances because we didn't transfer the ownership here either */
|
|
|
|
|
CORRADE_COMPARE(device.properties().name(), deviceProperties.name());
|
|
|
|
|
CORRADE_VERIFY(&device.properties().properties() != &deviceProperties.properties());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructTransferDeviceProperties() {
|
|
|
|
|
DeviceProperties deviceProperties = pickDevice(instance());
|
|
|
|
|
const void* vkProperties = &deviceProperties.properties();
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
Device device{instance(), DeviceCreateInfo{std::move(deviceProperties)}
|
|
|
|
|
.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* Device properties should be the same address as in the original instance
|
|
|
|
|
because the ownership got transferred through */
|
|
|
|
|
CORRADE_COMPARE(&device.properties().properties(), vkProperties);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructExtensionsCommandLineDisable() {
|
|
|
|
|
auto&& data = ConstructCommandLineData[testCaseInstanceId()];
|
|
|
|
|
setTestCaseDescription(data.nameDisable);
|
|
|
|
|
|
|
|
|
|
if(std::getenv("MAGNUM_VULKAN_VERSION"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_VULKAN_VERSION environment variable set");
|
|
|
|
|
if(std::getenv("MAGNUM_DISABLE_LAYERS"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_DISABLE_LAYERS environment variable set");
|
|
|
|
|
if(std::getenv("MAGNUM_DISABLE_EXTENSIONS"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_DISABLE_EXTENSIONS environment variable set");
|
|
|
|
|
|
|
|
|
|
if(!enumerateLayerProperties().isSupported("VK_LAYER_KHRONOS_validation"))
|
|
|
|
|
CORRADE_SKIP("VK_LAYER_KHRONOS_validation not supported, can't test");
|
|
|
|
|
|
|
|
|
|
/* Creating a dedicated instance so we can pass custom args and enable
|
|
|
|
|
layers independently */
|
|
|
|
|
Instance instance2{InstanceCreateInfo{Int(data.argsDisable.size()), data.argsDisable}
|
|
|
|
|
.addEnabledLayers({"VK_LAYER_KHRONOS_validation"})
|
|
|
|
|
/* Needed by VK_EXT_debug_marker */
|
|
|
|
|
.addEnabledExtensions<Extensions::EXT::debug_report>()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
DeviceProperties deviceProperties = pickDevice(instance2);
|
|
|
|
|
ExtensionProperties extensions = deviceProperties.enumerateExtensionProperties({"VK_LAYER_KHRONOS_validation"});
|
|
|
|
|
if(!extensions.isSupported<Extensions::EXT::debug_marker>())
|
|
|
|
|
CORRADE_SKIP("VK_EXT_debug_marker not supported, can't test");
|
|
|
|
|
if(!extensions.isSupported<Extensions::KHR::maintenance1>())
|
|
|
|
|
CORRADE_SKIP("VK_KHR_maintenance1 not supported, can't test");
|
|
|
|
|
|
|
|
|
|
std::ostringstream out;
|
|
|
|
|
Debug redirectOutput{&out};
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
Device device{instance2, DeviceCreateInfo{deviceProperties, DeviceCreateInfo::Flag::NoImplicitExtensions}
|
|
|
|
|
.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
.addEnabledExtensions<
|
|
|
|
|
Extensions::EXT::debug_marker,
|
|
|
|
|
Extensions::KHR::maintenance1
|
|
|
|
|
>()};
|
|
|
|
|
CORRADE_VERIFY(device.handle());
|
|
|
|
|
CORRADE_COMPARE(device.isVersionSupported(deviceProperties.version()), data.driverVersionSupported);
|
|
|
|
|
CORRADE_COMPARE(device.isExtensionEnabled<Extensions::EXT::debug_marker>(), data.debugMarkerEnabled);
|
|
|
|
|
CORRADE_COMPARE(device.isExtensionEnabled<Extensions::KHR::maintenance1>(), data.maintenance1Enabled);
|
|
|
|
|
|
|
|
|
|
/** @todo cleanup when Debug::toString() or some similar utility exists */
|
|
|
|
|
UnsignedInt major = versionMajor(deviceProperties.version());
|
|
|
|
|
UnsignedInt minor = versionMinor(deviceProperties.version());
|
|
|
|
|
UnsignedInt patch = versionPatch(deviceProperties.version());
|
|
|
|
|
/* SwiftShader reports just 1.1 with no patch version, special-case that */
|
|
|
|
|
CORRADE_COMPARE(out.str(), Utility::formatString(data.log, deviceProperties.name(), 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(!!device->CmdDebugMarkerInsertEXT, data.debugMarkerEnabled);
|
|
|
|
|
CORRADE_COMPARE(!!device->TrimCommandPoolKHR, data.maintenance1Enabled);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructExtensionsCommandLineEnable() {
|
|
|
|
|
auto&& data = ConstructCommandLineData[testCaseInstanceId()];
|
|
|
|
|
setTestCaseDescription(data.nameEnable);
|
|
|
|
|
|
|
|
|
|
if(std::getenv("MAGNUM_VULKAN_VERSION"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_VULKAN_VERSION environment variable set");
|
|
|
|
|
if(std::getenv("MAGNUM_DISABLE_LAYERS"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_DISABLE_LAYERS environment variable set");
|
|
|
|
|
if(std::getenv("MAGNUM_DISABLE_EXTENSIONS"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_DISABLE_EXTENSIONS environment variable set");
|
|
|
|
|
|
|
|
|
|
if(!enumerateLayerProperties().isSupported("VK_LAYER_KHRONOS_validation"))
|
|
|
|
|
CORRADE_SKIP("VK_LAYER_KHRONOS_validation not supported, can't test");
|
|
|
|
|
|
|
|
|
|
/* Creating a dedicated instance so we can pass custom args and enable
|
|
|
|
|
layers independently */
|
|
|
|
|
Instance instance2{InstanceCreateInfo{Int(data.argsEnable.size()), data.argsEnable}
|
|
|
|
|
.addEnabledLayers({"VK_LAYER_KHRONOS_validation"})
|
|
|
|
|
/* Needed by VK_EXT_debug_marker */
|
|
|
|
|
.addEnabledExtensions<Extensions::EXT::debug_report>()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
DeviceProperties deviceProperties = pickDevice(instance2);
|
|
|
|
|
ExtensionProperties extensions = deviceProperties.enumerateExtensionProperties({"VK_LAYER_KHRONOS_validation"});
|
|
|
|
|
if(!extensions.isSupported<Extensions::EXT::debug_marker>())
|
|
|
|
|
CORRADE_SKIP("VK_EXT_debug_marker not supported, can't test");
|
|
|
|
|
if(!extensions.isSupported<Extensions::KHR::maintenance1>())
|
|
|
|
|
CORRADE_SKIP("VK_KHR_maintenance1 not supported, can't test");
|
|
|
|
|
|
|
|
|
|
std::ostringstream out;
|
|
|
|
|
Debug redirectOutput{&out};
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
Device device{instance2, DeviceCreateInfo{pickDevice(instance2), DeviceCreateInfo::Flag::NoImplicitExtensions}
|
|
|
|
|
.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
/* Nothing enabled by the application */
|
|
|
|
|
};
|
|
|
|
|
CORRADE_VERIFY(device.handle());
|
|
|
|
|
CORRADE_COMPARE(device.isVersionSupported(deviceProperties.version()), data.driverVersionSupported);
|
|
|
|
|
CORRADE_COMPARE(device.isExtensionEnabled<Extensions::EXT::debug_marker>(), data.debugMarkerEnabled);
|
|
|
|
|
CORRADE_COMPARE(device.isExtensionEnabled<Extensions::KHR::maintenance1>(), data.maintenance1Enabled);
|
|
|
|
|
|
|
|
|
|
/** @todo cleanup when Debug::toString() or some similar utility exists */
|
|
|
|
|
UnsignedInt major = versionMajor(deviceProperties.version());
|
|
|
|
|
UnsignedInt minor = versionMinor(deviceProperties.version());
|
|
|
|
|
UnsignedInt patch = versionPatch(deviceProperties.version());
|
|
|
|
|
/* SwiftShader reports just 1.1 with no patch version, special-case that */
|
|
|
|
|
CORRADE_COMPARE(out.str(), Utility::formatString(data.log, deviceProperties.name(), 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(!!device->CmdDebugMarkerInsertEXT, data.debugMarkerEnabled);
|
|
|
|
|
CORRADE_COMPARE(!!device->TrimCommandPoolKHR, data.maintenance1Enabled);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructMultipleQueues() {
|
|
|
|
|
/* Find a GPU that has at least two queue families and at least four
|
|
|
|
|
queues in one family */
|
|
|
|
|
Containers::Array<DeviceProperties> deviceProperties = enumerateDevices(instance());
|
|
|
|
|
|
|
|
|
|
DeviceProperties* deviceWithMultipleQueues = nullptr;
|
|
|
|
|
UnsignedInt largeFamily = ~UnsignedInt{};
|
|
|
|
|
for(DeviceProperties& i: deviceProperties) {
|
|
|
|
|
if(i.queueFamilyCount() < 2) continue;
|
|
|
|
|
for(UnsignedInt family = 0; family != i.queueFamilyCount(); ++family) {
|
|
|
|
|
if(i.queueFamilySize(family) < 4) continue;
|
|
|
|
|
largeFamily = family;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
deviceWithMultipleQueues = &i;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if(!deviceWithMultipleQueues || largeFamily == ~UnsignedInt{})
|
|
|
|
|
CORRADE_SKIP("No device with at least two queue families and at least four queues in one family found, can't test");
|
|
|
|
|
|
|
|
|
|
const UnsignedInt otherFamily = largeFamily == 0 ? 1 : 0;
|
|
|
|
|
|
|
|
|
|
constexpr Float zero = 0.0f;
|
|
|
|
|
VkDeviceQueueCreateInfo rawQueueInfo{};
|
|
|
|
|
rawQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
|
|
rawQueueInfo.pQueuePriorities = &zero;
|
|
|
|
|
rawQueueInfo.queueFamilyIndex = otherFamily;
|
|
|
|
|
rawQueueInfo.queueCount = 1;
|
|
|
|
|
|
|
|
|
|
Queue a{NoCreate}, b{NoCreate}, c{NoCreate};
|
|
|
|
|
Device device{instance(), DeviceCreateInfo{*deviceWithMultipleQueues}
|
|
|
|
|
/* Request a raw queue in the middle of it all to test we skip it when
|
|
|
|
|
populating the outputs, and correctly offset the next IDs. According
|
|
|
|
|
to the spec we can request each family only once, which makes the
|
|
|
|
|
implementation and testing slightly simpler. */
|
|
|
|
|
.addQueues(rawQueueInfo)
|
|
|
|
|
/* Request multiple queues in a single family to test we correctly loop
|
|
|
|
|
over these as well */
|
|
|
|
|
.addQueues(largeFamily, {0.5f, 0.75f, 1.0f}, {a, b, c})};
|
|
|
|
|
|
|
|
|
|
/* All queues should be found and different */
|
|
|
|
|
CORRADE_VERIFY(a.handle());
|
|
|
|
|
CORRADE_VERIFY(b.handle());
|
|
|
|
|
CORRADE_VERIFY(c.handle());
|
|
|
|
|
CORRADE_VERIFY(a.handle() != b.handle());
|
|
|
|
|
CORRADE_VERIFY(a.handle() != c.handle());
|
|
|
|
|
CORRADE_VERIFY(b.handle() != c.handle());
|
|
|
|
|
|
|
|
|
|
/* Fetching the same queue again should give the same handle */
|
|
|
|
|
VkQueue aAgain;
|
|
|
|
|
device->GetDeviceQueue(device, largeFamily, 0, &aAgain);
|
|
|
|
|
CORRADE_COMPARE(aAgain, a.handle());
|
|
|
|
|
|
|
|
|
|
/* Fetch the raw queue, should be different from everything else as well */
|
|
|
|
|
VkQueue rawQueue;
|
|
|
|
|
device->GetDeviceQueue(device, otherFamily, 0, &rawQueue);
|
|
|
|
|
CORRADE_VERIFY(rawQueue);
|
|
|
|
|
CORRADE_VERIFY(rawQueue != a.handle());
|
|
|
|
|
CORRADE_VERIFY(rawQueue != b.handle());
|
|
|
|
|
CORRADE_VERIFY(rawQueue != c.handle());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructRawQueue() {
|
|
|
|
|
/* Testing a subset of constructQueues() again because not all drivers
|
|
|
|
|
have multiple queues and we want to have the coverage */
|
|
|
|
|
constexpr Float zero = 0.0f;
|
|
|
|
|
VkDeviceQueueCreateInfo rawQueueInfo{};
|
|
|
|
|
rawQueueInfo.sType = VK_STRUCTURE_TYPE_DEVICE_QUEUE_CREATE_INFO;
|
|
|
|
|
rawQueueInfo.pQueuePriorities = &zero;
|
|
|
|
|
rawQueueInfo.queueFamilyIndex = 0;
|
|
|
|
|
rawQueueInfo.queueCount = 1;
|
|
|
|
|
Device device{instance(), DeviceCreateInfo{pickDevice(instance())}
|
|
|
|
|
.addQueues(rawQueueInfo)};
|
|
|
|
|
|
|
|
|
|
/* Fetch the raw queue */
|
|
|
|
|
VkQueue rawQueue;
|
|
|
|
|
device->GetDeviceQueue(device, 0, 0, &rawQueue);
|
|
|
|
|
CORRADE_VERIFY(rawQueue);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructMove() {
|
|
|
|
|
if(std::getenv("MAGNUM_VULKAN_VERSION"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_VULKAN_VERSION environment variable set");
|
|
|
|
|
|
|
|
|
|
DeviceProperties deviceProperties = pickDevice(instance());
|
|
|
|
|
ExtensionProperties extensions = deviceProperties.enumerateExtensionProperties();
|
|
|
|
|
if(!extensions.isSupported<Extensions::KHR::maintenance1>())
|
|
|
|
|
CORRADE_SKIP("VK_KHR_maintenance1 not supported, can't test");
|
|
|
|
|
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
Device a{instance(), DeviceCreateInfo{deviceProperties}
|
|
|
|
|
.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
.addEnabledExtensions<Extensions::KHR::maintenance1>()
|
|
|
|
|
};
|
|
|
|
|
VkDevice handle = a.handle();
|
|
|
|
|
Version version = a.version();
|
|
|
|
|
CORRADE_VERIFY(handle);
|
|
|
|
|
CORRADE_VERIFY(version != Version{});
|
|
|
|
|
CORRADE_VERIFY(version != Version::None);
|
|
|
|
|
|
|
|
|
|
Device 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_COMPARE(b.properties().version(), version);
|
|
|
|
|
CORRADE_VERIFY(b.isExtensionEnabled<Extensions::KHR::maintenance1>());
|
|
|
|
|
/* Function pointers in a are left in whatever state they were before, as
|
|
|
|
|
that doesn't matter */
|
|
|
|
|
CORRADE_VERIFY(b->CreateBuffer);
|
|
|
|
|
|
|
|
|
|
Device 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_COMPARE(c.properties().version(), version);
|
|
|
|
|
CORRADE_VERIFY(c.isExtensionEnabled<Extensions::KHR::maintenance1>());
|
|
|
|
|
/* Everything is swapped, including function pointers */
|
|
|
|
|
CORRADE_VERIFY(!b->CreateBuffer);
|
|
|
|
|
CORRADE_VERIFY(c->CreateBuffer);
|
|
|
|
|
|
|
|
|
|
CORRADE_VERIFY(std::is_nothrow_move_constructible<Device>::value);
|
|
|
|
|
CORRADE_VERIFY(std::is_nothrow_move_assignable<Device>::value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructUnknownExtension() {
|
|
|
|
|
CORRADE_SKIP("Currently this hits an internal assert, which can't be tested.");
|
|
|
|
|
|
|
|
|
|
std::ostringstream out;
|
|
|
|
|
Error redirectError{&out};
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
Device device{instance(), DeviceCreateInfo{pickDevice(instance())}
|
|
|
|
|
.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
.addEnabledExtensions({"VK_this_doesnt_exist"_s})};
|
|
|
|
|
CORRADE_COMPARE(out.str(), "TODO");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructFeatureNotSupported() {
|
|
|
|
|
DeviceProperties properties = pickDevice(instance());
|
|
|
|
|
if(properties.features() & DeviceFeature::SparseBinding)
|
|
|
|
|
CORRADE_SKIP("The SparseBinding feature is supported, can't test");
|
|
|
|
|
CORRADE_SKIP("Currently this hits an internal assert, which can't be tested.");
|
|
|
|
|
|
|
|
|
|
std::ostringstream out;
|
|
|
|
|
Error redirectError{&out};
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
Device device{instance(), DeviceCreateInfo{properties}
|
|
|
|
|
.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
.setEnabledFeatures(DeviceFeature::SparseBinding)};
|
|
|
|
|
CORRADE_COMPARE(out.str(), "TODO");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructFeatureWithoutExtension() {
|
|
|
|
|
DeviceProperties properties = pickDevice(instance());
|
|
|
|
|
if((!instance().isVersionSupported(Version::Vk11) || !properties.isVersionSupported(Version::Vk11)) && !instance().isExtensionEnabled<Extensions::KHR::get_physical_device_properties2>())
|
|
|
|
|
CORRADE_SKIP("Neither Vulkan 1.1 nor KHR_get_physical_device_properties2 is supported, can't test");
|
|
|
|
|
if(properties.features() & DeviceFeature::TextureCompressionAstcHdr)
|
|
|
|
|
CORRADE_SKIP("The TextureCompressionAstcHdr feature is supported, can't test");
|
|
|
|
|
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
DeviceCreateInfo info{properties};
|
|
|
|
|
info.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
.setEnabledFeatures(DeviceFeature::TextureCompressionAstcHdr);
|
|
|
|
|
|
|
|
|
|
/* Just to verify we're doing the correct thing */
|
|
|
|
|
CORRADE_VERIFY(info->pNext);
|
|
|
|
|
CORRADE_COMPARE(static_cast<const VkBaseInStructure*>(info->pNext)->sType, VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_TEXTURE_COMPRESSION_ASTC_HDR_FEATURES_EXT);
|
|
|
|
|
CORRADE_VERIFY(static_cast<const VkPhysicalDeviceTextureCompressionASTCHDRFeaturesEXT*>(info->pNext)->textureCompressionASTC_HDR);
|
|
|
|
|
|
|
|
|
|
std::ostringstream out;
|
|
|
|
|
Error redirectError{&out};
|
|
|
|
|
Device device{instance(), info};
|
|
|
|
|
CORRADE_EXPECT_FAIL("For some reason it doesn't complain when a feature that needs an extension is enabled. Am I stupid?");
|
|
|
|
|
CORRADE_VERIFY(!out.str().empty());
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::constructNoQueue() {
|
|
|
|
|
#ifdef CORRADE_NO_ASSERT
|
|
|
|
|
CORRADE_SKIP("CORRADE_NO_ASSERT defined, can't test assertions");
|
|
|
|
|
#endif
|
|
|
|
|
|
|
|
|
|
std::ostringstream out;
|
|
|
|
|
Error redirectError{&out};
|
|
|
|
|
Device device{instance(), DeviceCreateInfo{pickDevice(instance())}};
|
|
|
|
|
CORRADE_COMPARE(out.str(), "Vk::Device: needs to be created with at least one queue\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::wrap() {
|
|
|
|
|
if(std::getenv("MAGNUM_VULKAN_VERSION"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_VULKAN_VERSION environment variable set");
|
|
|
|
|
if(std::getenv("MAGNUM_DISABLE_LAYERS"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_DISABLE_LAYERS environment variable set");
|
|
|
|
|
if(std::getenv("MAGNUM_DISABLE_EXTENSIONS"))
|
|
|
|
|
CORRADE_SKIP("Can't test with the MAGNUM_DISABLE_EXTENSIONS environment variable set");
|
|
|
|
|
|
|
|
|
|
if(!enumerateLayerProperties().isSupported("VK_LAYER_KHRONOS_validation"))
|
|
|
|
|
CORRADE_SKIP("VK_LAYER_KHRONOS_validation not supported, can't test");
|
|
|
|
|
|
|
|
|
|
/* Creating a dedicated instance so we can enable layers independently */
|
|
|
|
|
Instance instance2{InstanceCreateInfo{}
|
|
|
|
|
.addEnabledLayers({"VK_LAYER_KHRONOS_validation"})
|
|
|
|
|
/* Needed by VK_EXT_debug_marker */
|
|
|
|
|
.addEnabledExtensions<Extensions::EXT::debug_report>()
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
DeviceProperties deviceProperties = pickDevice(instance2);
|
|
|
|
|
ExtensionProperties extensions = deviceProperties.enumerateExtensionProperties({"VK_LAYER_KHRONOS_validation"});
|
|
|
|
|
if(!extensions.isSupported<Extensions::EXT::debug_marker>())
|
|
|
|
|
CORRADE_SKIP("VK_EXT_debug_marker not supported, can't test");
|
|
|
|
|
if(!extensions.isSupported<Extensions::KHR::maintenance1>())
|
|
|
|
|
CORRADE_SKIP("VK_KHR_maintenance1 not supported, can't test");
|
|
|
|
|
|
|
|
|
|
VkDevice device;
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
CORRADE_COMPARE(Result(instance2->CreateDevice(deviceProperties,
|
|
|
|
|
DeviceCreateInfo{pickDevice(instance2)}
|
|
|
|
|
.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
.addEnabledExtensions<
|
|
|
|
|
Extensions::EXT::debug_marker,
|
|
|
|
|
Extensions::KHR::maintenance1
|
|
|
|
|
>()
|
|
|
|
|
/* RobustBufferAccess is guaranteed to be supported always, no need
|
|
|
|
|
to check anything */
|
|
|
|
|
.setEnabledFeatures(DeviceFeature::RobustBufferAccess),
|
|
|
|
|
nullptr, &device)), Result::Success);
|
|
|
|
|
CORRADE_VERIFY(device);
|
|
|
|
|
/* Populating the queue handle is done only from Device itself, so it won't
|
|
|
|
|
happen here -- would need to call vkGetDeviceQueue[2] directly */
|
|
|
|
|
CORRADE_VERIFY(!queue.handle());
|
|
|
|
|
|
|
|
|
|
{
|
|
|
|
|
/* Wrapping should load the basic function pointers */
|
|
|
|
|
auto wrapped = Device::wrap(instance2, device, Version::Vk11, {
|
|
|
|
|
Extensions::EXT::debug_marker::string()
|
|
|
|
|
}, DeviceFeature::RobustBufferAccess, HandleFlag::DestroyOnDestruction);
|
|
|
|
|
CORRADE_VERIFY(wrapped->DestroyDevice);
|
|
|
|
|
|
|
|
|
|
/* 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_marker>());
|
|
|
|
|
CORRADE_VERIFY(wrapped->CmdDebugMarkerInsertEXT);
|
|
|
|
|
|
|
|
|
|
/* Unlisted not, but function pointers should still be loaded as the
|
|
|
|
|
actual instance does have the extension enabled */
|
|
|
|
|
CORRADE_VERIFY(!wrapped.isExtensionEnabled<Extensions::KHR::maintenance1>());
|
|
|
|
|
CORRADE_VERIFY(wrapped->TrimCommandPoolKHR);
|
|
|
|
|
|
|
|
|
|
/* Listed features should be reported as enabled */
|
|
|
|
|
CORRADE_COMPARE(wrapped.enabledFeatures(), DeviceFeature::RobustBufferAccess);
|
|
|
|
|
|
|
|
|
|
/* Releasing won't destroy anything ... */
|
|
|
|
|
CORRADE_COMPARE(wrapped.release(), device);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* ...so we can wrap it again, non-owned, and then destroy it manually */
|
|
|
|
|
auto wrapped = Device::wrap(instance2, device, Version::Vk10, {}, {});
|
|
|
|
|
CORRADE_VERIFY(wrapped->DestroyDevice);
|
|
|
|
|
wrapped->DestroyDevice(device, nullptr);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
void DeviceVkTest::populateGlobalFunctionPointers() {
|
|
|
|
|
vkDestroyDevice = nullptr;
|
|
|
|
|
|
|
|
|
|
Queue queue{NoCreate};
|
|
|
|
|
Device device{instance(), DeviceCreateInfo{pickDevice(instance())}
|
|
|
|
|
.addQueues(0, {0.0f}, {queue})
|
|
|
|
|
};
|
|
|
|
|
CORRADE_VERIFY(!vkDestroyDevice);
|
|
|
|
|
device.populateGlobalFunctionPointers();
|
|
|
|
|
CORRADE_VERIFY(vkDestroyDevice);
|
|
|
|
|
CORRADE_VERIFY(vkDestroyDevice == device->DestroyDevice);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
}}}}
|
|
|
|
|
|
|
|
|
|
CORRADE_TEST_MAIN(Magnum::Vk::Test::DeviceVkTest)
|