1 #include <cstring>
2 #include "../../AppConfig.h"
3 #include "GSH_VulkanDeviceInfo.h"
4 #include "GSH_Vulkan.h"
5 #include "string_format.h"
6 
7 using namespace GSH_Vulkan;
8 
CDeviceInfo()9 CDeviceInfo::CDeviceInfo()
10 {
11 	CAppConfig::GetInstance().RegisterPreferenceInteger(PREF_CGSH_VULKAN_DEVICEID, 0);
12 	CAppConfig::GetInstance().RegisterPreferenceInteger(PREF_CGSH_VULKAN_VENDORID, 0);
13 
14 	PopulateDevices();
15 
16 	m_selectedDevice.deviceId = CAppConfig::GetInstance().GetPreferenceInteger(PREF_CGSH_VULKAN_DEVICEID);
17 	m_selectedDevice.vendorId = CAppConfig::GetInstance().GetPreferenceInteger(PREF_CGSH_VULKAN_VENDORID);
18 
19 	bool needsReset = (m_selectedDevice.deviceId == 0 || m_selectedDevice.vendorId == 0);
20 	needsReset |= !HasDevice(m_selectedDevice);
21 
22 	if(needsReset && HasAvailableDevices())
23 	{
24 		SetSelectedDevice(m_devices[0]);
25 	}
26 }
27 
PopulateDevices()28 void CDeviceInfo::PopulateDevices()
29 {
30 	assert(m_log.empty());
31 
32 	try
33 	{
34 		auto result = VK_SUCCESS;
35 
36 		//Create instance without validation layers to be as minimalist as possible
37 		auto instance = CGSH_Vulkan::CreateInstance(false);
38 
39 		uint32_t physicalDeviceCount = 0;
40 		result = instance.vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, nullptr);
41 		CHECKVULKANERROR(result);
42 
43 		std::vector<VkPhysicalDevice> physicalDevices(physicalDeviceCount);
44 		result = instance.vkEnumeratePhysicalDevices(instance, &physicalDeviceCount, physicalDevices.data());
45 		CHECKVULKANERROR(result);
46 
47 		for(const auto& physicalDevice : physicalDevices)
48 		{
49 			VkPhysicalDeviceProperties physicalDeviceProperties = {};
50 			instance.vkGetPhysicalDeviceProperties(physicalDevice, &physicalDeviceProperties);
51 
52 			m_log += "------------------------------------------\r\n";
53 			m_log += "Physical Device Info:\r\n";
54 			m_log += string_format("Driver Version: %d\r\n", physicalDeviceProperties.driverVersion);
55 			m_log += string_format("Vendor ID:      %d\r\n", physicalDeviceProperties.vendorID);
56 			m_log += string_format("Device ID:      %d\r\n", physicalDeviceProperties.deviceID);
57 			m_log += string_format("Device Name:    %s\r\n", physicalDeviceProperties.deviceName);
58 			m_log += string_format("Device Type:    %d\r\n", physicalDeviceProperties.deviceType);
59 			m_log += string_format("API Version:    %d.%d.%d\r\n",
60 			                       VK_VERSION_MAJOR(physicalDeviceProperties.apiVersion),
61 			                       VK_VERSION_MINOR(physicalDeviceProperties.apiVersion),
62 			                       VK_VERSION_PATCH(physicalDeviceProperties.apiVersion));
63 
64 			uint32_t propertyCount = 0;
65 			result = instance.vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &propertyCount, nullptr);
66 			CHECKVULKANERROR(result);
67 
68 			std::vector<VkExtensionProperties> properties(propertyCount);
69 			result = instance.vkEnumerateDeviceExtensionProperties(physicalDevice, nullptr, &propertyCount, properties.data());
70 			CHECKVULKANERROR(result);
71 
72 			auto propertyIterator = std::find_if(properties.begin(), properties.end(), [](const auto& property) { return (strcmp(property.extensionName, VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME) == 0); });
73 			if(propertyIterator == std::end(properties))
74 			{
75 				m_log += "Device not suitable: Doesn't support " VK_EXT_FRAGMENT_SHADER_INTERLOCK_EXTENSION_NAME ".";
76 			}
77 			else
78 			{
79 				m_devices.push_back({physicalDeviceProperties.deviceName, physicalDeviceProperties.vendorID, physicalDeviceProperties.deviceID});
80 			}
81 
82 			m_log += "\r\n\r\n";
83 		}
84 	}
85 	catch(const std::exception& exception)
86 	{
87 		m_log += string_format("Got exception while scanning devices: %s.\r\n", exception.what());
88 	}
89 }
90 
HasDevice(const VULKAN_DEVICE & deviceToTest) const91 bool CDeviceInfo::HasDevice(const VULKAN_DEVICE& deviceToTest) const
92 {
93 	for(const auto& device : m_devices)
94 	{
95 		if(
96 		    (device.deviceId == deviceToTest.deviceId) &&
97 		    (device.vendorId == deviceToTest.vendorId))
98 		{
99 			return true;
100 		}
101 	}
102 	return false;
103 }
104 
GetAvailableDevices() const105 DeviceList CDeviceInfo::GetAvailableDevices() const
106 {
107 	return m_devices;
108 }
109 
GetSelectedDevice() const110 VULKAN_DEVICE CDeviceInfo::GetSelectedDevice() const
111 {
112 	assert(HasDevice(m_selectedDevice));
113 	return m_selectedDevice;
114 }
115 
SetSelectedDevice(const VULKAN_DEVICE & device)116 void CDeviceInfo::SetSelectedDevice(const VULKAN_DEVICE& device)
117 {
118 	m_selectedDevice = device;
119 	CAppConfig::GetInstance().SetPreferenceInteger(PREF_CGSH_VULKAN_DEVICEID, m_selectedDevice.deviceId);
120 	CAppConfig::GetInstance().SetPreferenceInteger(PREF_CGSH_VULKAN_VENDORID, m_selectedDevice.vendorId);
121 }
122 
HasAvailableDevices() const123 bool CDeviceInfo::HasAvailableDevices() const
124 {
125 	return !m_devices.empty();
126 }
127 
GetLog() const128 std::string CDeviceInfo::GetLog() const
129 {
130 	return m_log;
131 }
132