Skip to content

Commit

Permalink
Add Vulkan device selection support (google#698)
Browse files Browse the repository at this point in the history
Add the `-D` command line option for selecting a physical Vulkan
device to run with. Only choose from enumerated physical devices
in ChooseVulkanPhysicalDevice and move feature and extension checks
to a new CheckVulkanPhysicalDeviceRequirements function.

Issue google#619
  • Loading branch information
mvainola authored and dj2 committed Oct 28, 2019
1 parent 40fce11 commit 34bb13d
Show file tree
Hide file tree
Showing 7 changed files with 130 additions and 69 deletions.
17 changes: 17 additions & 0 deletions samples/amber.cc
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@ struct Options {
uint32_t engine_major = 1;
uint32_t engine_minor = 0;
int32_t fence_timeout = -1;
int32_t selected_device = -1;
bool parse_only = false;
bool pipeline_create_only = false;
bool disable_validation_layer = false;
Expand All @@ -70,6 +71,7 @@ const char kUsage[] = R"(Usage: amber [options] SCRIPT [SCRIPTS...]
-ps -- Parse input files, create pipelines; Don't execute.
-q -- Disable summary output.
-d -- Disable validation layers.
-D <ID> -- ID of device to run with (Vulkan only).
-f <value> -- Sets the fence timeout value to |value|
-t <spirv_env> -- The target SPIR-V environment e.g., spv1.3, vulkan1.1.
If a SPIR-V environment, assume the lowest version of Vulkan that
Expand Down Expand Up @@ -146,6 +148,20 @@ bool ParseArgs(const std::vector<std::string>& args, Options* opts) {
<< std::endl;
return false;
}
} else if (arg == "-D") {
++i;
if (i >= args.size()) {
std::cerr << "Missing ID for -D argument." << std::endl;
return false;
}

int32_t val = std::stoi(std::string(args[i]));
if (val < 0) {
std::cerr << "Device ID must be non-negative" << std::endl;
return false;
}
opts->selected_device = val;

} else if (arg == "-f") {
++i;
if (i >= args.size()) {
Expand Down Expand Up @@ -405,6 +421,7 @@ int main(int argc, const char** argv) {

amber::Result r = config_helper.CreateConfig(
amber_options.engine, options.engine_major, options.engine_minor,
options.selected_device,
std::vector<std::string>(required_features.begin(),
required_features.end()),
std::vector<std::string>(required_instance_extensions.begin(),
Expand Down
3 changes: 2 additions & 1 deletion samples/config_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -40,6 +40,7 @@ amber::Result ConfigHelper::CreateConfig(
amber::EngineType engine,
uint32_t engine_major,
uint32_t engine_minor,
int32_t selected_device,
const std::vector<std::string>& required_features,
const std::vector<std::string>& required_instance_extensions,
const std::vector<std::string>& required_device_extensions,
Expand Down Expand Up @@ -67,7 +68,7 @@ amber::Result ConfigHelper::CreateConfig(
return amber::Result("Unable to create config helper");

return impl_->CreateConfig(
engine_major, engine_minor, required_features,
engine_major, engine_minor, selected_device, required_features,
required_instance_extensions, required_device_extensions,
disable_validation_layer, show_version_info, config);
}
Expand Down
2 changes: 2 additions & 0 deletions samples/config_helper.h
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ class ConfigHelperImpl {
virtual amber::Result CreateConfig(
uint32_t engine_major,
uint32_t engine_minor,
int32_t selected_device,
const std::vector<std::string>& required_features,
const std::vector<std::string>& required_instance_extensions,
const std::vector<std::string>& required_device_extensions,
Expand All @@ -58,6 +59,7 @@ class ConfigHelper {
amber::EngineType engine,
uint32_t engine_major,
uint32_t engine_minor,
int32_t selected_device,
const std::vector<std::string>& required_features,
const std::vector<std::string>& required_instance_extensions,
const std::vector<std::string>& required_device_extensions,
Expand Down
1 change: 1 addition & 0 deletions samples/config_helper_dawn.cc
Original file line number Diff line number Diff line change
Expand Up @@ -51,6 +51,7 @@ void PrintDeviceError(DawnErrorType errorType, const char* message, void*) {
amber::Result ConfigHelperDawn::CreateConfig(
uint32_t,
uint32_t,
int32_t,
const std::vector<std::string>&,
const std::vector<std::string>&,
const std::vector<std::string>&,
Expand Down
1 change: 1 addition & 0 deletions samples/config_helper_dawn.h
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@ class ConfigHelperDawn : public ConfigHelperImpl {
amber::Result CreateConfig(
uint32_t engine_major,
uint32_t engine_minor,
int32_t selected_device,
const std::vector<std::string>& required_features,
const std::vector<std::string>& required_instance_extensions,
const std::vector<std::string>& required_device_extensions,
Expand Down
164 changes: 97 additions & 67 deletions samples/config_helper_vulkan.cc
Original file line number Diff line number Diff line change
Expand Up @@ -699,9 +699,85 @@ amber::Result ConfigHelperVulkan::CreateDebugReportCallback() {
return {};
}

amber::Result ConfigHelperVulkan::ChooseVulkanPhysicalDevice(
amber::Result ConfigHelperVulkan::CheckVulkanPhysicalDeviceRequirements(
const VkPhysicalDevice physical_device,
const std::vector<std::string>& required_features,
const std::vector<std::string>& required_extensions) {
VkPhysicalDeviceFeatures required_vulkan_features =
VkPhysicalDeviceFeatures();

if (use_physical_device_features2_) {
VkPhysicalDeviceVariablePointerFeaturesKHR var_ptrs =
VkPhysicalDeviceVariablePointerFeaturesKHR();
var_ptrs.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
var_ptrs.pNext = nullptr;

VkPhysicalDeviceFeatures2KHR features2 = VkPhysicalDeviceFeatures2KHR();
features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
features2.pNext = &var_ptrs;

auto vkGetPhysicalDeviceFeatures2KHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
vkGetInstanceProcAddr(vulkan_instance_,
"vkGetPhysicalDeviceFeatures2KHR"));
vkGetPhysicalDeviceFeatures2KHR(physical_device, &features2);
available_features_ = features2.features;

std::vector<std::string> required_features1;
for (const auto& feature : required_features) {
// No dot means this is a features1 feature.
if (feature.find_first_of('.') == std::string::npos) {
required_features1.push_back(feature);
continue;
}

if (feature == kVariablePointers &&
var_ptrs.variablePointers != VK_TRUE) {
continue;
}
if (feature == kVariablePointersStorageBuffer &&
var_ptrs.variablePointersStorageBuffer != VK_TRUE) {
continue;
}
}

amber::Result r =
NamesToVulkanFeatures(required_features1, &required_vulkan_features);
if (!r.IsSuccess())
return r;

} else {
amber::Result r =
NamesToVulkanFeatures(required_features, &required_vulkan_features);
if (!r.IsSuccess())
return r;

vkGetPhysicalDeviceFeatures(physical_device, &available_features_);
}
if (!AreAllRequiredFeaturesSupported(available_features_,
required_vulkan_features)) {
return amber::Result("Device does not support all required features");
}

available_device_extensions_ = GetAvailableDeviceExtensions(physical_device);
if (!AreAllExtensionsSupported(available_device_extensions_,
required_extensions)) {
return amber::Result("Device does not support all required extensions");
}

vulkan_queue_family_index_ = ChooseQueueFamilyIndex(physical_device);
if (vulkan_queue_family_index_ == std::numeric_limits<uint32_t>::max()) {
return amber::Result("Device does not support required queue flags");
}

return {};
}

amber::Result ConfigHelperVulkan::ChooseVulkanPhysicalDevice(
const std::vector<std::string>& required_features,
const std::vector<std::string>& required_extensions,
const int32_t selected_device) {
uint32_t count = 0;
std::vector<VkPhysicalDevice> physical_devices;

Expand All @@ -716,72 +792,24 @@ amber::Result ConfigHelperVulkan::ChooseVulkanPhysicalDevice(
return amber::Result("Unable to enumerate physical devices");
}

VkPhysicalDeviceFeatures required_vulkan_features =
VkPhysicalDeviceFeatures();
for (uint32_t i = 0; i < count; ++i) {
if (use_physical_device_features2_) {
VkPhysicalDeviceVariablePointerFeaturesKHR var_ptrs =
VkPhysicalDeviceVariablePointerFeaturesKHR();
var_ptrs.sType =
VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_VARIABLE_POINTER_FEATURES_KHR;
var_ptrs.pNext = nullptr;

VkPhysicalDeviceFeatures2KHR features2 = VkPhysicalDeviceFeatures2KHR();
features2.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2_KHR;
features2.pNext = &var_ptrs;

auto vkGetPhysicalDeviceFeatures2KHR =
reinterpret_cast<PFN_vkGetPhysicalDeviceFeatures2KHR>(
vkGetInstanceProcAddr(vulkan_instance_,
"vkGetPhysicalDeviceFeatures2KHR"));
vkGetPhysicalDeviceFeatures2KHR(physical_devices[i], &features2);
available_features_ = features2.features;

std::vector<std::string> required_features1;
for (const auto& feature : required_features) {
// No dot means this is a features1 feature.
if (feature.find_first_of('.') == std::string::npos) {
required_features1.push_back(feature);
continue;
}

if (feature == kVariablePointers &&
var_ptrs.variablePointers != VK_TRUE) {
continue;
}
if (feature == kVariablePointersStorageBuffer &&
var_ptrs.variablePointersStorageBuffer != VK_TRUE) {
continue;
}
}

amber::Result r =
NamesToVulkanFeatures(required_features1, &required_vulkan_features);
if (!r.IsSuccess())
return r;

} else {
amber::Result r =
NamesToVulkanFeatures(required_features, &required_vulkan_features);
if (!r.IsSuccess())
return r;

vkGetPhysicalDeviceFeatures(physical_devices[i], &available_features_);
}
if (!AreAllRequiredFeaturesSupported(available_features_,
required_vulkan_features)) {
continue;
}

available_device_extensions_ =
GetAvailableDeviceExtensions(physical_devices[i]);
if (!AreAllExtensionsSupported(available_device_extensions_,
required_extensions)) {
continue;
if (selected_device > -1) {
uint32_t deviceID = static_cast<uint32_t>(selected_device);
if (deviceID >= count) {
return amber::Result("Unable to find Vulkan device with ID " +
std::to_string(deviceID));
}

vulkan_queue_family_index_ = ChooseQueueFamilyIndex(physical_devices[i]);
if (vulkan_queue_family_index_ != std::numeric_limits<uint32_t>::max()) {
amber::Result r = CheckVulkanPhysicalDeviceRequirements(
physical_devices[deviceID], required_features, required_extensions);
if (!r.IsSuccess())
return r;
vulkan_physical_device_ = physical_devices[deviceID];
return {};
} else {
for (uint32_t i = 0; i < count; ++i) {
amber::Result r = CheckVulkanPhysicalDeviceRequirements(
physical_devices[i], required_features, required_extensions);
if (!r.IsSuccess())
continue;
vulkan_physical_device_ = physical_devices[i];
return {};
}
Expand Down Expand Up @@ -909,6 +937,7 @@ void ConfigHelperVulkan::DumpPhysicalDeviceInfo() {
amber::Result ConfigHelperVulkan::CreateConfig(
uint32_t engine_major,
uint32_t engine_minor,
int32_t selected_device,
const std::vector<std::string>& required_features,
const std::vector<std::string>& required_instance_extensions,
const std::vector<std::string>& required_device_extensions,
Expand All @@ -927,7 +956,8 @@ amber::Result ConfigHelperVulkan::CreateConfig(
return r;
}

r = ChooseVulkanPhysicalDevice(required_features, required_device_extensions);
r = ChooseVulkanPhysicalDevice(required_features, required_device_extensions,
selected_device);
if (!r.IsSuccess())
return r;

Expand Down
11 changes: 10 additions & 1 deletion samples/config_helper_vulkan.h
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ class ConfigHelperVulkan : public ConfigHelperImpl {
amber::Result CreateConfig(
uint32_t engine_major,
uint32_t engine_minor,
int32_t selected_device,
const std::vector<std::string>& required_features,
const std::vector<std::string>& required_instance_extensions,
const std::vector<std::string>& required_device_extensions,
Expand All @@ -63,11 +64,19 @@ class ConfigHelperVulkan : public ConfigHelperImpl {
/// via debugCallback() function in config_helper_vulkan.cc.
amber::Result CreateDebugReportCallback();

/// Check if |physical_device| supports both
/// |required_features| and |required_extensions|.
amber::Result CheckVulkanPhysicalDeviceRequirements(
const VkPhysicalDevice physical_device,
const std::vector<std::string>& required_features,
const std::vector<std::string>& required_extensions);

/// Choose Vulkan physical device that supports both
/// |required_features| and |required_extensions|.
amber::Result ChooseVulkanPhysicalDevice(
const std::vector<std::string>& required_features,
const std::vector<std::string>& required_extensions);
const std::vector<std::string>& required_extensions,
const int32_t selected_device);

/// Create Vulkan logical device that enables both
/// |required_features| and |required_extensions|.
Expand Down

0 comments on commit 34bb13d

Please sign in to comment.