diff --git a/Common/CMakeLists.txt b/Common/CMakeLists.txt
index f86cffe35a..29b2a2ed3d 100644
--- a/Common/CMakeLists.txt
+++ b/Common/CMakeLists.txt
@@ -200,6 +200,7 @@ add_library(Common STATIC
GPU/Vulkan/VulkanBarrier.h
GPU/Vulkan/VulkanDebug.cpp
GPU/Vulkan/VulkanDebug.h
+ GPU/Vulkan/VulkanDriverVars.h
GPU/Vulkan/VulkanContext.cpp
GPU/Vulkan/VulkanContext.h
GPU/Vulkan/FixedSPIRVCache.h
diff --git a/Common/Common.vcxproj b/Common/Common.vcxproj
index f618df14f5..f922675333 100644
--- a/Common/Common.vcxproj
+++ b/Common/Common.vcxproj
@@ -452,6 +452,7 @@
+
diff --git a/Common/Common.vcxproj.filters b/Common/Common.vcxproj.filters
index ee58c22799..26c4ae712e 100644
--- a/Common/Common.vcxproj.filters
+++ b/Common/Common.vcxproj.filters
@@ -821,6 +821,9 @@
Render
+
+ GPU\Vulkan
+
diff --git a/Common/GPU/Vulkan/VulkanDriverVars.h b/Common/GPU/Vulkan/VulkanDriverVars.h
new file mode 100644
index 0000000000..34ec7c299c
--- /dev/null
+++ b/Common/GPU/Vulkan/VulkanDriverVars.h
@@ -0,0 +1,17 @@
+#pragma once
+
+#include
+#include "Common/Common.h"
+
+enum class AdrenoEnvVar : int {
+ enable_tp_ubwc_flag_hint = (1 << 0),
+ storage_8bit = (1 << 1),
+};
+ENUM_CLASS_BITOPS(AdrenoEnvVar);
+
+struct AdrenoEnvVarDef {
+ std::string_view name;
+ AdrenoEnvVar var;
+};
+
+const AdrenoEnvVarDef *GetAdrenoEnvVarDefs(int *count);
diff --git a/Common/GPU/Vulkan/VulkanLoader.cpp b/Common/GPU/Vulkan/VulkanLoader.cpp
index a574926328..6906331f4c 100644
--- a/Common/GPU/Vulkan/VulkanLoader.cpp
+++ b/Common/GPU/Vulkan/VulkanLoader.cpp
@@ -20,6 +20,7 @@
#include
#include
#include
+#include
#include "Core/Config.h"
#include "Common/Data/Format/JSONReader.h"
@@ -385,6 +386,8 @@ static VulkanLibraryHandle VulkanLoadLibrary(std::string *errorString) {
File::CreateDir(tempDir);
File::CreateDir(fileRedirectDir);
+ // Driver workaround through environment variables must have been applied before this (AdrenoEnvVar).
+
lib = adrenotools_open_libvulkan(
RTLD_NOW | RTLD_LOCAL, ADRENOTOOLS_DRIVER_FILE_REDIRECT | ADRENOTOOLS_DRIVER_CUSTOM,
(std::string(tempDir.c_str()) + "/").c_str(), g_nativeLibDir.c_str(),
@@ -1007,3 +1010,35 @@ const char *VulkanResultToString(VkResult res) {
return temp;
}
}
+
+static const AdrenoEnvVarDef adrenoEnvVarDefs[] = {
+ {"enable_tp_ubwc_flag_hint", AdrenoEnvVar::enable_tp_ubwc_flag_hint},
+ {"storage_8bit", AdrenoEnvVar::storage_8bit},
+};
+
+const AdrenoEnvVarDef *GetAdrenoEnvVarDefs(int *count) {
+ *count = ARRAY_SIZE(adrenoEnvVarDefs);
+ return adrenoEnvVarDefs;
+}
+
+void VulkanApplyCustomDriverEnvVars(AdrenoEnvVar envVars) {
+ std::string FD_DEV_FEATURES;
+ for (int i = 0; i < ARRAY_SIZE(adrenoEnvVarDefs); i++) {
+ const char *value = (envVars & adrenoEnvVarDefs[i].var) ? "1" : "0";
+ if (!FD_DEV_FEATURES.empty()) {
+ FD_DEV_FEATURES += ",";
+ }
+ FD_DEV_FEATURES += adrenoEnvVarDefs[i].name;
+ FD_DEV_FEATURES += "=";
+ FD_DEV_FEATURES += value;
+ }
+
+ // Simply set the environment variable, AdrenoTools will pick it up.
+#if PPSSPP_PLATFORM(ANDROID) || PPSSPP_PLATFORM(LINUX)
+ setenv("FD_DEV_FEATURES", FD_DEV_FEATURES.c_str(), 1); // 1 = overwrite existing value
+#else
+ WARN_LOG(Log::G3D, "VulkanApplyCustomDriverEnvVars: Not supported on this platform. (%s)", FD_DEV_FEATURES.c_str());
+#endif
+}
+
+const AdrenoEnvVarDef *GetAdrenoEnvVarDefs(int *count);
diff --git a/Common/GPU/Vulkan/VulkanLoader.h b/Common/GPU/Vulkan/VulkanLoader.h
index 879b372043..fed9b7ba1f 100644
--- a/Common/GPU/Vulkan/VulkanLoader.h
+++ b/Common/GPU/Vulkan/VulkanLoader.h
@@ -18,6 +18,7 @@
#pragma once
#include "ppsspp_config.h"
+#include "Common/GPU/Vulkan/VulkanDriverVars.h"
#if PPSSPP_PLATFORM(ANDROID)
#define VK_USE_PLATFORM_ANDROID_KHR
@@ -286,6 +287,8 @@ struct VulkanExtensions {
// bool EXT_depth_range_unrestricted; // Allows depth outside [0.0, 1.0] in 32-bit float depth buffers.
};
+void VulkanApplyCustomDriverEnvVars(AdrenoEnvVar envVars);
+
// Way to do a quick check before even attempting to load.
void VulkanSetNativeLibDir(std::string_view nativeLibDir);
bool VulkanMayBeAvailable();
diff --git a/Core/Config.cpp b/Core/Config.cpp
index 9c24f73ee7..c38b8debe3 100644
--- a/Core/Config.cpp
+++ b/Core/Config.cpp
@@ -754,6 +754,8 @@ bool Config::IsBackendEnabled(GPUBackend backend) {
if (backend == GPUBackend::OPENGL)
return false;
#endif
+ // On normal boots, this is where the Vulkan driver gets loaded the first time, in this check.
+ // That's a bit weird actually. But at least the config is loaded.
if (backend == GPUBackend::VULKAN && !VulkanMayBeAvailable())
return false;
return true;
@@ -920,6 +922,7 @@ static constexpr ConfigSetting graphicsSettings[] = {
.Label(I18NCat::GRAPHICS, "External display").Choices(externalDisplayNames),
#if PPSSPP_PLATFORM(ANDROID) && PPSSPP_ARCH(ARM64)
ConfigSetting("CustomDriver", SETTING(g_Config, sCustomDriver), "", CfgFlag::DEFAULT),
+ ConfigSetting("AdrenoDriverVars", SETTING(g_Config, iAdrenoEnvVars), 0, CfgFlag::DEFAULT),
#endif
ConfigSetting("DisabledGraphicsBackends", SETTING(g_Config, sDisabledGPUBackends), "", CfgFlag::DEFAULT),
ConfigSetting("VulkanDevice", SETTING(g_Config, sVulkanDevice), "", CfgFlag::DEFAULT)
@@ -2050,6 +2053,12 @@ void Config::PostLoadCleanup() {
iGPUBackend = (int)GPUBackend::DIRECT3D11;
#endif
+ // IsBackendEnabled below triggers a Vulkan driver load. So we must first apply the environment vars for custom drivers,
+ // so the environment variables are set on load. Not super pretty.
+ if (!g_Config.sCustomDriver.empty()) {
+ VulkanApplyCustomDriverEnvVars((AdrenoEnvVar)g_Config.iAdrenoEnvVars);
+ }
+
if (!IsBackendEnabled((GPUBackend)iGPUBackend)) {
ERROR_LOG(Log::G3D, "Backend %d not enabled - switching to platform default", iGPUBackend);
iGPUBackend = (int)DefaultGPUBackend();
diff --git a/Core/Config.h b/Core/Config.h
index e0ea676739..3a981eafd4 100644
--- a/Core/Config.h
+++ b/Core/Config.h
@@ -301,6 +301,7 @@ public:
int iGPUBackend;
int iExternalDisplay; // ExternalDisplayMode
std::string sCustomDriver;
+ int iAdrenoEnvVars; // AdrenoEnvVars
std::string sFailedGPUBackends; // NOT stored in ppsspp.ini anymore!
std::string sDisabledGPUBackends;
// We have separate device parameters for each backend so it doesn't get erased if you switch backends.
diff --git a/UI/DeveloperSettingsPages.cpp b/UI/DeveloperSettingsPages.cpp
index 1646226516..9e9b995dc6 100644
--- a/UI/DeveloperSettingsPages.cpp
+++ b/UI/DeveloperSettingsPages.cpp
@@ -67,7 +67,7 @@ static bool SupportsCustomDriver() {
static bool SupportsCustomDriver() {
#ifdef _DEBUG
- return false; // change to true to debug driver installation on other platforms
+ return false; // change to true to debug driver installation on other platforms. DO NOT commit as true.
#else
return false;
#endif
diff --git a/UI/DriverManagerScreen.cpp b/UI/DriverManagerScreen.cpp
index 51ae7a6950..91007188c0 100644
--- a/UI/DriverManagerScreen.cpp
+++ b/UI/DriverManagerScreen.cpp
@@ -3,6 +3,7 @@
#include "Common/Data/Text/I18n.h"
#include "Common/System/Request.h"
#include "Common/System/OSD.h"
+#include "Common/GPU/Vulkan/VulkanDriverVars.h"
#include "Common/Log.h"
#include "Common/StringUtils.h"
#include "Common/UI/PopupScreens.h"
@@ -165,12 +166,21 @@ void DriverManagerScreen::CreateDriverTab(UI::ViewGroup *drivers) {
auto di = GetI18NCategory(I18NCat::DIALOG);
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
- ChoiceGroup *driverManagerGroup = drivers->Add(new ChoiceGroupList())->Add(new ChoiceGroup(gr->T("AdrenoTools driver manager")));
+ ChoiceGroupList *groups = drivers->Add(new ChoiceGroupList());
+
+ ChoiceGroup *driverManagerGroup = groups->Add(new ChoiceGroup(gr->T("AdrenoTools driver manager")));
auto customDriverInstallChoice = driverManagerGroup->Add(new Choice(gr->T("Install custom driver...")));
driverManagerGroup->Add(new Choice(di->T("More info")))->OnClick.Add([=](UI::EventParams &e) {
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/docs/reference/custom-drivers/");
});
+ ChoiceGroup *adrenoEnvVarGroup = groups->Add(new ChoiceGroup(gr->T("Turnip driver flags")));
+ int count = 0;
+ const AdrenoEnvVarDef *adrenoEnvVarDefs = GetAdrenoEnvVarDefs(&count);
+ for (int i = 0; i < count; i++) {
+ adrenoEnvVarGroup->Add(new BitCheckBox(&g_Config.iAdrenoEnvVars, (int)adrenoEnvVarDefs[i].var, adrenoEnvVarDefs[i].name));
+ }
+
customDriverInstallChoice->OnClick.Handle(this, &DriverManagerScreen::OnCustomDriverInstall);
drivers->Add(new ItemHeader(gr->T("Drivers")));