Ubuntu 16.04, Vulkan SDK 1.0.65.0, Beta Driver 387.42.01 (same Behavior with genereal release driver 387.34).
3 GPUs in a dual CPU system (i.e. 2 GPUs on one CPU, 1 on the other).
vkEnumeratePhysicalDevices lists only 1 of the GPUs if the program is run from an X environment.
If the same program is run from the TTY (i.e. Ctrl+Alt+1 into text mode), it lists all 3 GPUs. The X server does not have to be shut down.
VkDeviceProerties for the GPU found from X environment:
Device 0
apiVersion 0x400042
driverVersion 0x60ca8040
vendorID 0x10de
deviceID 0x17c2
deviceType 2
deviceName GeForce GTX TITAN X
VkDeviceProerties for the GPUs found from TTY:
Device 0
apiVersion 0x400042
driverVersion 0x60ca8040
vendorID 0x10de
deviceID 0x17c2
deviceType 2
deviceName GeForce GTX TITAN X
Device 1
apiVersion 0x400042
driverVersion 0x60ca8040
vendorID 0x10de
deviceID 0x17c2
deviceType 2
deviceName GeForce GTX TITAN X
Device 2
apiVersion 0x400042
driverVersion 0x60ca8040
vendorID 0x10de
deviceID 0x17c2
deviceType 2
deviceName GeForce GTX TITAN X
nvidia-smi:
+-----------------------------------------------------------------------------+
| NVIDIA-SMI 387.42.01 Driver Version: 387.42.01 |
|-------------------------------+----------------------+----------------------+
| GPU Name Persistence-M| Bus-Id Disp.A | Volatile Uncorr. ECC |
| Fan Temp Perf Pwr:Usage/Cap| Memory-Usage | GPU-Util Compute M. |
|===============================+======================+======================|
| 0 GeForce GTX TIT... Off | 00000000:03:00.0 On | N/A |
| 29% 71C P0 80W / 250W | 614MiB / 12205MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 1 GeForce GTX TIT... Off | 00000000:81:00.0 Off | N/A |
| 22% 56C P8 16W / 250W | 1MiB / 12207MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
| 2 GeForce GTX TIT... Off | 00000000:82:00.0 Off | N/A |
| 23% 62C P8 18W / 250W | 1MiB / 12207MiB | 0% Default |
+-------------------------------+----------------------+----------------------+
+-----------------------------------------------------------------------------+
| Processes: GPU Memory |
| GPU PID Type Process name Usage |
|=============================================================================|
| 0 1375 G /usr/lib/xorg/Xorg 388MiB |
| 0 2651 G compiz 221MiB |
+-----------------------------------------------------------------------------+
Note that vulkaninfo cannot be used to query device data from TTY, since it terminates with an error if run outside an X env. The following program can be used instead:
// #!/bin/bash
// VULKAN_SDK_HOME=~/VulkanSDK/1.0.65.0/x86_64
// g++ \
// -std=c++14 \
// -I $VULKAN_SDK_HOME/include/ \
// vk_properties.cc \
// -L $VULKAN_SDK_HOME/lib/ \
// -lvulkan \
// -Wl,-rpath,$VULKAN_SDK_HOME/lib \
// -o vk_properties
#include <vulkan/vulkan.h>
#include <iostream>
#include <sstream>
#include <vector>
namespace vulkan {
inline void handle_vulkan_result(VkResult result, const char* file, const char* func, int line) {
if ( VK_SUCCESS != result ) {
std::ostringstream ostr;
ostr << "VkResult(" << result << ") in " << file << ":" << func << ":" << line;
throw std::runtime_error(ostr.str());
}
}
#define VK_CALL(x) vulkan::handle_vulkan_result((x), __FILE__, __FUNCTION__, __LINE__)
class Instance {
public:
Instance(const Instance&) = delete;
Instance(Instance&& rhs) : instance_(rhs.instance_) {
rhs.instance_ = nullptr;
}
Instance(const VkInstanceCreateInfo& create_info) {
VK_CALL(vkCreateInstance(&create_info, nullptr, &instance_));
}
~Instance() {
vkDestroyInstance(instance_, nullptr);
}
operator VkInstance() const noexcept {
return instance_;
}
private:
VkInstance instance_{};
};
template<class Item>
class EnumerationContainer {
public:
template<class CountCall, class ListCall>
EnumerationContainer(CountCall&& count_call, ListCall&& list_call) {
items_.resize(count_call());
try {
list_call(items_);
}
catch ( ... ) {
items_.clear();
throw;
}
}
auto begin() const noexcept {
return items_.begin();
}
auto end() const noexcept {
return items_.end();
}
auto size() const noexcept {
return items_.size();
}
bool empty() const noexcept {
return items_.empty();
}
private:
std::vector<Item> items_;
};
class ExtensionProperties : public EnumerationContainer<VkExtensionProperties> {
public:
ExtensionProperties() :
EnumerationContainer<VkExtensionProperties>(
[] {
uint32_t count = 0;
VK_CALL(vkEnumerateInstanceExtensionProperties(nullptr, &count, nullptr));
return count;
},
[](auto& vector) {
uint32_t count = vector.size();
VK_CALL(vkEnumerateInstanceExtensionProperties(nullptr, &count, vector.data()));
}
)
{}
};
class LayerProperties : public EnumerationContainer<VkLayerProperties> {
public:
LayerProperties() :
EnumerationContainer<VkLayerProperties>(
[] {
uint32_t count = 0;
VK_CALL(vkEnumerateInstanceLayerProperties(&count, nullptr));
return count;
},
[](auto& vector) {
uint32_t count = vector.size();
VK_CALL(vkEnumerateInstanceLayerProperties(&count, vector.data()));
}
)
{}
};
class PhysicalDevices : public EnumerationContainer<VkPhysicalDevice> {
public:
PhysicalDevices(VkInstance instance) :
EnumerationContainer<VkPhysicalDevice>(
[instance] {
uint32_t count = 0;
VK_CALL(vkEnumeratePhysicalDevices(instance, &count, nullptr));
return count;
},
[instance](auto& vector) {
uint32_t count = vector.size();
VK_CALL(vkEnumeratePhysicalDevices(instance, &count, vector.data()));
}
)
{}
};
} // namespace vulkan
vulkan::Instance create_instance() {
VkApplicationInfo app_info{};
app_info.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO;
VkInstanceCreateInfo create_info{};
create_info.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
create_info.pApplicationInfo = &app_info;
return vulkan::Instance(create_info);
}
int main() {
try {
auto extensions = vulkan::ExtensionProperties();
std::cout << "Extensions (" << extensions.size() << ")" << std::endl;
for ( auto& ext : extensions )
std::cout << " " << ext.extensionName << " v" << ext.specVersion << std::endl;
auto layers = vulkan::LayerProperties();
std::cout << "Layers (" << layers.size() << ")" << std::endl;
for ( auto& layer : layers ) {
std::cout << " " << layer.layerName << " spec v" << layer.specVersion
<< " impl v" << layer.implementationVersion << std::endl
<< " " << layer.description << std::endl;
}
auto instance = create_instance();
int dev_idx = 0;
for ( auto device : vulkan::PhysicalDevices(instance) ) {
VkPhysicalDeviceProperties props = {};
vkGetPhysicalDeviceProperties(device, &props);
std::cout << "Device " << dev_idx++ << std::endl
<< " apiVersion 0x" << std::hex << props.apiVersion << std::endl
<< " driverVersion 0x" << std::hex << props.driverVersion << std::endl
<< " vendorID 0x" << std::hex << props.vendorID << std::endl
<< " deviceID 0x" << std::hex << props.deviceID << std::endl
<< " deviceType " << props.deviceType << std::endl
<< " deviceName " << props.deviceName << std::endl;
}
return 0;
}
catch ( const std::exception& e ) {
std::cerr << "Exception caught in main: " << e.what() << std::endl;
return 1;
}
catch ( ... ) {
std::cerr << "Unknown exception caught in main" << std::endl;
return 1;
}
}