Permalink
Browse files

Improve Vulkan device selection mechanism to prefer discrete GPUs

  • Loading branch information...
hrydgard committed Nov 9, 2017
1 parent c855ab6 commit c6c90d4cbcdd77e4a2b799ebcc6c0a0cb020136c
Showing with 61 additions and 12 deletions.
  1. +42 −9 Common/Vulkan/VulkanContext.cpp
  2. +10 −2 Common/Vulkan/VulkanContext.h
  3. +9 −1 android/jni/app-android.cpp
@@ -120,6 +120,11 @@ VkResult VulkanContext::CreateInstance(const char *app_name, int app_ver, uint32
}
VulkanLoadInstanceFunctions(instance_);
if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) {
WLOG("CheckLayers for instance failed");
// init_error_ = "Failed to validate instance layers";
// return;
}
uint32_t gpu_count = 1;
res = vkEnumeratePhysicalDevices(instance_, &gpu_count, nullptr);
@@ -141,11 +146,6 @@ VkResult VulkanContext::CreateInstance(const char *app_name, int app_ver, uint32
return res;
}
if (!CheckLayers(instance_layer_properties_, instance_layer_names_)) {
WLOG("CheckLayers failed");
// init_error_ = "Failed to validate instance layers";
// return;
}
return VK_SUCCESS;
}
@@ -333,14 +333,47 @@ bool VulkanContext::CheckLayers(const std::vector<LayerProperties> &layer_props,
return true;
}
int VulkanContext::GetBestPhysicalDevice() {
// Rules: Prefer discrete over embedded.
// Prefer nVidia over Intel.
int maxScore = -1;
int best = -1;
for (size_t i = 0; i < physical_devices_.size(); i++) {
int score = 0;
VkPhysicalDeviceProperties props;
vkGetPhysicalDeviceProperties(physical_devices_[i], &props);
switch (props.deviceType) {
case VK_PHYSICAL_DEVICE_TYPE_CPU:
score += 1;
break;
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
score += 20;
break;
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
score += 10;
break;
}
if (props.vendorID == VULKAN_VENDOR_AMD) {
score += 5;
} else if (props.vendorID == VULKAN_VENDOR_NVIDIA) {
score += 5;
}
if (score > maxScore) {
best = i;
maxScore = score;
}
}
return best;
}
void VulkanContext::ChooseDevice(int physical_device) {
physical_device_ = physical_device;
GetDeviceLayerProperties();
if (!CheckLayers(device_layer_properties_, device_layer_names_)) {
WLOG("CheckLayers failed (2)");
// init_error_ = "Failed to validate device layers";
// return;
WLOG("CheckLayers for device %d failed", physical_device);
}
vkGetPhysicalDeviceQueueFamilyProperties(physical_devices_[physical_device_], &queue_count, nullptr);
@@ -913,4 +946,4 @@ const char *VulkanResultToString(VkResult res) {
default:
return "VK_ERROR_...(unknown)";
}
}
}
@@ -43,6 +43,15 @@ enum {
VULKAN_FLAG_PRESENT_FIFO_RELAXED = 8,
};
enum {
VULKAN_VENDOR_NVIDIA = 0x000010de,
VULKAN_VENDOR_INTEL = 0x00008086, // Haha!
VULKAN_VENDOR_AMD = 0x00001002,
VULKAN_VENDOR_ARM = 0x000013B5, // Mali
VULKAN_VENDOR_QUALCOMM = 0x00005143,
VULKAN_VENDOR_IMGTEC = 0x00001010, // PowerVR
};
struct VulkanPhysicalDeviceInfo {
VkFormat preferredDepthStencilFormat;
};
@@ -203,8 +212,7 @@ class VulkanContext {
VkResult CreateInstance(const char *app_name, int app_ver, uint32_t flags);
// TODO: Actually do some checks?
int GetBestPhysicalDevice() const { return 0; }
int GetBestPhysicalDevice();
void ChooseDevice(int physical_device);
bool EnableDeviceExtension(const char *extension);
VkResult CreateDevice();
@@ -290,7 +290,15 @@ bool AndroidVulkanContext::Init(ANativeWindow *wnd, int desiredBackbufferSizeX,
return false;
}
g_Vulkan->ChooseDevice(g_Vulkan->GetBestPhysicalDevice());
int physicalDevice = g_Vulkan->GetBestPhysicalDevice();
if (physicalDevice < 0) {
ELOG("No usable Vulkan device found.");
delete g_Vulkan;
g_Vulkan = nullptr;
return false;
}
g_Vulkan->ChooseDevice(physicalDevice);
// Here we can enable device extensions if we like.
ILOG("Creating vulkan device");

0 comments on commit c6c90d4

Please sign in to comment.