Do more detailed checks for Vulkan availability. Should hopefully solve #10729.

This commit is contained in:
Henrik Rydgård committed 2018-03-17 11:36:16 +01:00
1 parent 1bb7be489f
commit 08c3e13517
5 files changed
+117 -10

No files matched your search

+1
View File
@@ -579,6 +579,7 @@ VkResult VulkanContext::CreateDevice() {
VulkanLoadDeviceFunctions(device_);
}
ILOG("Device created.\n");
VulkanSetAvailable(true);
return res;
}
+111 -8
View File
@@ -16,6 +16,7 @@
// https://github.com/hrydgard/ppsspp and http://www.ppsspp.org/.
#include "Common/Vulkan/VulkanLoader.h"
#include <vector>
#include "base/logging.h"
#include "base/basictypes.h"
@@ -203,37 +204,139 @@ static HINSTANCE vulkanLibrary;
static void *vulkanLibrary;
#endif
bool g_vulkanAvailabilityChecked = false;
bool g_vulkanMayBeAvailable = false;
#define LOAD_INSTANCE_FUNC(instance, x) x = (PFN_ ## x)vkGetInstanceProcAddr(instance, #x); if (!x) {ILOG("Missing (instance): %s", #x);}
#define LOAD_DEVICE_FUNC(instance, x) x = (PFN_ ## x)vkGetDeviceProcAddr(instance, #x); if (!x) {ILOG("Missing (device): %s", #x);}
#define LOAD_GLOBAL_FUNC(x) x = (PFN_ ## x)dlsym(vulkanLibrary, #x); if (!x) {ILOG("Missing (global): %s", #x);}
#define LOAD_GLOBAL_FUNC_LOCAL(lib, x) (PFN_ ## x)dlsym(lib, #x);
static const char *so_names[] = {
"libvulkan.so",
"libvulkan.so.1",
};
void VulkanSetAvailable(bool available) {
g_vulkanAvailabilityChecked = true;
g_vulkanMayBeAvailable = available;
}
bool VulkanMayBeAvailable() {
if (vulkanLibrary)
return true;
if (g_vulkanAvailabilityChecked)
return g_vulkanMayBeAvailable;
bool available = false;
#ifndef _WIN32
void *lib = nullptr;
for (int i = 0; i < ARRAY_SIZE(so_names); i++) {
void *lib = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL);
lib = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL);
if (lib) {
available = true;
dlclose(lib);
break;
}
}
#else
// LoadLibrary etc
HINSTANCE lib = LoadLibrary(L"vulkan-1.dll");
available = lib != 0;
if (lib) {
FreeLibrary(lib);
}
#endif
return available;
// Do a hyper minimal initialization and teardown to figure out if there's any chance
// that any sort of Vulkan will be usable.
PFN_vkCreateInstance localCreateInstance = LOAD_GLOBAL_FUNC_LOCAL(lib, vkCreateInstance);
PFN_vkEnumeratePhysicalDevices localEnumerate = LOAD_GLOBAL_FUNC_LOCAL(lib, vkEnumeratePhysicalDevices);
PFN_vkDestroyInstance localDestroyInstance = LOAD_GLOBAL_FUNC_LOCAL(lib, vkDestroyInstance);
PFN_vkGetPhysicalDeviceProperties localGetPhysicalDeviceProperties = LOAD_GLOBAL_FUNC_LOCAL(lib, vkGetPhysicalDeviceProperties);
// Need to predeclare all this because of the gotos...
VkInstanceCreateInfo ci{ VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO };
VkApplicationInfo info{ VK_STRUCTURE_TYPE_APPLICATION_INFO };
std::vector<VkPhysicalDevice> devices;
bool anyGood;
const char *instanceExtensions[1];
int extCount = 0;
VkInstance instance = VK_NULL_HANDLE;
VkResult res;
uint32_t physicalDeviceCount = 0;
if (!localCreateInstance || !localEnumerate || !localDestroyInstance || !localGetPhysicalDeviceProperties)
goto bail;
#ifdef _WIN32
instanceExtensions[0] = VK_KHR_WIN32_SURFACE_EXTENSION_NAME;
ci.enabledExtensionCount = 1;
#elif defined(__ANDROID__)
instanceExtensions[0] = VK_KHR_ANDROID_SURFACE_EXTENSION_NAME;
ci.enabledExtensionCount = 1;
#endif
ci.ppEnabledExtensionNames = instanceExtensions;
ci.enabledLayerCount = 0;
info.apiVersion = VK_API_VERSION_1_0;
info.applicationVersion = 1;
info.engineVersion = 1;
info.pApplicationName = "VulkanChecker";
info.pEngineName = "VulkanChecker";
ci.pApplicationInfo = &info;
ci.flags = 0;
res = localCreateInstance(&ci, nullptr, &instance);
if (res != VK_SUCCESS) {
ELOG("Failed to create vulkan instance.");
goto bail;
}
ILOG("Vulkan test instance created successfully.");
res = localEnumerate(instance, &physicalDeviceCount, nullptr);
if (res != VK_SUCCESS) {
ELOG("Failed to count physical devices.");
goto bail;
}
if (physicalDeviceCount == 0) {
ELOG("No physical Vulkan devices.");
goto bail;
}
devices.resize(physicalDeviceCount);
res = localEnumerate(instance, &physicalDeviceCount, devices.data());
if (res != VK_SUCCESS) {
ELOG("Failed to enumerate physical devices.");
goto bail;
}
anyGood = false;
for (auto device : devices) {
VkPhysicalDeviceProperties props;
localGetPhysicalDeviceProperties(device, &props);
switch (props.deviceType) {
case VK_PHYSICAL_DEVICE_TYPE_DISCRETE_GPU:
case VK_PHYSICAL_DEVICE_TYPE_INTEGRATED_GPU:
case VK_PHYSICAL_DEVICE_TYPE_VIRTUAL_GPU:
anyGood = true;
break;
}
// TODO: Should also check queuefamilyproperties for a GRAPHICS queue family? Oh well.
}
if (!anyGood) {
WLOG("Found Vulkan API, but no good Vulkan device!");
g_vulkanMayBeAvailable = false;
} else {
ILOG("Found working Vulkan API!");
g_vulkanMayBeAvailable = true;
}
bail:
g_vulkanAvailabilityChecked = true;
if (instance) {
localDestroyInstance(instance, nullptr);
}
if (lib) {
#ifndef _WIN32
dlclose(lib);
#else
FreeLibrary(lib);
#endif
} else {
ELOG("Vulkan with working device not detected.");
}
return g_vulkanMayBeAvailable;
}
bool VulkanLoad() {
+1
View File
@@ -201,6 +201,7 @@ extern PFN_vkDestroyDebugReportCallbackEXT dyn_vkDestroyDebugReportCallbackEXT;
// Way to do a quick check before even attempting to load.
bool VulkanMayBeAvailable();
void VulkanSetAvailable(bool available);
bool VulkanLoad();
void VulkanLoadInstanceFunctions(VkInstance instance);
+3 -1
View File
@@ -98,9 +98,11 @@ bool AndroidVulkanContext::InitAPI() {
info.app_name = "PPSSPP";
info.app_ver = gitVer.ToInteger();
info.flags = VULKAN_FLAG_PRESENT_MAILBOX | VULKAN_FLAG_PRESENT_FIFO_RELAXED;
if (VK_SUCCESS != g_Vulkan->CreateInstance(info)) {
VkResult res = g_Vulkan->CreateInstance(info);
if (res != VK_SUCCESS) {
ELOG("Failed to create vulkan context: %s", g_Vulkan->InitError().c_str());
System_SendMessage("toast", "No Vulkan compatible device found. Using OpenGL instead.");
VulkanSetAvailable(false);
delete g_Vulkan;
g_Vulkan = nullptr;
return false;
+1 -1
View File
@@ -431,10 +431,10 @@ extern "C" void Java_org_ppsspp_ppsspp_NativeApp_init
NativeInit(2, argv, user_data_path.c_str(), externalDir.c_str(), cacheDir.c_str());
}
retry:
// Now that we've loaded config, set javaGL.
javaGL = NativeQueryConfig("androidJavaGL") == "true";
switch (g_Config.iGPUBackend) {
case (int)GPUBackend::OPENGL:
useCPUThread = true;