diff --git a/renderdoc/driver/vulkan/vk_core.h b/renderdoc/driver/vulkan/vk_core.h index 9d69519bc..317e216b2 100644 --- a/renderdoc/driver/vulkan/vk_core.h +++ b/renderdoc/driver/vulkan/vk_core.h @@ -531,7 +531,8 @@ private: VulkanDrawcallTreeNode m_ParentDrawcall; // in vk_.cpp - void AddRequiredExtensions(bool instance, vector &extensionList); + bool AddRequiredExtensions(bool instance, vector &extensionList, + const std::set &supportedExtensions); void InsertDrawsAndRefreshIDs(vector &cmdBufNodes, uint32_t baseEventID, uint32_t baseDrawID); @@ -590,7 +591,7 @@ public: bool ReleaseResource(WrappedVkRes *res); - void Initialise(VkInitParams ¶ms); + ReplayCreateStatus Initialise(VkInitParams ¶ms); void Shutdown(); void ReplayLog(uint32_t startEventID, uint32_t endEventID, ReplayLogType replayType); void ReadLogInitialisation(); diff --git a/renderdoc/driver/vulkan/vk_dispatchtables.cpp b/renderdoc/driver/vulkan/vk_dispatchtables.cpp index 94f9b1bb3..813f707e5 100644 --- a/renderdoc/driver/vulkan/vk_dispatchtables.cpp +++ b/renderdoc/driver/vulkan/vk_dispatchtables.cpp @@ -57,13 +57,15 @@ void InitReplayTables(void *vulkanModule) VkLayerInstanceDispatchTableExtended &table = replayInstanceTable; memset(&table, 0, sizeof(table)); HookInit(GetInstanceProcAddr); + HookInit(EnumerateInstanceExtensionProperties); + HookInit(EnumerateInstanceLayerProperties); HookInitVulkanInstance(); } } #define InstanceGPA(func) \ table->func = \ - (CONCAT(PFN_vk, func))table->GetInstanceProcAddr(instance, STRINGIZE(CONCAT(vk, func))); + (CONCAT(PFN_vk, func))table->GetInstanceProcAddr(instance, STRINGIZE(CONCAT(vk, func))) void InitInstanceReplayTables(VkInstance instance) { @@ -72,30 +74,34 @@ void InitInstanceReplayTables(VkInstance instance) // we know we'll only have one instance, so this is safe - InstanceGPA(EnumerateDeviceExtensionProperties) InstanceGPA(EnumerateDeviceLayerProperties) + InstanceGPA(EnumerateDeviceExtensionProperties); + InstanceGPA(EnumerateDeviceLayerProperties); - InstanceGPA(GetPhysicalDeviceSurfaceCapabilitiesKHR) InstanceGPA( - GetPhysicalDeviceSurfaceFormatsKHR) InstanceGPA(GetPhysicalDeviceSurfacePresentModesKHR) - InstanceGPA(GetPhysicalDeviceSurfaceSupportKHR) InstanceGPA(CreateDebugReportCallbackEXT) - InstanceGPA(DestroyDebugReportCallbackEXT) InstanceGPA(DebugReportMessageEXT) + InstanceGPA(GetPhysicalDeviceSurfaceCapabilitiesKHR); + InstanceGPA(GetPhysicalDeviceSurfaceFormatsKHR); + InstanceGPA(GetPhysicalDeviceSurfacePresentModesKHR); + InstanceGPA(GetPhysicalDeviceSurfaceSupportKHR); + InstanceGPA(CreateDebugReportCallbackEXT); + InstanceGPA(DestroyDebugReportCallbackEXT); + InstanceGPA(DebugReportMessageEXT); #ifdef VK_USE_PLATFORM_WIN32_KHR - InstanceGPA(CreateWin32SurfaceKHR) + InstanceGPA(CreateWin32SurfaceKHR); #endif #ifdef VK_USE_PLATFORM_ANDROID_KHR - InstanceGPA(CreateAndroidSurfaceKHR) + InstanceGPA(CreateAndroidSurfaceKHR); #endif #ifdef VK_USE_PLATFORM_XCB_KHR - InstanceGPA(CreateXcbSurfaceKHR) + InstanceGPA(CreateXcbSurfaceKHR); #endif #ifdef VK_USE_PLATFORM_XLIB_KHR - InstanceGPA(CreateXlibSurfaceKHR) + InstanceGPA(CreateXlibSurfaceKHR); #endif - InstanceGPA(DestroySurfaceKHR) + InstanceGPA(DestroySurfaceKHR); } void InitInstanceExtensionTables(VkInstance instance) diff --git a/renderdoc/driver/vulkan/vk_hookset_defs.h b/renderdoc/driver/vulkan/vk_hookset_defs.h index ede26a76e..9e486cbbd 100644 --- a/renderdoc/driver/vulkan/vk_hookset_defs.h +++ b/renderdoc/driver/vulkan/vk_hookset_defs.h @@ -605,6 +605,10 @@ struct VkLayerInstanceDispatchTableExtended : VkLayerInstanceDispatchTable // even though it won't actually ever get used PFN_vkCreateInstance CreateInstance; + // we need to use these before we have a dispatch table + PFN_vkEnumerateInstanceExtensionProperties EnumerateInstanceExtensionProperties; + PFN_vkEnumerateInstanceLayerProperties EnumerateInstanceLayerProperties; + // extensions here }; diff --git a/renderdoc/driver/vulkan/vk_posix.cpp b/renderdoc/driver/vulkan/vk_posix.cpp index bef83e50c..13a212eac 100644 --- a/renderdoc/driver/vulkan/vk_posix.cpp +++ b/renderdoc/driver/vulkan/vk_posix.cpp @@ -35,28 +35,68 @@ bool VulkanReplay::IsOutputWindowVisible(uint64_t id) return true; } -void WrappedVulkan::AddRequiredExtensions(bool instance, vector &extensionList) +bool WrappedVulkan::AddRequiredExtensions(bool instance, vector &extensionList, + const std::set &supportedExtensions) { bool device = !instance; - // TODO should check if these are present.. - if(instance) { - extensionList.push_back(VK_KHR_SURFACE_EXTENSION_NAME); + // we must have VK_KHR_surface + if(supportedExtensions.find(VK_KHR_SURFACE_EXTENSION_NAME) == supportedExtensions.end()) + { + RDCERR("Unsupported required instance extension '%s'", VK_KHR_SURFACE_EXTENSION_NAME); + return false; + } + + // don't add duplicates + if(std::find(extensionList.begin(), extensionList.end(), VK_KHR_SURFACE_EXTENSION_NAME) == + extensionList.end()) + extensionList.push_back(VK_KHR_SURFACE_EXTENSION_NAME); + + bool oneSurfaceTypeSupported = false; #if defined(VK_USE_PLATFORM_XCB_KHR) - extensionList.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); + // don't add duplicates, and only add if supported + if(supportedExtensions.find(VK_KHR_XCB_SURFACE_EXTENSION_NAME) != supportedExtensions.end() && + std::find(extensionList.begin(), extensionList.end(), VK_KHR_XCB_SURFACE_EXTENSION_NAME) == + extensionList.end()) + { + extensionList.push_back(VK_KHR_XCB_SURFACE_EXTENSION_NAME); + oneSurfaceTypeSupported = true; + } #endif #if defined(VK_USE_PLATFORM_XLIB_KHR) - extensionList.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); + // don't add duplicates + if(supportedExtensions.find(VK_KHR_XLIB_SURFACE_EXTENSION_NAME) != supportedExtensions.end() && + std::find(extensionList.begin(), extensionList.end(), VK_KHR_XLIB_SURFACE_EXTENSION_NAME) == + extensionList.end()) + { + extensionList.push_back(VK_KHR_XLIB_SURFACE_EXTENSION_NAME); + oneSurfaceTypeSupported = true; + } #endif + + if(!oneSurfaceTypeSupported) + { + RDCERR("Required at least one of '%s' or '%s' extension to be present", + VK_KHR_XCB_SURFACE_EXTENSION_NAME, VK_KHR_XLIB_SURFACE_EXTENSION_NAME); + return false; + } } else if(device) { + if(supportedExtensions.find(VK_KHR_SWAPCHAIN_EXTENSION_NAME) == supportedExtensions.end()) + { + RDCERR("Unsupported required device extension '%s'", VK_KHR_SWAPCHAIN_EXTENSION_NAME); + return false; + } + extensionList.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); } + + return true; } #if defined(VK_USE_PLATFORM_XCB_KHR) diff --git a/renderdoc/driver/vulkan/vk_replay.cpp b/renderdoc/driver/vulkan/vk_replay.cpp index 371b136d8..8310128fd 100644 --- a/renderdoc/driver/vulkan/vk_replay.cpp +++ b/renderdoc/driver/vulkan/vk_replay.cpp @@ -5304,7 +5304,13 @@ ReplayCreateStatus Vulkan_CreateReplayDevice(const char *logfile, IReplayDriver VulkanReplay::PreDeviceInitCounters(); WrappedVulkan *vk = new WrappedVulkan(logfile); - vk->Initialise(initParams); + ReplayCreateStatus status = vk->Initialise(initParams); + + if(status != eReplayCreate_Success) + { + delete vk; + return status; + } RDCLOG("Created device."); VulkanReplay *replay = vk->GetReplay(); diff --git a/renderdoc/driver/vulkan/vk_win32.cpp b/renderdoc/driver/vulkan/vk_win32.cpp index 7be54e73f..d9c439283 100644 --- a/renderdoc/driver/vulkan/vk_win32.cpp +++ b/renderdoc/driver/vulkan/vk_win32.cpp @@ -70,21 +70,50 @@ bool VulkanReplay::IsOutputWindowVisible(uint64_t id) return (IsWindowVisible(m_OutputWindows[id].wnd) == TRUE); } -void WrappedVulkan::AddRequiredExtensions(bool instance, vector &extensionList) +bool WrappedVulkan::AddRequiredExtensions(bool instance, vector &extensionList, + const std::set &supportedExtensions) { bool device = !instance; - // TODO should check if these are present.. - if(instance) { - extensionList.push_back(VK_KHR_SURFACE_EXTENSION_NAME); - extensionList.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); + // for windows we require both extensions as there's no alternative + if(supportedExtensions.find(VK_KHR_SURFACE_EXTENSION_NAME) == supportedExtensions.end()) + { + RDCERR("Unsupported required instance extension '%s'", VK_KHR_SURFACE_EXTENSION_NAME); + return false; + } + + if(supportedExtensions.find(VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == supportedExtensions.end()) + { + RDCERR("Unsupported required instance extension '%s'", VK_KHR_WIN32_SURFACE_EXTENSION_NAME); + return false; + } + + // don't add duplicates + if(std::find(extensionList.begin(), extensionList.end(), VK_KHR_SURFACE_EXTENSION_NAME) == + extensionList.end()) + extensionList.push_back(VK_KHR_SURFACE_EXTENSION_NAME); + + if(std::find(extensionList.begin(), extensionList.end(), VK_KHR_WIN32_SURFACE_EXTENSION_NAME) == + extensionList.end()) + extensionList.push_back(VK_KHR_WIN32_SURFACE_EXTENSION_NAME); } else if(device) { - extensionList.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); + if(supportedExtensions.find(VK_KHR_SWAPCHAIN_EXTENSION_NAME) == supportedExtensions.end()) + { + RDCERR("Unsupported required device extension '%s'", VK_KHR_SWAPCHAIN_EXTENSION_NAME); + return false; + } + + // don't add duplicates + if(std::find(extensionList.begin(), extensionList.end(), VK_KHR_SWAPCHAIN_EXTENSION_NAME) == + extensionList.end()) + extensionList.push_back(VK_KHR_SWAPCHAIN_EXTENSION_NAME); } + + return true; } #if !defined(VK_USE_PLATFORM_WIN32_KHR) diff --git a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp index 0c71c0e3c..5594cb7ae 100644 --- a/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp +++ b/renderdoc/driver/vulkan/wrappers/vk_device_funcs.cpp @@ -82,7 +82,7 @@ static void StripUnwantedLayers(vector &Layers) } } -void WrappedVulkan::Initialise(VkInitParams ¶ms) +ReplayCreateStatus WrappedVulkan::Initialise(VkInitParams ¶ms) { m_InitParams = params; @@ -115,7 +115,63 @@ void WrappedVulkan::Initialise(VkInitParams ¶ms) } } - AddRequiredExtensions(true, params.Extensions); + std::set supportedExtensions; + + for(size_t i = 0; i <= params.Layers.size(); i++) + { + const char *pLayerName = (i == 0 ? NULL : params.Layers[i - 1].c_str()); + + uint32_t count = 0; + GetInstanceDispatchTable(NULL)->EnumerateInstanceExtensionProperties(pLayerName, &count, NULL); + + VkExtensionProperties *props = new VkExtensionProperties[count]; + GetInstanceDispatchTable(NULL)->EnumerateInstanceExtensionProperties(pLayerName, &count, props); + + for(uint32_t e = 0; e < count; e++) + supportedExtensions.insert(props[e].extensionName); + + SAFE_DELETE_ARRAY(props); + } + + std::set supportedLayers; + + { + uint32_t count = 0; + GetInstanceDispatchTable(NULL)->EnumerateInstanceLayerProperties(&count, NULL); + + VkLayerProperties *props = new VkLayerProperties[count]; + GetInstanceDispatchTable(NULL)->EnumerateInstanceLayerProperties(&count, props); + + for(uint32_t e = 0; e < count; e++) + supportedLayers.insert(props[e].layerName); + + SAFE_DELETE_ARRAY(props); + } + + bool ok = AddRequiredExtensions(true, params.Extensions, supportedExtensions); + + // error message will be printed to log in above function if something went wrong + if(!ok) + return eReplayCreate_APIHardwareUnsupported; + + // verify that extensions & layers are supported + for(size_t i = 0; i < params.Layers.size(); i++) + { + if(supportedLayers.find(params.Layers[i]) == supportedLayers.end()) + { + RDCERR("Log requires layer '%s' which is not supported", params.Layers[i].c_str()); + return eReplayCreate_APIHardwareUnsupported; + } + } + + for(size_t i = 0; i < params.Extensions.size(); i++) + { + if(supportedExtensions.find(params.Extensions[i]) == supportedExtensions.end()) + { + RDCERR("Log requires extension '%s' which is not supported", params.Extensions[i].c_str()); + return eReplayCreate_APIHardwareUnsupported; + } + } const char **layerscstr = new const char *[params.Layers.size()]; for(size_t i = 0; i < params.Layers.size(); i++) @@ -149,6 +205,13 @@ void WrappedVulkan::Initialise(VkInitParams ¶ms) m_Instance = VK_NULL_HANDLE; VkResult ret = GetInstanceDispatchTable(NULL)->CreateInstance(&instinfo, NULL, &m_Instance); + + SAFE_DELETE_ARRAY(layerscstr); + SAFE_DELETE_ARRAY(extscstr); + + if(ret != VK_SUCCESS) + return eReplayCreate_APIHardwareUnsupported; + RDCASSERTEQUAL(ret, VK_SUCCESS); InitInstanceReplayTables(m_Instance); @@ -177,8 +240,7 @@ void WrappedVulkan::Initialise(VkInitParams ¶ms) ->CreateDebugReportCallbackEXT(Unwrap(m_Instance), &debugInfo, NULL, &m_DbgMsgCallback); } - SAFE_DELETE_ARRAY(layerscstr); - SAFE_DELETE_ARRAY(extscstr); + return eReplayCreate_Success; } VkResult WrappedVulkan::vkCreateInstance(const VkInstanceCreateInfo *pCreateInfo, @@ -612,7 +674,29 @@ bool WrappedVulkan::Serialise_vkCreateDevice(Serialiser *localSerialiser, StripUnwantedLayers(Layers); - AddRequiredExtensions(false, Extensions); + physicalDevice = GetResourceManager()->GetLiveHandle(physId); + + std::set supportedExtensions; + + for(size_t i = 0; i <= Layers.size(); i++) + { + const char *pLayerName = (i == 0 ? NULL : Layers[i - 1].c_str()); + + uint32_t count = 0; + ObjDisp(physicalDevice) + ->EnumerateDeviceExtensionProperties(Unwrap(physicalDevice), pLayerName, &count, NULL); + + VkExtensionProperties *props = new VkExtensionProperties[count]; + ObjDisp(physicalDevice) + ->EnumerateDeviceExtensionProperties(Unwrap(physicalDevice), pLayerName, &count, props); + + for(uint32_t e = 0; e < count; e++) + supportedExtensions.insert(props[e].extensionName); + + SAFE_DELETE_ARRAY(props); + } + + AddRequiredExtensions(false, Extensions, supportedExtensions); #if defined(FORCE_VALIDATION_LAYERS) Layers.push_back("VK_LAYER_LUNARG_standard_validation"); @@ -644,8 +728,6 @@ bool WrappedVulkan::Serialise_vkCreateDevice(Serialiser *localSerialiser, createInfo.ppEnabledExtensionNames = extArray; } - physicalDevice = GetResourceManager()->GetLiveHandle(physId); - VkDevice device; uint32_t qCount = 0;