mirror of
https://github.com/cemu-project/Cemu.git
synced 2026-06-08 07:34:57 -06:00
only check LLVM crash on affected driver versions and eliminate IPC.
This commit is contained in:
parent
21122d9907
commit
a52fe81add
@ -341,71 +341,44 @@ void VulkanRenderer::GetDeviceFeatures()
|
|||||||
|
|
||||||
static void WorkaroundChildAbortHandler(int unused)
|
static void WorkaroundChildAbortHandler(int unused)
|
||||||
{
|
{
|
||||||
_exit(2);
|
_exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void PerformBOTWLinuxWorkaround(int subProcessPipes[2])
|
static void LinuxBreathOfTheWildWorkaround(VkInstance& instance, const VkInstanceCreateInfo* create_info)
|
||||||
{
|
{
|
||||||
int childID = fork();
|
|
||||||
if (childID == 0) // inside this if statement runs in child
|
|
||||||
{
|
|
||||||
struct sigaction sa{.sa_handler = WorkaroundChildAbortHandler};
|
|
||||||
sigaction(SIGABRT, &sa, nullptr);
|
|
||||||
|
|
||||||
freopen("/dev/null", "w", stderr);
|
// if the user specified either shader backend, do nothing.
|
||||||
|
// should parse the flag list but there are currently no other flags containing llvm or aco as a substring
|
||||||
setenv("RADV_DEBUG", "llvm", 1);
|
std::string_view debugEnv = getenv("RADV_DEBUG");
|
||||||
|
if (debugEnv.find("aco") != std::string_view::npos || debugEnv.find("llvm") != std::string_view::npos)
|
||||||
VkInstanceCreateInfo instanceCreateInfo = {};
|
return;
|
||||||
instanceCreateInfo.sType = VK_STRUCTURE_TYPE_INSTANCE_CREATE_INFO;
|
|
||||||
VkInstance instance = VK_NULL_HANDLE;
|
uint32_t count = 0;
|
||||||
if (vkCreateInstance(&instanceCreateInfo, nullptr, &instance) != VK_SUCCESS)
|
vkEnumeratePhysicalDevices(instance, &count, nullptr);
|
||||||
_exit(1);
|
|
||||||
|
std::vector<VkPhysicalDevice> physicalDevices{count};
|
||||||
InitializeInstanceVulkan(instance);
|
vkEnumeratePhysicalDevices(instance, &count, physicalDevices.data());
|
||||||
|
|
||||||
uint32_t count = 0;
|
// Find the first AMD device using a RADV driver and store its version
|
||||||
vkEnumeratePhysicalDevices(instance, &count, nullptr);
|
int version = 0;
|
||||||
|
for (auto& i : physicalDevices)
|
||||||
std::vector<VkPhysicalDevice> physicalDevices{count};
|
{
|
||||||
vkEnumeratePhysicalDevices(instance, &count, physicalDevices.data());
|
VkPhysicalDeviceDriverProperties driverProps{};
|
||||||
|
driverProps.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_DRIVER_PROPERTIES;
|
||||||
for (auto& i : physicalDevices)
|
VkPhysicalDeviceProperties2 prop{};
|
||||||
{
|
prop.sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_PROPERTIES_2;
|
||||||
VkPhysicalDeviceProperties prop{};
|
prop.pNext = &driverProps;
|
||||||
vkGetPhysicalDeviceProperties(i, &prop);
|
vkGetPhysicalDeviceProperties2(i, &prop);
|
||||||
if (prop.vendorID != 0x1002)
|
if (prop.properties.vendorID != 0x1002 || driverProps.driverID != VK_DRIVER_ID_MESA_RADV)
|
||||||
continue;
|
continue;
|
||||||
|
|
||||||
std::string_view deviceName = prop.deviceName;
|
version = prop.properties.driverVersion;
|
||||||
if (deviceName.find("RADV") != std::string_view::npos)
|
break;
|
||||||
{
|
}
|
||||||
write(subProcessPipes[1], &prop.driverVersion, sizeof(uint32_t));
|
|
||||||
vkDestroyInstance(instance, nullptr);
|
if (version == 0)
|
||||||
_exit(0);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// no appropriate device found to query version
|
|
||||||
vkDestroyInstance(instance, nullptr);
|
|
||||||
_exit(1);
|
|
||||||
}
|
|
||||||
|
|
||||||
int childStatus = 0;
|
|
||||||
waitpid(childID, &childStatus, 0);
|
|
||||||
|
|
||||||
if (WEXITSTATUS(childStatus) == 2)
|
|
||||||
{
|
|
||||||
cemuLog_log(LogType::Force, "BOTW/RADV workaround not applied because mesa was built without LLVM");
|
|
||||||
}
|
|
||||||
|
|
||||||
// only continue if the process exits with code zero, which means it determined the version and didn't crash.
|
|
||||||
if (WEXITSTATUS(childStatus) != 0)
|
|
||||||
return;
|
return;
|
||||||
|
|
||||||
uint32_t version = 0;
|
|
||||||
if (read(subProcessPipes[0], &version, sizeof(version)) == -1)
|
|
||||||
return; // if we fail to read bail. Should never happen if the subprocess exited with 0
|
|
||||||
|
|
||||||
int major = VK_API_VERSION_MAJOR(version);
|
int major = VK_API_VERSION_MAJOR(version);
|
||||||
int minor = VK_API_VERSION_MINOR(version);
|
int minor = VK_API_VERSION_MINOR(version);
|
||||||
@ -417,38 +390,55 @@ static void PerformBOTWLinuxWorkaround(int subProcessPipes[2])
|
|||||||
if ((major <= 25 && minor < 3) || (major == 26 && (minor > 0 || patch >= 5)) || major > 26)
|
if ((major <= 25 && minor < 3) || (major == 26 && (minor > 0 || patch >= 5)) || major > 26)
|
||||||
return;
|
return;
|
||||||
|
|
||||||
cemuLog_log(LogType::Force, "BOTW/RADV workaround active. Adding llvm to RADV_DEBUG environment variable");
|
// check if running with LLVM would crash because mesa is LLVM-less.
|
||||||
// if the variable is empty set it to llvm, otherwise check if it contains llvm/aco and if not append it
|
int childID = fork();
|
||||||
if (const char* value; (value = getenv("RADV_DEBUG")) != NULL && strlen(value) != 0)
|
if (childID == 0) // inside this if statement runs in child
|
||||||
{
|
{
|
||||||
std::string valueStr{value};
|
struct sigaction sa{.sa_handler = WorkaroundChildAbortHandler};
|
||||||
// only append ,llvm when llvm or aco are not already passed as flags.
|
sigaction(SIGABRT, &sa, nullptr);
|
||||||
// "aco" is not a mesa flag (anymore, it used to be when llvm was default)
|
|
||||||
// but it will provide users with a way to override this workaround by setting RADV_DEBUG=aco
|
freopen("/dev/null", "w", stderr);
|
||||||
// should parse the flag list but there are currently no other flags containing llvm or aco as a substring
|
|
||||||
if (valueStr.find("llvm") == std::string::npos && valueStr.find("aco") == std::string::npos)
|
setenv("RADV_DEBUG", "llvm", 1);
|
||||||
{
|
|
||||||
valueStr.append(",llvm");
|
VkInstance instance = VK_NULL_HANDLE;
|
||||||
setenv("RADV_DEBUG", valueStr.c_str(), 1);
|
vkCreateInstance(create_info, nullptr, &instance);
|
||||||
}
|
// this function will abort() when LLVM is absent
|
||||||
|
uint32_t count = 0;
|
||||||
|
vkEnumeratePhysicalDevices(instance, &count, nullptr);
|
||||||
|
vkDestroyInstance(instance, nullptr);
|
||||||
|
_exit(0);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
|
int childStatus = 0;
|
||||||
|
waitpid(childID, &childStatus, 0);
|
||||||
|
|
||||||
|
if (WEXITSTATUS(childStatus) == 1)
|
||||||
|
cemuLog_log(LogType::Force, "BOTW/RADV workaround not applied because mesa was built without LLVM");
|
||||||
|
|
||||||
|
// only continue if the process exits with code zero, which means it didn't crash
|
||||||
|
if (WEXITSTATUS(childStatus) != 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
cemuLog_log(LogType::Force, "BOTW/RADV workaround active. Adding \"llvm\" to RADV_DEBUG environment variable");
|
||||||
|
if (debugEnv.empty())
|
||||||
{
|
{
|
||||||
setenv("RADV_DEBUG", "llvm", 1);
|
setenv("RADV_DEBUG", "llvm", 1);
|
||||||
}
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
std::string appendedDebugEnv{debugEnv};
|
||||||
|
appendedDebugEnv.append(",llvm");
|
||||||
|
setenv("RADV_DEBUG", appendedDebugEnv.c_str(), 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
// recreate the vulkan instance to update debug setting
|
||||||
|
vkDestroyInstance(instance, nullptr);
|
||||||
|
vkCreateInstance(create_info, nullptr, &instance);
|
||||||
|
InitializeInstanceVulkan(instance);
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
static void LinuxBreathOfTheWildWorkaround()
|
|
||||||
{
|
|
||||||
int subProcessPipes[2]{};
|
|
||||||
pipe(subProcessPipes);
|
|
||||||
|
|
||||||
PerformBOTWLinuxWorkaround(subProcessPipes);
|
|
||||||
|
|
||||||
close(subProcessPipes[0]);
|
|
||||||
close(subProcessPipes[1]);
|
|
||||||
}
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
VulkanRenderer::VulkanRenderer()
|
VulkanRenderer::VulkanRenderer()
|
||||||
@ -457,15 +447,6 @@ VulkanRenderer::VulkanRenderer()
|
|||||||
|
|
||||||
cemuLog_log(LogType::Force, "------- Init Vulkan graphics backend -------");
|
cemuLog_log(LogType::Force, "------- Init Vulkan graphics backend -------");
|
||||||
|
|
||||||
// Workaround for BOTW + RADV. Runes like Magnesis and the camera cause GPU crashes.
|
|
||||||
#if BOOST_OS_LINUX
|
|
||||||
uint64 currentTitleId = CafeSystem::GetForegroundTitleId();
|
|
||||||
if (currentTitleId == 0x00050000101c9500 || currentTitleId == 0x00050000101c9400 || currentTitleId == 0x00050000101c9300)
|
|
||||||
{
|
|
||||||
LinuxBreathOfTheWildWorkaround();
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
|
|
||||||
const bool useValidationLayer = cemuLog_isLoggingEnabled(LogType::VulkanValidation);
|
const bool useValidationLayer = cemuLog_isLoggingEnabled(LogType::VulkanValidation);
|
||||||
if (useValidationLayer)
|
if (useValidationLayer)
|
||||||
cemuLog_log(LogType::Force, "Validation layer is enabled");
|
cemuLog_log(LogType::Force, "Validation layer is enabled");
|
||||||
@ -519,6 +500,15 @@ VulkanRenderer::VulkanRenderer()
|
|||||||
if (!InitializeInstanceVulkan(m_instance))
|
if (!InitializeInstanceVulkan(m_instance))
|
||||||
throw std::runtime_error("Unable to load instanced Vulkan functions");
|
throw std::runtime_error("Unable to load instanced Vulkan functions");
|
||||||
|
|
||||||
|
// Workaround for BOTW + RADV. Runes like Magnesis and the camera cause GPU crashes.
|
||||||
|
#if BOOST_OS_LINUX
|
||||||
|
uint64 currentTitleId = CafeSystem::GetForegroundTitleId();
|
||||||
|
if (currentTitleId == 0x00050000101c9500 || currentTitleId == 0x00050000101c9400 || currentTitleId == 0x00050000101c9300)
|
||||||
|
{
|
||||||
|
LinuxBreathOfTheWildWorkaround(m_instance, &create_info);
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
uint32_t device_count = 0;
|
uint32_t device_count = 0;
|
||||||
vkEnumeratePhysicalDevices(m_instance, &device_count, nullptr);
|
vkEnumeratePhysicalDevices(m_instance, &device_count, nullptr);
|
||||||
if (device_count == 0)
|
if (device_count == 0)
|
||||||
|
|||||||
Loading…
Reference in New Issue
Block a user