mirror of https://github.com/bjornbytes/lovr.git
Improve Vulkan initialization;
- Check for layers before enabling - Check for instance/device extensions before enabling Fixes unfriendly errors when running on a system without validation layers installed. Uses same table approach as OpenXR code.
This commit is contained in:
parent
7b3e1a02eb
commit
3879ce926d
|
@ -210,6 +210,8 @@ static gpu_memory* gpu_allocate(gpu_memory_type type, VkMemoryRequirements info,
|
|||
static void gpu_release(gpu_memory* memory);
|
||||
static void condemn(void* handle, VkObjectType type);
|
||||
static void expunge(void);
|
||||
static bool hasLayer(VkLayerProperties* layers, uint32_t count, const char* layer);
|
||||
static bool hasExtension(VkExtensionProperties* extensions, uint32_t count, const char* extension);
|
||||
static void createSwapchain(uint32_t width, uint32_t height);
|
||||
static VkRenderPass getCachedRenderPass(gpu_pass_info* pass, bool exact);
|
||||
static VkFramebuffer getCachedFramebuffer(VkRenderPass pass, VkImageView images[9], uint32_t imageCount, uint32_t size[2]);
|
||||
|
@ -226,6 +228,7 @@ static bool check(bool condition, const char* message);
|
|||
|
||||
// Functions that don't require an instance
|
||||
#define GPU_FOREACH_ANONYMOUS(X)\
|
||||
X(vkEnumerateInstanceLayerProperties)\
|
||||
X(vkEnumerateInstanceExtensionProperties)\
|
||||
X(vkCreateInstance)
|
||||
|
||||
|
@ -1840,51 +1843,86 @@ bool gpu_init(gpu_config* config) {
|
|||
GPU_FOREACH_ANONYMOUS(GPU_LOAD_ANONYMOUS);
|
||||
|
||||
{ // Instance
|
||||
const char* extensions[32];
|
||||
uint32_t extensionCount = 0;
|
||||
struct {
|
||||
bool validation;
|
||||
bool portability;
|
||||
bool debug;
|
||||
} supports = { 0 };
|
||||
|
||||
// Layers
|
||||
|
||||
struct { const char* name; bool shouldEnable; bool* isEnabled; } layers[] = {
|
||||
{ "VK_LAYER_KHRONOS_validation", config->debug, &supports.validation }
|
||||
};
|
||||
|
||||
const char* enabledLayers[1];
|
||||
uint32_t enabledLayerCount = 0;
|
||||
|
||||
VkLayerProperties layerInfo[32];
|
||||
uint32_t count = COUNTOF(layerInfo);
|
||||
VK(vkEnumerateInstanceLayerProperties(&count, layerInfo), "Failed to enumerate instance layers") return gpu_destroy(), false;
|
||||
|
||||
for (uint32_t i = 0; i < COUNTOF(layers); i++) {
|
||||
if (!layers[i].shouldEnable) continue;
|
||||
if (hasLayer(layerInfo, count, layers[i].name)) {
|
||||
CHECK(enabledLayerCount < COUNTOF(enabledLayers), "Too many layers") return gpu_destroy(), false;
|
||||
if (layers[i].isEnabled) *layers[i].isEnabled = true;
|
||||
enabledLayers[enabledLayerCount++] = layers[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
// Extensions
|
||||
|
||||
struct { const char* name; bool shouldEnable; bool* isEnabled; } extensions[] = {
|
||||
{ "VK_KHR_portability_enumeration", true, &supports.portability },
|
||||
{ "VK_EXT_debug_utils", config->debug, &supports.debug }
|
||||
};
|
||||
|
||||
const char* enabledExtensions[32];
|
||||
uint32_t enabledExtensionCount = 0;
|
||||
|
||||
if (state.config.vk.getInstanceExtensions) {
|
||||
const char** instanceExtensions = state.config.vk.getInstanceExtensions(&extensionCount);
|
||||
CHECK(extensionCount < COUNTOF(extensions), "Too many instance extensions") return gpu_destroy(), false;
|
||||
for (uint32_t i = 0; i < extensionCount; i++) {
|
||||
extensions[i] = instanceExtensions[i];
|
||||
const char** instanceExtensions = state.config.vk.getInstanceExtensions(&enabledExtensionCount);
|
||||
CHECK(enabledExtensionCount < COUNTOF(enabledExtensions), "Too many instance extensions") return gpu_destroy(), false;
|
||||
for (uint32_t i = 0; i < enabledExtensionCount; i++) {
|
||||
enabledExtensions[i] = instanceExtensions[i];
|
||||
}
|
||||
}
|
||||
|
||||
if (state.config.debug) {
|
||||
CHECK(extensionCount < COUNTOF(extensions), "Too many instance extensions") return gpu_destroy(), false;
|
||||
extensions[extensionCount++] = "VK_EXT_debug_utils";
|
||||
}
|
||||
|
||||
VkExtensionProperties extensionInfo[256];
|
||||
uint32_t count = COUNTOF(extensionInfo);
|
||||
count = COUNTOF(extensionInfo);
|
||||
VK(vkEnumerateInstanceExtensionProperties(NULL, &count, extensionInfo), "Failed to enumerate instance extensions") return gpu_destroy(), false;
|
||||
|
||||
VkInstanceCreateFlags instanceFlags = 0;
|
||||
for (uint32_t i = 0; i < COUNTOF(extensions); i++) {
|
||||
if (!extensions[i].shouldEnable) continue;
|
||||
if (hasExtension(extensionInfo, count, extensions[i].name)) {
|
||||
CHECK(enabledExtensionCount < COUNTOF(enabledExtensions), "Too many instance extensions") return gpu_destroy(), false;
|
||||
if (extensions[i].isEnabled) *extensions[i].isEnabled = true;
|
||||
enabledExtensions[enabledExtensionCount++] = extensions[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef VK_KHR_portability_enumeration
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (!strcmp(extensionInfo[i].extensionName, "VK_KHR_portability_enumeration")) {
|
||||
CHECK(extensionCount < COUNTOF(extensions), "Too many instance extensions") return gpu_destroy(), false;
|
||||
extensions[extensionCount++] = "VK_KHR_portability_enumeration";
|
||||
instanceFlags |= VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR;
|
||||
if (state.config.debug && !supports.validation && state.config.callback) {
|
||||
state.config.callback(state.config.userdata, "Warning: GPU debug mode is enabled, but validation layer is not supported", false);
|
||||
}
|
||||
|
||||
if (state.config.debug && !supports.debug) {
|
||||
state.config.debug = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
VkInstanceCreateInfo instanceInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO,
|
||||
.flags = instanceFlags,
|
||||
.flags = supports.portability ? VK_INSTANCE_CREATE_ENUMERATE_PORTABILITY_BIT_KHR : 0,
|
||||
.pApplicationInfo = &(VkApplicationInfo) {
|
||||
.sType = VK_STRUCTURE_TYPE_APPLICATION_INFO,
|
||||
.pEngineName = config->engineName,
|
||||
.engineVersion = VK_MAKE_VERSION(config->engineVersion[0], config->engineVersion[1], config->engineVersion[2]),
|
||||
.apiVersion = VK_MAKE_VERSION(1, 1, 0)
|
||||
},
|
||||
.enabledLayerCount = state.config.debug ? 1 : 0,
|
||||
.ppEnabledLayerNames = (const char*[]) { "VK_LAYER_KHRONOS_validation" },
|
||||
.enabledExtensionCount = extensionCount,
|
||||
.ppEnabledExtensionNames = extensions
|
||||
.enabledLayerCount = enabledLayerCount,
|
||||
.ppEnabledLayerNames = enabledLayers,
|
||||
.enabledExtensionCount = enabledExtensionCount,
|
||||
.ppEnabledExtensionNames = enabledExtensions
|
||||
};
|
||||
|
||||
if (state.config.vk.createInstance) {
|
||||
|
@ -2056,23 +2094,33 @@ bool gpu_init(gpu_config* config) {
|
|||
}
|
||||
CHECK(state.queueFamilyIndex != ~0u, "Queue selection failed") return gpu_destroy(), false;
|
||||
|
||||
const char* extensions[4];
|
||||
uint32_t extensionCount = 0;
|
||||
struct {
|
||||
bool swapchain;
|
||||
} supports = { 0 };
|
||||
|
||||
if (state.surface) {
|
||||
extensions[extensionCount++] = "VK_KHR_swapchain";
|
||||
}
|
||||
struct { const char* name; bool shouldEnable; bool* isEnabled; } extensions[] = {
|
||||
{ "VK_KHR_swapchain", state.surface, &supports.swapchain },
|
||||
{ "VK_KHR_portability_subset", true, NULL }
|
||||
};
|
||||
|
||||
const char* enabledExtensions[4];
|
||||
uint32_t enabledExtensionCount = 0;
|
||||
|
||||
VkExtensionProperties extensionInfo[256];
|
||||
uint32_t count = COUNTOF(extensionInfo);
|
||||
VK(vkEnumerateDeviceExtensionProperties(state.adapter, NULL, &count, extensionInfo), "Failed to enumerate device extensions") return gpu_destroy(), false;
|
||||
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (!strcmp(extensionInfo[i].extensionName, "VK_KHR_portability_subset")) {
|
||||
extensions[extensionCount++] = "VK_KHR_portability_subset";
|
||||
for (uint32_t i = 0; i < COUNTOF(extensions); i++) {
|
||||
if (!extensions[i].shouldEnable) continue;
|
||||
if (hasExtension(extensionInfo, count, extensions[i].name)) {
|
||||
CHECK(enabledExtensionCount < COUNTOF(enabledExtensions), "Too many device extensions") return gpu_destroy(), false;
|
||||
if (extensions[i].isEnabled) *extensions[i].isEnabled = true;
|
||||
enabledExtensions[enabledExtensionCount++] = extensions[i].name;
|
||||
}
|
||||
}
|
||||
|
||||
CHECK(supports.swapchain || !state.surface, "Swapchain extension not supported");
|
||||
|
||||
VkDeviceCreateInfo deviceInfo = {
|
||||
.sType = VK_STRUCTURE_TYPE_DEVICE_CREATE_INFO,
|
||||
.pNext = config->features ? &enabledFeatures : NULL,
|
||||
|
@ -2083,8 +2131,8 @@ bool gpu_init(gpu_config* config) {
|
|||
.pQueuePriorities = &(float) { 1.f },
|
||||
.queueCount = 1
|
||||
},
|
||||
.enabledExtensionCount = extensionCount,
|
||||
.ppEnabledExtensionNames = extensions
|
||||
.enabledExtensionCount = enabledExtensionCount,
|
||||
.ppEnabledExtensionNames = enabledExtensions
|
||||
};
|
||||
|
||||
if (state.config.vk.createDevice) {
|
||||
|
@ -2586,6 +2634,24 @@ static void expunge() {
|
|||
}
|
||||
}
|
||||
|
||||
static bool hasLayer(VkLayerProperties* layers, uint32_t count, const char* layer) {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (!strcmp(layers[i].layerName, layer)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static bool hasExtension(VkExtensionProperties* extensions, uint32_t count, const char* extension) {
|
||||
for (uint32_t i = 0; i < count; i++) {
|
||||
if (!strcmp(extensions[i].extensionName, extension)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
static void createSwapchain(uint32_t width, uint32_t height) {
|
||||
if (width == 0 || height == 0) {
|
||||
state.swapchainValid = false;
|
||||
|
|
Loading…
Reference in New Issue