Browse Source

Vk: externally tuneable device selection.

pull/234/head
Vladimír Vondruš 6 years ago
parent
commit
722da61e65
  1. 56
      src/Magnum/Vk/DeviceProperties.cpp
  2. 24
      src/Magnum/Vk/DeviceProperties.h
  3. 4
      src/Magnum/Vk/Implementation/Arguments.cpp
  4. 76
      src/Magnum/Vk/Test/DevicePropertiesVkTest.cpp

56
src/Magnum/Vk/DeviceProperties.cpp

@ -26,13 +26,16 @@
#include "DeviceProperties.h"
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/StringView.h>
#include <Corrade/Utility/Arguments.h>
#include <Corrade/Utility/Debug.h>
#include "Magnum/Vk/Instance.h"
#include "Magnum/Vk/ExtensionProperties.h"
#include "Magnum/Vk/LayerProperties.h"
#include "Magnum/Vk/Result.h"
#include "Magnum/Vk/Implementation/Arguments.h"
#include "Magnum/Vk/Implementation/InstanceState.h"
namespace Magnum { namespace Vk {
@ -114,6 +117,59 @@ Containers::Array<DeviceProperties> enumerateDevices(Instance& instance) {
return out;
}
Containers::Optional<DeviceProperties> tryPickDevice(Instance& instance) {
Utility::Arguments args = Implementation::arguments();
args.parse(instance.state().argc, instance.state().argv);
Containers::Array<DeviceProperties> devices = enumerateDevices(instance);
/* Pick the first by default */
if(args.value("device").empty()) {
if(devices.empty()) {
Error{} << "Vk::tryPickDevice(): no Vulkan devices found";
return {};
}
return std::move(devices.front());
}
/* Pick by ID */
if(args.value("device")[0] >= '0' && args.value("device")[0] <= '9') {
UnsignedInt id = args.value<UnsignedInt>("device");
if(id >= devices.size()) {
Error{} << "Vk::tryPickDevice(): index" << id << "out of bounds for" << devices.size() << "Vulkan devices";
return {};
}
return std::move(devices[id]);
}
/* Pick by type */
DeviceType type;
if(args.value("device") == "integrated")
type = DeviceType::IntegratedGpu;
else if(args.value("device") == "discrete")
type = DeviceType::DiscreteGpu;
else if(args.value("device") == "virtual")
type = DeviceType::VirtualGpu;
else if(args.value("device") == "cpu")
type = DeviceType::Cpu;
else {
Error{} << "Vk::tryPickDevice(): unknown Vulkan device type" << args.value<Containers::StringView>("device");
return {};
}
for(DeviceProperties& device: devices)
if(device.type() == type) return std::move(device);
Error{} << "Vk::tryPickDevice(): no" << type << "found among" << devices.size() << "Vulkan devices";
return {};
}
DeviceProperties pickDevice(Instance& instance) {
Containers::Optional<DeviceProperties> device = tryPickDevice(instance);
if(device) return *std::move(device);
std::exit(1); /* LCOV_EXCL_LINE */
}
Debug& operator<<(Debug& debug, const DeviceType value) {
debug << "Vk::DeviceType" << Debug::nospace;

24
src/Magnum/Vk/DeviceProperties.h

@ -26,7 +26,7 @@
*/
/** @file
* @brief Class @ref Magnum::Vk::DeviceProperties, enum @ref Magnum::Vk::DeviceType, function @ref Magnum::Vk::enumerateDevices()
* @brief Class @ref Magnum::Vk::DeviceProperties, enum @ref Magnum::Vk::DeviceType, function @ref Magnum::Vk::enumerateDevices(), @ref Magnum::Vk::pickDevice(), @ref Magnum::Vk::tryPickDevice()
* @m_since_latest
*/
@ -86,7 +86,7 @@ MAGNUM_VK_EXPORT Debug& operator<<(Debug& debug, DeviceType value);
Wraps a @type_vk_keyword{PhysicalDevice} along with its (lazy-populated)
properties.
@see @ref enumeratePhysicalDevices()
@see @ref enumerateDevices()
*/
class MAGNUM_VK_EXPORT DeviceProperties {
public:
@ -228,6 +228,26 @@ class MAGNUM_VK_EXPORT DeviceProperties {
*/
MAGNUM_VK_EXPORT Containers::Array<DeviceProperties> enumerateDevices(Instance& instance);
/**
@brief Pick a physical device
@m_since_latest
Calls @ref enumerateDevices() and selects a device based on preferences
specified through command-line parameters or the environment. If a device is
not found, exits. See @ref tryPickDevice() for an alternative that doesn't exit
on failure.
*/
MAGNUM_VK_EXPORT DeviceProperties pickDevice(Instance& instance);
/**
@brief Try to pick a physical device
@m_since_latest
Compared to @ref pickDevice() the function returns @ref Containers::NullOpt if
a device isn't found instead of exiting.
*/
MAGNUM_VK_EXPORT Containers::Optional<DeviceProperties> tryPickDevice(Instance& instance);
}}
#endif

4
src/Magnum/Vk/Implementation/Arguments.cpp

@ -37,12 +37,14 @@ Utility::Arguments arguments() {
.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")
.addOption("device").setHelp("device", "device to use", "ID|integrated|discrete|virtual|cpu")
.setFromEnvironment("disable-layers")
.setFromEnvironment("disable-extensions")
.setFromEnvironment("enable-layers")
.setFromEnvironment("enable-instance-extensions")
.setFromEnvironment("vulkan-version")
.setFromEnvironment("log");
.setFromEnvironment("log")
.setFromEnvironment("device");
return args;
}

76
src/Magnum/Vk/Test/DevicePropertiesVkTest.cpp

@ -25,11 +25,13 @@
#include <sstream>
#include <Corrade/Containers/Array.h>
#include <Corrade/Containers/Optional.h>
#include <Corrade/Containers/StringStl.h>
#include <Corrade/Containers/StringView.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/DeviceProperties.h"
#include "Magnum/Vk/Extensions.h"
@ -58,9 +60,27 @@ struct DevicePropertiesVkTest: TestSuite::Tester {
void extensionIsSupported();
void extensionNamedRevision();
void pickDevice();
void pickDeviceIndex();
void pickDeviceType();
void pickDeviceError();
Instance _instance;
};
const struct {
const char* name;
Containers::Array<const char*> args;
const char* message;
} PickDeviceErrorData[] {
{"nothing for type found", Containers::array({"", "--magnum-device", "virtual"}),
"Vk::tryPickDevice(): no Vk::DeviceType::VirtualGpu found among {} Vulkan devices\n"},
{"index out of bounds", Containers::array({"", "--magnum-device", "666"}),
"Vk::tryPickDevice(): index 666 out of bounds for {} Vulkan devices\n"},
{"unknown type", Containers::array({"", "--magnum-device", "FAST"}),
"Vk::tryPickDevice(): unknown Vulkan device type FAST\n"}
};
DevicePropertiesVkTest::DevicePropertiesVkTest(): _instance{InstanceCreateInfo{arguments().first, arguments().second}} {
addTests({&DevicePropertiesVkTest::enumerate,
&DevicePropertiesVkTest::constructMove,
@ -72,7 +92,14 @@ DevicePropertiesVkTest::DevicePropertiesVkTest(): _instance{InstanceCreateInfo{a
&DevicePropertiesVkTest::extensionConstructMove,
&DevicePropertiesVkTest::extensionIsSupported,
&DevicePropertiesVkTest::extensionNamedRevision});
&DevicePropertiesVkTest::extensionNamedRevision,
&DevicePropertiesVkTest::pickDevice,
&DevicePropertiesVkTest::pickDeviceIndex,
&DevicePropertiesVkTest::pickDeviceType});
addInstancedTests({&DevicePropertiesVkTest::pickDeviceError},
Containers::arraySize(PickDeviceErrorData));
}
void DevicePropertiesVkTest::enumerate() {
@ -227,6 +254,53 @@ void DevicePropertiesVkTest::extensionNamedRevision() {
TestSuite::Compare::GreaterOrEqual);
}
void DevicePropertiesVkTest::pickDevice() {
/* Default behavior */
Containers::Optional<DeviceProperties> device = tryPickDevice(_instance);
CORRADE_VERIFY(device);
}
void DevicePropertiesVkTest::pickDeviceIndex() {
Containers::Array<DeviceProperties> devices = enumerateDevices(_instance);
CORRADE_VERIFY(!devices.empty());
/* Pick the last one */
CORRADE_COMPARE_AS(devices.size(), 10, TestSuite::Compare::Less);
const char id[] {char('0' + devices.size() - 1), '\0'};
const char* argv[] {"", "--magnum-device", id};
/* Creating another dedicated instance so we can pass custom args */
Instance instance{InstanceCreateInfo{Int(Containers::arraySize(argv)), argv}};
Containers::Optional<DeviceProperties> device = tryPickDevice(instance);
CORRADE_VERIFY(device);
}
void DevicePropertiesVkTest::pickDeviceType() {
const char* argv[] {"", "--magnum-device", "cpu"};
/* Creating a dedicated instance so we can pass custom args */
Instance instance{InstanceCreateInfo{Int(Containers::arraySize(argv)), argv}};
Containers::Optional<DeviceProperties> device = tryPickDevice(instance);
if(!device) CORRADE_SKIP("No CPU device found.");
CORRADE_VERIFY(device->type() == DeviceType::Cpu);
}
void DevicePropertiesVkTest::pickDeviceError() {
auto&& data = PickDeviceErrorData[testCaseInstanceId()];
setTestCaseDescription(data.name);
/* Creating a dedicated instance so we can pass custom args */
Instance instance{InstanceCreateInfo{Int(data.args.size()), const_cast<const char**>(data.args.data())}};
std::ostringstream out;
Error redirectError{&out};
CORRADE_VERIFY(!tryPickDevice(instance));
CORRADE_COMPARE(out.str(), Utility::formatString(data.message, enumerateDevices(_instance).size()));
}
}}}}
CORRADE_TEST_MAIN(Magnum::Vk::Test::DevicePropertiesVkTest)

Loading…
Cancel
Save