Reworked command line argument handling (#804)
* Reworked command line argument handling Added a new class to handle these
This commit is contained in:
parent
b1eafdbcc6
commit
165b66a718
2 changed files with 192 additions and 122 deletions
|
|
@ -701,84 +701,57 @@ VulkanExampleBase::VulkanExampleBase(bool enableValidation)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
settings.validation = enableValidation;
|
settings.validation = enableValidation;
|
||||||
|
|
||||||
char* numConvPtr;
|
// Command line arguments
|
||||||
|
commandLineParser.parse(args);
|
||||||
// Parse command line arguments
|
if (commandLineParser.isSet("help")) {
|
||||||
for (size_t i = 0; i < args.size(); i++)
|
#if defined(_WIN32)
|
||||||
{
|
setupConsole("Vulkan example");
|
||||||
if (args[i] == std::string("-validation")) {
|
#endif
|
||||||
settings.validation = true;
|
commandLineParser.printHelp();
|
||||||
|
std::cin.get();
|
||||||
|
exit(0);
|
||||||
|
}
|
||||||
|
if (commandLineParser.isSet("validation")) {
|
||||||
|
settings.validation = true;
|
||||||
|
}
|
||||||
|
if (commandLineParser.isSet("vsync")) {
|
||||||
|
settings.vsync = true;
|
||||||
|
}
|
||||||
|
if (commandLineParser.isSet("height")) {
|
||||||
|
height = commandLineParser.getValueAsInt("height", width);
|
||||||
|
}
|
||||||
|
if (commandLineParser.isSet("width")) {
|
||||||
|
width = commandLineParser.getValueAsInt("width", width);
|
||||||
|
}
|
||||||
|
if (commandLineParser.isSet("fullscreen")) {
|
||||||
|
settings.fullscreen = true;
|
||||||
|
}
|
||||||
|
if (commandLineParser.isSet("shaders")) {
|
||||||
|
std::string value = commandLineParser.getValueAsString("shaders", "glsl");
|
||||||
|
if ((value != "glsl") && (value != "hlsl")) {
|
||||||
|
std::cerr << "Shader type must be one of 'glsl' or 'hlsl'\n";
|
||||||
}
|
}
|
||||||
if (args[i] == std::string("-vsync")) {
|
else {
|
||||||
settings.vsync = true;
|
shaderDir = value;
|
||||||
}
|
|
||||||
if ((args[i] == std::string("-f")) || (args[i] == std::string("--fullscreen"))) {
|
|
||||||
settings.fullscreen = true;
|
|
||||||
}
|
|
||||||
if ((args[i] == std::string("-w")) || (args[i] == std::string("--width"))) {
|
|
||||||
uint32_t w = strtol(args[i + 1], &numConvPtr, 10);
|
|
||||||
if (numConvPtr != args[i + 1]) { width = w; };
|
|
||||||
}
|
|
||||||
if ((args[i] == std::string("-h")) || (args[i] == std::string("--height"))) {
|
|
||||||
uint32_t h = strtol(args[i + 1], &numConvPtr, 10);
|
|
||||||
if (numConvPtr != args[i + 1]) { height = h; };
|
|
||||||
}
|
|
||||||
// Select between glsl and hlsl shaders
|
|
||||||
if ((args[i] == std::string("-s")) || (args[i] == std::string("--shaders"))) {
|
|
||||||
std::string type;
|
|
||||||
if (args.size() > i + 1) {
|
|
||||||
type = args[i + 1];
|
|
||||||
}
|
|
||||||
if (type == "glsl" || type == "hlsl") {
|
|
||||||
shaderDir = type;
|
|
||||||
} else {
|
|
||||||
std::cerr << args[i] << " must be one of 'glsl' or 'hlsl'" << std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Benchmark
|
|
||||||
if ((args[i] == std::string("-b")) || (args[i] == std::string("--benchmark"))) {
|
|
||||||
benchmark.active = true;
|
|
||||||
vks::tools::errorModeSilent = true;
|
|
||||||
}
|
|
||||||
// Warmup time (in seconds)
|
|
||||||
if ((args[i] == std::string("-bw")) || (args[i] == std::string("--benchwarmup"))) {
|
|
||||||
if (args.size() > i + 1) {
|
|
||||||
uint32_t num = strtol(args[i + 1], &numConvPtr, 10);
|
|
||||||
if (numConvPtr != args[i + 1]) {
|
|
||||||
benchmark.warmup = num;
|
|
||||||
} else {
|
|
||||||
std::cerr << "Warmup time for benchmark mode must be specified as a number!" << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Benchmark runtime (in seconds)
|
|
||||||
if ((args[i] == std::string("-br")) || (args[i] == std::string("--benchruntime"))) {
|
|
||||||
if (args.size() > i + 1) {
|
|
||||||
uint32_t num = strtol(args[i + 1], &numConvPtr, 10);
|
|
||||||
if (numConvPtr != args[i + 1]) {
|
|
||||||
benchmark.duration = num;
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
std::cerr << "Benchmark run duration must be specified as a number!" << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Bench result save filename (overrides default)
|
|
||||||
if ((args[i] == std::string("-bf")) || (args[i] == std::string("--benchfilename"))) {
|
|
||||||
if (args.size() > i + 1) {
|
|
||||||
if (args[i + 1][0] == '-') {
|
|
||||||
std::cerr << "Filename for benchmark results must not start with a hyphen!" << "\n";
|
|
||||||
} else {
|
|
||||||
benchmark.filename = args[i + 1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Output frame times to benchmark result file
|
|
||||||
if ((args[i] == std::string("-bt")) || (args[i] == std::string("--benchframetimes"))) {
|
|
||||||
benchmark.outputFrameTimes = true;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (commandLineParser.isSet("benchmark")) {
|
||||||
|
benchmark.active = true;
|
||||||
|
vks::tools::errorModeSilent = true;
|
||||||
|
}
|
||||||
|
if (commandLineParser.isSet("benchmarkwarmup")) {
|
||||||
|
benchmark.warmup = commandLineParser.getValueAsInt("benchmarkwarmup", benchmark.warmup);
|
||||||
|
}
|
||||||
|
if (commandLineParser.isSet("benchmarkruntime")) {
|
||||||
|
benchmark.duration = commandLineParser.getValueAsInt("benchmarkruntime", benchmark.duration);
|
||||||
|
}
|
||||||
|
if (commandLineParser.isSet("benchmarkresultfile")) {
|
||||||
|
benchmark.filename = commandLineParser.getValueAsString("benchmarkresultfile", benchmark.filename);
|
||||||
|
}
|
||||||
|
if (commandLineParser.isSet("benchmarkframetimes")) {
|
||||||
|
benchmark.outputFrameTimes = true;
|
||||||
|
}
|
||||||
|
|
||||||
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
#if defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||||
// Vulkan library is loaded dynamically on Android
|
// Vulkan library is loaded dynamically on Android
|
||||||
|
|
@ -793,11 +766,10 @@ VulkanExampleBase::VulkanExampleBase(bool enableValidation)
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
#if defined(_WIN32)
|
#if defined(_WIN32)
|
||||||
// Enable console if validation is active
|
// Enable console if validation is active, debug message callback will output to it
|
||||||
// Debug message callback will output to it
|
|
||||||
if (this->settings.validation)
|
if (this->settings.validation)
|
||||||
{
|
{
|
||||||
setupConsole("Vulkan validation output");
|
setupConsole("Vulkan example");
|
||||||
}
|
}
|
||||||
setupDPIAwareness();
|
setupDPIAwareness();
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -912,7 +884,10 @@ bool VulkanExampleBase::initVulkan()
|
||||||
uint32_t gpuCount = 0;
|
uint32_t gpuCount = 0;
|
||||||
// Get number of available physical devices
|
// Get number of available physical devices
|
||||||
VK_CHECK_RESULT(vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr));
|
VK_CHECK_RESULT(vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr));
|
||||||
assert(gpuCount > 0);
|
if (gpuCount == 0) {
|
||||||
|
vks::tools::exitFatal("No device with Vulkan support found", -1);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
// Enumerate devices
|
// Enumerate devices
|
||||||
std::vector<VkPhysicalDevice> physicalDevices(gpuCount);
|
std::vector<VkPhysicalDevice> physicalDevices(gpuCount);
|
||||||
err = vkEnumeratePhysicalDevices(instance, &gpuCount, physicalDevices.data());
|
err = vkEnumeratePhysicalDevices(instance, &gpuCount, physicalDevices.data());
|
||||||
|
|
@ -929,50 +904,22 @@ bool VulkanExampleBase::initVulkan()
|
||||||
|
|
||||||
#if !defined(VK_USE_PLATFORM_ANDROID_KHR)
|
#if !defined(VK_USE_PLATFORM_ANDROID_KHR)
|
||||||
// GPU selection via command line argument
|
// GPU selection via command line argument
|
||||||
for (size_t i = 0; i < args.size(); i++)
|
if (commandLineParser.isSet("gpuselection")) {
|
||||||
{
|
uint32_t index = commandLineParser.getValueAsInt("gpuselection", 0);
|
||||||
// Select GPU
|
if (index > gpuCount - 1) {
|
||||||
if ((args[i] == std::string("-g")) || (args[i] == std::string("-gpu")))
|
std::cerr << "Selected device index " << index << " is out of range, reverting to device 0 (use -listgpus to show available Vulkan devices)" << "\n";
|
||||||
{
|
} else {
|
||||||
char* endptr;
|
selectedDevice = index;
|
||||||
uint32_t index = strtol(args[i + 1], &endptr, 10);
|
|
||||||
if (endptr != args[i + 1])
|
|
||||||
{
|
|
||||||
if (index > gpuCount - 1)
|
|
||||||
{
|
|
||||||
std::cerr << "Selected device index " << index << " is out of range, reverting to device 0 (use -listgpus to show available Vulkan devices)" << "\n";
|
|
||||||
}
|
|
||||||
else
|
|
||||||
{
|
|
||||||
std::cout << "Selected Vulkan device " << index << "\n";
|
|
||||||
selectedDevice = index;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
// List available GPUs
|
}
|
||||||
if (args[i] == std::string("-listgpus"))
|
if (commandLineParser.isSet("gpulist")) {
|
||||||
{
|
std::cout << "Available Vulkan devices" << "\n";
|
||||||
uint32_t gpuCount = 0;
|
for (uint32_t i = 0; i < gpuCount; i++) {
|
||||||
VK_CHECK_RESULT(vkEnumeratePhysicalDevices(instance, &gpuCount, nullptr));
|
VkPhysicalDeviceProperties deviceProperties;
|
||||||
if (gpuCount == 0)
|
vkGetPhysicalDeviceProperties(physicalDevices[i], &deviceProperties);
|
||||||
{
|
std::cout << "Device [" << i << "] : " << deviceProperties.deviceName << std::endl;
|
||||||
std::cerr << "No Vulkan devices found!" << "\n";
|
std::cout << " Type: " << vks::tools::physicalDeviceTypeString(deviceProperties.deviceType) << "\n";
|
||||||
}
|
std::cout << " API: " << (deviceProperties.apiVersion >> 22) << "." << ((deviceProperties.apiVersion >> 12) & 0x3ff) << "." << (deviceProperties.apiVersion & 0xfff) << "\n";
|
||||||
else
|
|
||||||
{
|
|
||||||
// Enumerate devices
|
|
||||||
std::cout << "Available Vulkan devices" << "\n";
|
|
||||||
std::vector<VkPhysicalDevice> devices(gpuCount);
|
|
||||||
VK_CHECK_RESULT(vkEnumeratePhysicalDevices(instance, &gpuCount, devices.data()));
|
|
||||||
for (uint32_t j = 0; j < gpuCount; j++) {
|
|
||||||
VkPhysicalDeviceProperties deviceProperties;
|
|
||||||
vkGetPhysicalDeviceProperties(devices[j], &deviceProperties);
|
|
||||||
std::cout << "Device [" << j << "] : " << deviceProperties.deviceName << std::endl;
|
|
||||||
std::cout << " Type: " << vks::tools::physicalDeviceTypeString(deviceProperties.deviceType) << "\n";
|
|
||||||
std::cout << " API: " << (deviceProperties.apiVersion >> 22) << "." << ((deviceProperties.apiVersion >> 12) & 0x3ff) << "." << (deviceProperties.apiVersion & 0xfff) << "\n";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
|
@ -1036,6 +983,7 @@ void VulkanExampleBase::setupConsole(std::string title)
|
||||||
AllocConsole();
|
AllocConsole();
|
||||||
AttachConsole(GetCurrentProcessId());
|
AttachConsole(GetCurrentProcessId());
|
||||||
FILE *stream;
|
FILE *stream;
|
||||||
|
freopen_s(&stream, "CONIN$", "r", stdin);
|
||||||
freopen_s(&stream, "CONOUT$", "w+", stdout);
|
freopen_s(&stream, "CONOUT$", "w+", stdout);
|
||||||
freopen_s(&stream, "CONOUT$", "w+", stderr);
|
freopen_s(&stream, "CONOUT$", "w+", stderr);
|
||||||
SetConsoleTitle(TEXT(title.c_str()));
|
SetConsoleTitle(TEXT(title.c_str()));
|
||||||
|
|
@ -2759,3 +2707,103 @@ void VulkanExampleBase::setupSwapChain()
|
||||||
}
|
}
|
||||||
|
|
||||||
void VulkanExampleBase::OnUpdateUIOverlay(vks::UIOverlay *overlay) {}
|
void VulkanExampleBase::OnUpdateUIOverlay(vks::UIOverlay *overlay) {}
|
||||||
|
|
||||||
|
// Command line argument parser class
|
||||||
|
|
||||||
|
CommandLineParser::CommandLineParser()
|
||||||
|
{
|
||||||
|
add("help", { "--help" }, 0, "Show help");
|
||||||
|
add("validation", {"-v", "--validation"}, 0, "Enable validation layers");
|
||||||
|
add("vsync", {"-vs", "--vsync"}, 0, "Enable V-Sync");
|
||||||
|
add("fullscreen", { "-f", "--fullscreen" }, 0, "Start in fullscreen mode");
|
||||||
|
add("width", { "-w", "--width" }, 1, "Set window width");
|
||||||
|
add("height", { "-h", "--height" }, 1, "Set window height");
|
||||||
|
add("shaders", { "-s", "--shaders" }, 1, "Select shader type to use (glsl or hlsl)");
|
||||||
|
add("gpuselection", { "-g", "--gpu" }, 1, "Select GPU to run on");
|
||||||
|
add("gpulist", { "-gl", "--listgpus" }, 0, "Display a list of available Vulkan devices");
|
||||||
|
add("benchmark", { "-b", "--benchmark" }, 0, "Run example in benchmark mode");
|
||||||
|
add("benchmarkwarmup", { "-bw", "--benchwarmup" }, 1, "Set warmup time for benchmark mode in seconds");
|
||||||
|
add("benchmarkruntime", { "-br", "--benchruntime" }, 1, "Set duration time for benchmark mode in seconds");
|
||||||
|
add("benchmarkresultfile", { "-bf", "--benchfilename" }, 1, "Set file name for benchmark results");
|
||||||
|
add("benchmarkresultframes", { "-bt", "--benchframetimes" }, 1, "Save frame times to benchmark results file");
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandLineParser::add(std::string name, std::vector<std::string> commands, bool hasValue, std::string help)
|
||||||
|
{
|
||||||
|
options[name].commands = commands;
|
||||||
|
options[name].help = help;
|
||||||
|
options[name].set = false;
|
||||||
|
options[name].hasValue = hasValue;
|
||||||
|
options[name].value = "";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandLineParser::printHelp()
|
||||||
|
{
|
||||||
|
std::cout << "Available command line options:\n";
|
||||||
|
for (auto option : options) {
|
||||||
|
std::cout << " ";
|
||||||
|
for (size_t i = 0; i < option.second.commands.size(); i++) {
|
||||||
|
std::cout << option.second.commands[i];
|
||||||
|
if (i < option.second.commands.size() - 1) {
|
||||||
|
std::cout << ", ";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
std::cout << ": " << option.second.help << "\n";
|
||||||
|
}
|
||||||
|
std::cout << "Press any key to close...";
|
||||||
|
}
|
||||||
|
|
||||||
|
void CommandLineParser::parse(std::vector<const char*> arguments)
|
||||||
|
{
|
||||||
|
bool printHelp = false;
|
||||||
|
// Known arguments
|
||||||
|
for (auto& option : options) {
|
||||||
|
for (auto& command : option.second.commands) {
|
||||||
|
for (size_t i = 0; i < arguments.size(); i++) {
|
||||||
|
if (strcmp(arguments[i], command.c_str()) == 0) {
|
||||||
|
option.second.set = true;
|
||||||
|
// Get value
|
||||||
|
if (option.second.hasValue) {
|
||||||
|
if (arguments.size() > i + 1) {
|
||||||
|
option.second.value = arguments[i + 1];
|
||||||
|
}
|
||||||
|
if (option.second.value == "") {
|
||||||
|
printHelp = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
// Print help for unknown arguments or missing argument values
|
||||||
|
if (printHelp) {
|
||||||
|
options["help"].set = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool CommandLineParser::isSet(std::string name)
|
||||||
|
{
|
||||||
|
return ((options.find(name) != options.end()) && options[name].set);
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string CommandLineParser::getValueAsString(std::string name, std::string defaultValue)
|
||||||
|
{
|
||||||
|
assert(options.find(name) != options.end());
|
||||||
|
std::string value = options[name].value;
|
||||||
|
return (value != "") ? value : defaultValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
int32_t CommandLineParser::getValueAsInt(std::string name, int32_t defaultValue)
|
||||||
|
{
|
||||||
|
assert(options.find(name) != options.end());
|
||||||
|
std::string value = options[name].value;
|
||||||
|
if (value != "") {
|
||||||
|
char* numConvPtr;
|
||||||
|
int32_t intVal = strtol(value.c_str(), &numConvPtr, 10);
|
||||||
|
return (intVal > 0) ? intVal : defaultValue;
|
||||||
|
} else {
|
||||||
|
return defaultValue;
|
||||||
|
}
|
||||||
|
return int32_t();
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -37,6 +37,7 @@
|
||||||
#include <assert.h>
|
#include <assert.h>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <array>
|
#include <array>
|
||||||
|
#include <unordered_map>
|
||||||
#include <numeric>
|
#include <numeric>
|
||||||
#include <ctime>
|
#include <ctime>
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
@ -71,6 +72,26 @@
|
||||||
#include "camera.hpp"
|
#include "camera.hpp"
|
||||||
#include "benchmark.hpp"
|
#include "benchmark.hpp"
|
||||||
|
|
||||||
|
class CommandLineParser
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
struct CommandLineOption {
|
||||||
|
std::vector<std::string> commands;
|
||||||
|
std::string value;
|
||||||
|
bool hasValue = false;
|
||||||
|
std::string help;
|
||||||
|
bool set = false;
|
||||||
|
};
|
||||||
|
std::unordered_map<std::string, CommandLineOption> options;
|
||||||
|
CommandLineParser();
|
||||||
|
void add(std::string name, std::vector<std::string> commands, bool hasValue, std::string help);
|
||||||
|
void printHelp();
|
||||||
|
void parse(std::vector<const char*> arguments);
|
||||||
|
bool isSet(std::string name);
|
||||||
|
std::string getValueAsString(std::string name, std::string defaultValue);
|
||||||
|
int32_t getValueAsInt(std::string name, int32_t defaultValue);
|
||||||
|
};
|
||||||
|
|
||||||
class VulkanExampleBase
|
class VulkanExampleBase
|
||||||
{
|
{
|
||||||
private:
|
private:
|
||||||
|
|
@ -160,6 +181,7 @@ public:
|
||||||
uint32_t height = 720;
|
uint32_t height = 720;
|
||||||
|
|
||||||
vks::UIOverlay UIOverlay;
|
vks::UIOverlay UIOverlay;
|
||||||
|
CommandLineParser commandLineParser;
|
||||||
|
|
||||||
/** @brief Last frame time measured using a high performance timer (if available) */
|
/** @brief Last frame time measured using a high performance timer (if available) */
|
||||||
float frameTimer = 1.0f;
|
float frameTimer = 1.0f;
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue