mirror of
https://github.com/hrydgard/ppsspp.git
synced 2024-11-23 05:19:56 +00:00
Add a new screen for managing installed Adreno drivers
This commit is contained in:
parent
72c4d346d0
commit
9253bf9cb5
@ -1455,6 +1455,8 @@ list(APPEND NativeAppSource
|
||||
UI/GameScreen.cpp
|
||||
UI/GameSettingsScreen.h
|
||||
UI/GameSettingsScreen.cpp
|
||||
UI/DriverManagerScreen.h
|
||||
UI/DriverManagerScreen.cpp
|
||||
UI/GPUDriverTestScreen.h
|
||||
UI/GPUDriverTestScreen.cpp
|
||||
UI/TiltAnalogSettingsScreen.h
|
||||
|
@ -67,7 +67,7 @@ const JsonNode *JsonGet::get(const char *child_name, JsonTag type) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *JsonGet::getStringOrDie(const char *child_name) const {
|
||||
const char *JsonGet::getStringOrNull(const char *child_name) const {
|
||||
const JsonNode *val = get(child_name, JSON_STRING);
|
||||
if (val)
|
||||
return val->value.toString();
|
||||
@ -75,7 +75,16 @@ const char *JsonGet::getStringOrDie(const char *child_name) const {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
const char *JsonGet::getString(const char *child_name, const char *default_value) const {
|
||||
bool JsonGet::getString(const char *child_name, std::string *output) const {
|
||||
const JsonNode *val = get(child_name, JSON_STRING);
|
||||
if (!val) {
|
||||
return false;
|
||||
}
|
||||
*output = val->value.toString();
|
||||
return true;
|
||||
}
|
||||
|
||||
const char *JsonGet::getStringOr(const char *child_name, const char *default_value) const {
|
||||
const JsonNode *val = get(child_name, JSON_STRING);
|
||||
if (!val)
|
||||
return default_value;
|
||||
|
@ -21,8 +21,9 @@ struct JsonGet {
|
||||
const JsonGet getDict(const char *child_name) const {
|
||||
return JsonGet(get(child_name, JSON_OBJECT)->value);
|
||||
}
|
||||
const char *getStringOrDie(const char *child_name) const;
|
||||
const char *getString(const char *child_name, const char *default_value) const;
|
||||
const char *getStringOrNull(const char *child_name) const;
|
||||
const char *getStringOr(const char *child_name, const char *default_value) const;
|
||||
bool getString(const char *child_name, std::string *output) const;
|
||||
bool getStringVector(std::vector<std::string> *vec) const;
|
||||
double getFloat(const char *child_name) const;
|
||||
double getFloat(const char *child_name, double default_value) const;
|
||||
@ -46,7 +47,7 @@ struct JsonGet {
|
||||
class JsonReader {
|
||||
public:
|
||||
JsonReader(const std::string &filename);
|
||||
// Makes a copy, after this returns you can free the input buffer.
|
||||
// Makes a copy, after this returns you can free the input buffer. Zero termination is not necessary.
|
||||
JsonReader(const char *data, size_t size) {
|
||||
buffer_ = (char *)malloc(size + 1);
|
||||
if (buffer_) {
|
||||
|
@ -62,6 +62,7 @@
|
||||
#include <dirent.h>
|
||||
#include <errno.h>
|
||||
#include <stdlib.h>
|
||||
#include <unistd.h>
|
||||
#endif
|
||||
|
||||
#if defined(__DragonFly__) || defined(__FreeBSD__) || defined(__FreeBSD_kernel__) || defined(__NetBSD__)
|
||||
@ -990,6 +991,19 @@ bool OpenFileInEditor(const Path &fileName) {
|
||||
return true;
|
||||
}
|
||||
|
||||
const Path GetCurDirectory() {
|
||||
#ifdef _WIN32
|
||||
wchar_t buffer[4096];
|
||||
size_t len = GetCurrentDirectory(sizeof(buffer) / sizeof(wchar_t), buffer);
|
||||
std::string curDir = ConvertWStringToUTF8(buffer);
|
||||
return Path(curDir);
|
||||
#else
|
||||
char temp[4096]{};
|
||||
getcwd(temp, 4096);
|
||||
return Path(temp);
|
||||
#endif
|
||||
}
|
||||
|
||||
const Path &GetExeDirectory() {
|
||||
static Path ExePath;
|
||||
|
||||
|
@ -123,6 +123,8 @@ bool OpenFileInEditor(const Path &fileName);
|
||||
// TODO: Belongs in System or something.
|
||||
const Path &GetExeDirectory();
|
||||
|
||||
const Path GetCurDirectory();
|
||||
|
||||
// simple wrapper for cstdlib file functions to
|
||||
// hopefully will make error checking easier
|
||||
// and make forgetting an fclose() harder
|
||||
|
@ -133,7 +133,7 @@ VkResult VulkanContext::CreateInstance(const CreateInfo &info) {
|
||||
#endif
|
||||
#endif
|
||||
|
||||
if ((flags_ & VULKAN_FLAG_VALIDATE) && g_Config.customDriver.empty()) {
|
||||
if ((flags_ & VULKAN_FLAG_VALIDATE) && g_Config.sCustomDriver.empty()) {
|
||||
if (IsInstanceExtensionAvailable(VK_EXT_DEBUG_UTILS_EXTENSION_NAME)) {
|
||||
// Enable the validation layers
|
||||
for (size_t i = 0; i < ARRAY_SIZE(validationLayers); i++) {
|
||||
|
@ -300,40 +300,42 @@ static VulkanLibraryHandle VulkanLoadLibrary(std::string *errorString) {
|
||||
void *lib = nullptr;
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID) && PPSSPP_ARCH(ARM64)
|
||||
if (!g_Config.customDriver.empty() && g_Config.customDriver != "Default") {
|
||||
const Path driverPath = g_Config.internalDataDirectory / "drivers" / g_Config.customDriver;
|
||||
if (!g_Config.sCustomDriver.empty() && g_Config.sCustomDriver != "Default") {
|
||||
const Path driverPath = g_Config.internalDataDirectory / "drivers" / g_Config.sCustomDriver;
|
||||
|
||||
json::JsonReader meta = json::JsonReader((driverPath / "meta.json").c_str());
|
||||
if (meta.ok()) {
|
||||
std::string driverLibName = meta.root().get("libraryName")->value.toString();
|
||||
json::JsonReader meta = json::JsonReader((driverPath / "meta.json").c_str());
|
||||
if (meta.ok()) {
|
||||
std::string driverLibName = meta.root().get("libraryName")->value.toString();
|
||||
|
||||
Path tempDir = g_Config.internalDataDirectory / "temp";
|
||||
Path fileRedirectDir = g_Config.internalDataDirectory / "vk_file_redirect";
|
||||
Path tempDir = g_Config.internalDataDirectory / "temp";
|
||||
Path fileRedirectDir = g_Config.internalDataDirectory / "vk_file_redirect";
|
||||
|
||||
File::CreateDir(tempDir);
|
||||
File::CreateDir(fileRedirectDir);
|
||||
File::CreateDir(tempDir);
|
||||
File::CreateDir(fileRedirectDir);
|
||||
|
||||
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(),
|
||||
(std::string(driverPath.c_str()) + "/").c_str(),driverLibName.c_str(),
|
||||
(std::string(fileRedirectDir.c_str()) + "/").c_str(),nullptr);
|
||||
if (!lib) {
|
||||
ERROR_LOG(G3D, "Failed to load custom driver");
|
||||
}
|
||||
}
|
||||
}
|
||||
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(),
|
||||
(std::string(driverPath.c_str()) + "/").c_str(), driverLibName.c_str(),
|
||||
(std::string(fileRedirectDir.c_str()) + "/").c_str(), nullptr);
|
||||
if (!lib) {
|
||||
ERROR_LOG(G3D, "Failed to load custom driver with AdrenoTools ('%s')", g_Config.sCustomDriver.c_str());
|
||||
} else {
|
||||
INFO_LOG(G3D, "Vulkan library loaded with AdrenoTools ('%s')", g_Config.sCustomDriver.c_str());
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
if (!lib) {
|
||||
for (int i = 0; i < ARRAY_SIZE(so_names); i++) {
|
||||
lib = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL);
|
||||
if (lib) {
|
||||
INFO_LOG(G3D, "Vulkan library loaded with AdrenoTools ('%s')", so_names[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
if (!lib) {
|
||||
for (int i = 0; i < ARRAY_SIZE(so_names); i++) {
|
||||
lib = dlopen(so_names[i], RTLD_NOW | RTLD_LOCAL);
|
||||
if (lib) {
|
||||
INFO_LOG(G3D, "Vulkan library loaded ('%s')", so_names[i]);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
return lib;
|
||||
#endif
|
||||
}
|
||||
|
@ -599,7 +599,7 @@ ItemHeader::ItemHeader(const std::string &text, LayoutParams *layoutParams)
|
||||
}
|
||||
|
||||
void ItemHeader::Draw(UIContext &dc) {
|
||||
dc.SetFontStyle(dc.theme->uiFontSmall);
|
||||
dc.SetFontStyle(large_ ? dc.theme->uiFont : dc.theme->uiFontSmall);
|
||||
dc.DrawText(text_.c_str(), bounds_.x + 4, bounds_.centerY(), dc.theme->headerStyle.fgColor, ALIGN_LEFT | ALIGN_VCENTER);
|
||||
dc.Draw()->DrawImageCenterTexel(dc.theme->whiteImage, bounds_.x, bounds_.y2()-2, bounds_.x2(), bounds_.y2(), dc.theme->headerStyle.fgColor);
|
||||
}
|
||||
|
@ -848,9 +848,10 @@ public:
|
||||
void Draw(UIContext &dc) override;
|
||||
std::string DescribeText() const override;
|
||||
void GetContentDimensionsBySpec(const UIContext &dc, MeasureSpec horiz, MeasureSpec vert, float &w, float &h) const override;
|
||||
|
||||
void SetLarge(bool large) { large_ = large; }
|
||||
private:
|
||||
std::string text_;
|
||||
bool large_ = false;
|
||||
};
|
||||
|
||||
class PopupHeader : public Item {
|
||||
|
@ -592,7 +592,7 @@ static const ConfigSetting graphicsSettings[] = {
|
||||
ConfigSetting("iShowStatusFlags", &g_Config.iShowStatusFlags, 0, CfgFlag::PER_GAME),
|
||||
ConfigSetting("GraphicsBackend", &g_Config.iGPUBackend, &DefaultGPUBackend, &GPUBackendTranslator::To, &GPUBackendTranslator::From, CfgFlag::DEFAULT | CfgFlag::REPORT),
|
||||
#if PPSSPP_PLATFORM(ANDROID) && PPSSPP_ARCH(ARM64)
|
||||
ConfigSetting("CustomDriver", &g_Config.customDriver, "", CfgFlag::DEFAULT),
|
||||
ConfigSetting("CustomDriver", &g_Config.sCustomDriver, "", CfgFlag::DEFAULT),
|
||||
#endif
|
||||
ConfigSetting("FailedGraphicsBackends", &g_Config.sFailedGPUBackends, "", CfgFlag::DEFAULT),
|
||||
ConfigSetting("DisabledGraphicsBackends", &g_Config.sDisabledGPUBackends, "", CfgFlag::DEFAULT),
|
||||
@ -1399,6 +1399,11 @@ void Config::PostLoadCleanup(bool gameSpecific) {
|
||||
if (iTexScalingLevel <= 0) {
|
||||
iTexScalingLevel = 1;
|
||||
}
|
||||
|
||||
// Remove a legacy value.
|
||||
if (g_Config.sCustomDriver == "Default") {
|
||||
g_Config.sCustomDriver = "";
|
||||
}
|
||||
}
|
||||
|
||||
void Config::PreSaveCleanup(bool gameSpecific) {
|
||||
@ -1448,7 +1453,8 @@ void Config::DownloadCompletedCallback(http::Request &download) {
|
||||
return;
|
||||
}
|
||||
|
||||
std::string version = root.getString("version", "");
|
||||
std::string version;
|
||||
root.getString("version", &version);
|
||||
|
||||
const char *gitVer = PPSSPP_GIT_VERSION;
|
||||
Version installed(gitVer);
|
||||
|
@ -149,7 +149,7 @@ public:
|
||||
|
||||
// GFX
|
||||
int iGPUBackend;
|
||||
std::string customDriver;
|
||||
std::string sCustomDriver;
|
||||
std::string sFailedGPUBackends;
|
||||
std::string sDisabledGPUBackends;
|
||||
// We have separate device parameters for each backend so it doesn't get erased if you switch backends.
|
||||
|
@ -165,7 +165,7 @@ void HandleDebuggerRequest(const http::ServerRequest &request) {
|
||||
}
|
||||
|
||||
const JsonGet root = reader.root();
|
||||
const char *event = root ? root.getString("event", nullptr) : nullptr;
|
||||
const char *event = root ? root.getStringOr("event", nullptr) : nullptr;
|
||||
if (!event) {
|
||||
ws->Send(DebuggerErrorEvent("Bad message: no event property", LogLevel::LERROR, root));
|
||||
return;
|
||||
|
@ -219,7 +219,7 @@ static DebuggerRegType ValidateRegName(DebuggerRequest &req, const std::string &
|
||||
}
|
||||
|
||||
static DebuggerRegType ValidateCatReg(DebuggerRequest &req, int *cat, int *reg) {
|
||||
const char *name = req.data.getString("name", nullptr);
|
||||
const char *name = req.data.getStringOr("name", nullptr);
|
||||
if (name)
|
||||
return ValidateRegName(req, name, cat, reg);
|
||||
|
||||
|
268
UI/DriverManagerScreen.cpp
Normal file
268
UI/DriverManagerScreen.cpp
Normal file
@ -0,0 +1,268 @@
|
||||
#include "Common/File/VFS/ZipFileReader.h"
|
||||
#include "Common/Data/Format/JSONReader.h"
|
||||
#include "Common/System/OSD.h"
|
||||
#include "Common/Log.h"
|
||||
#include "Common/StringUtils.h"
|
||||
|
||||
#include "Core/Config.h"
|
||||
#include "Core/System.h"
|
||||
|
||||
#include "UI/View.h"
|
||||
#include "UI/DriverManagerScreen.h"
|
||||
#include "UI/GameSettingsScreen.h" // for triggerrestart
|
||||
#include "UI/OnScreenDisplay.h"
|
||||
|
||||
static Path GetDriverPath() {
|
||||
if (g_Config.internalDataDirectory.empty()) {
|
||||
Path curDir = File::GetCurDirectory();
|
||||
// This is the case when testing on PC
|
||||
return GetSysDirectory(DIRECTORY_PSP) / "drivers";
|
||||
} else {
|
||||
// On Android, this is set to something usable.
|
||||
return g_Config.internalDataDirectory / "drivers";
|
||||
}
|
||||
}
|
||||
|
||||
// Example meta.json:
|
||||
// {
|
||||
// "schemaVersion": 1,
|
||||
// "name" : "Turnip driver revision 14",
|
||||
// "description" : "Compiled from Mesa source.",
|
||||
// "author" : "KIMCHI",
|
||||
// "packageVersion" : "1",
|
||||
// "vendor" : "Mesa",
|
||||
// "driverVersion" : "Vulkan 1.3.274",
|
||||
// "minApi" : 27,
|
||||
// "libraryName" : "vulkan.ad07XX.so"
|
||||
// }
|
||||
|
||||
struct DriverMeta {
|
||||
int minApi;
|
||||
std::string name;
|
||||
std::string description;
|
||||
std::string vendor;
|
||||
std::string driverVersion;
|
||||
|
||||
bool Read(std::string_view str, std::string *errorStr) {
|
||||
// Validate the json file. TODO: Be a bit more detailed.
|
||||
json::JsonReader meta = json::JsonReader((const char *)str.data(), str.size());
|
||||
if (!meta.ok()) {
|
||||
*errorStr = "meta.json not valid json";
|
||||
return false;
|
||||
}
|
||||
|
||||
if (!meta.root().getString("name", &name) || name.empty()) {
|
||||
*errorStr = "missing driver name in json";
|
||||
return false;
|
||||
}
|
||||
meta.root().getString("description", &description);
|
||||
meta.root().getString("vendor", &vendor);
|
||||
meta.root().getString("driverVersion", &driverVersion);
|
||||
minApi = meta.root().getInt("minApi");
|
||||
return true;
|
||||
}
|
||||
};
|
||||
|
||||
// Compound view, creating a FileChooserChoice inside.
|
||||
class DriverChoice : public UI::LinearLayout {
|
||||
public:
|
||||
DriverChoice(const std::string &driverName, bool current, UI::LayoutParams *layoutParams = nullptr);
|
||||
|
||||
UI::Event OnUse;
|
||||
UI::Event OnDelete;
|
||||
std::string name_;
|
||||
};
|
||||
|
||||
static constexpr UI::Size ITEM_HEIGHT = 64.f;
|
||||
|
||||
DriverChoice::DriverChoice(const std::string &driverName, bool current, UI::LayoutParams *layoutParams) : UI::LinearLayout(UI::ORIENT_VERTICAL, layoutParams), name_(driverName) {
|
||||
using namespace UI;
|
||||
SetSpacing(2.0f);
|
||||
if (!layoutParams) {
|
||||
layoutParams_->width = FILL_PARENT;
|
||||
layoutParams_->height = 220;
|
||||
}
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
|
||||
// Read the meta data
|
||||
DriverMeta meta{};
|
||||
bool isDefault = driverName.empty();
|
||||
if (isDefault) {
|
||||
meta.description = "The default installed driver on your system";
|
||||
}
|
||||
|
||||
Path metaPath = GetDriverPath() / driverName / "meta.json";
|
||||
std::string metaJson;
|
||||
if (File::ReadFileToString(true, metaPath, metaJson)) {
|
||||
std::string errorStr;
|
||||
meta.Read(metaJson, &errorStr);
|
||||
}
|
||||
Add(new Spacer(12.0));
|
||||
|
||||
#if PPSSPP_PLATFORM(ANDROID)
|
||||
bool usable = isDefault || meta.minApi <= System_GetPropertyInt(SYSPROP_SYSTEMVERSION);
|
||||
#else
|
||||
// For testing only
|
||||
bool usable = isDefault || true;
|
||||
#endif
|
||||
|
||||
Add(new ItemHeader(driverName.empty() ? gr->T("Default driver") : driverName))->SetLarge(true);
|
||||
if (current) {
|
||||
Add(new NoticeView(NoticeLevel::SUCCESS, gr->T("Current GPU driver"), ""));
|
||||
}
|
||||
|
||||
auto horizBar = Add(new UI::LinearLayout(UI::ORIENT_HORIZONTAL));
|
||||
std::string desc = meta.description;
|
||||
if (!desc.empty()) desc += "\n";
|
||||
if (!isDefault)
|
||||
desc += meta.vendor + ": " + meta.driverVersion;
|
||||
horizBar->Add(new TextView(desc));
|
||||
if (!current && !isDefault) {
|
||||
horizBar->Add(new Choice(ImageID("I_TRASHCAN"), new LinearLayoutParams(ITEM_HEIGHT, ITEM_HEIGHT)))->OnClick.Add([=](UI::EventParams &) {
|
||||
UI::EventParams e{};
|
||||
e.s = name_;
|
||||
OnDelete.Trigger(e);
|
||||
return UI::EVENT_DONE;
|
||||
});
|
||||
}
|
||||
if (usable) {
|
||||
if (!current) {
|
||||
Add(new Choice(gr->T("Use this driver")))->OnClick.Add([=](UI::EventParams &) {
|
||||
UI::EventParams e{};
|
||||
e.s = name_;
|
||||
OnUse.Trigger(e);
|
||||
return UI::EVENT_DONE;
|
||||
});
|
||||
}
|
||||
} else {
|
||||
Add(new NoticeView(NoticeLevel::WARN, ApplySafeSubstitutions(gr->T("Driver requires Android API version %1, current is %2"), meta.minApi, System_GetPropertyInt(SYSPROP_SYSTEMVERSION)),""));
|
||||
}
|
||||
}
|
||||
|
||||
DriverManagerScreen::DriverManagerScreen(const Path & gamePath) : TabbedUIDialogScreenWithGameBackground(gamePath) {}
|
||||
|
||||
void DriverManagerScreen::CreateTabs() {
|
||||
using namespace UI;
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
|
||||
LinearLayout *drivers = AddTab("DriverManagerDrivers", gr->T("Drivers"));
|
||||
CreateDriverTab(drivers);
|
||||
}
|
||||
|
||||
void DriverManagerScreen::CreateDriverTab(UI::ViewGroup *drivers) {
|
||||
using namespace UI;
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
|
||||
drivers->Add(new ItemHeader(gr->T("AdrenoTools driver manager")));
|
||||
auto customDriverInstallChoice = drivers->Add(new Choice(gr->T("Install custom driver...")));
|
||||
drivers->Add(new Choice(di->T("More information...")))->OnClick.Add([=](UI::EventParams &e) {
|
||||
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/docs/reference/custom-drivers/");
|
||||
return UI::EVENT_DONE;
|
||||
});
|
||||
|
||||
customDriverInstallChoice->OnClick.Handle(this, &DriverManagerScreen::OnCustomDriverInstall);
|
||||
|
||||
drivers->Add(new ItemHeader(gr->T("Drivers")));
|
||||
bool isDefault = g_Config.sCustomDriver.empty();
|
||||
drivers->Add(new DriverChoice("", isDefault))->OnUse.Handle(this, &DriverManagerScreen::OnCustomDriverChange);
|
||||
|
||||
const Path driverPath = GetDriverPath();
|
||||
std::vector<File::FileInfo> listing;
|
||||
if (File::GetFilesInDir(driverPath, &listing)) {
|
||||
for (auto driver : listing) {
|
||||
auto choice = drivers->Add(new DriverChoice(driver.name, g_Config.sCustomDriver == driver.name));
|
||||
choice->OnUse.Handle(this, &DriverManagerScreen::OnCustomDriverChange);
|
||||
choice->OnDelete.Handle(this, &DriverManagerScreen::OnCustomDriverUninstall);
|
||||
}
|
||||
}
|
||||
drivers->Add(new Spacer(12.0));
|
||||
}
|
||||
|
||||
UI::EventReturn DriverManagerScreen::OnCustomDriverChange(UI::EventParams &e) {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
|
||||
screenManager()->push(new PromptScreen(gamePath_, di->T("Changing this setting requires PPSSPP to restart."), di->T("Restart"), di->T("Cancel"), [=](bool yes) {
|
||||
if (yes) {
|
||||
INFO_LOG(G3D, "Switching driver to '%s'", e.s.c_str());
|
||||
g_Config.sCustomDriver = e.s;
|
||||
TriggerRestart("GameSettingsScreen::CustomDriverYes", false, gamePath_);
|
||||
}
|
||||
}));
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn DriverManagerScreen::OnCustomDriverUninstall(UI::EventParams &e) {
|
||||
INFO_LOG(G3D, "Uninstalling driver: %s", e.s.c_str());
|
||||
|
||||
Path folder = GetDriverPath() / e.s;
|
||||
File::DeleteDirRecursively(folder);
|
||||
|
||||
RecreateViews();
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn DriverManagerScreen::OnCustomDriverInstall(UI::EventParams &e) {
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
|
||||
System_BrowseForFile(gr->T("Install Custom Driver..."), BrowseFileType::ZIP, [this](const std::string &value, int) {
|
||||
if (value.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
|
||||
Path zipPath = Path(value);
|
||||
|
||||
// Don't bother checking the file extension. Can't always do that with files from Download (they have paths like content://com.android.providers.downloads.documents/document/msf%3A1000001095).
|
||||
// Though, it may be possible to get it in other ways.
|
||||
|
||||
std::unique_ptr<ZipFileReader> zipFileReader = std::unique_ptr<ZipFileReader>(ZipFileReader::Create(zipPath, "", true));
|
||||
if (!zipFileReader) {
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver", "couldn't open zip"));
|
||||
ERROR_LOG(SYSTEM, "Failed to open file '%s' as zip", zipPath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
size_t metaDataSize;
|
||||
uint8_t *metaData = zipFileReader->ReadFile("meta.json", &metaDataSize);
|
||||
if (!metaData) {
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver"), "meta.json missing");
|
||||
return;
|
||||
}
|
||||
|
||||
DriverMeta meta;
|
||||
std::string errorStr;
|
||||
if (!meta.Read(std::string_view((const char *)metaData, metaDataSize), &errorStr)) {
|
||||
delete[] metaData;
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver"), errorStr);
|
||||
return;
|
||||
}
|
||||
delete[] metaData;
|
||||
|
||||
const Path newCustomDriver = GetDriverPath() / meta.name;
|
||||
NOTICE_LOG(G3D, "Installing driver into '%s'", newCustomDriver.c_str());
|
||||
File::CreateFullPath(newCustomDriver);
|
||||
|
||||
std::vector<File::FileInfo> zipListing;
|
||||
zipFileReader->GetFileListing("", &zipListing, nullptr);
|
||||
|
||||
for (auto file : zipListing) {
|
||||
File::CreateEmptyFile(newCustomDriver / file.name);
|
||||
|
||||
size_t size;
|
||||
uint8_t *data = zipFileReader->ReadFile(file.name.c_str(), &size);
|
||||
if (!data) {
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver"), file.name.c_str());
|
||||
return;
|
||||
}
|
||||
File::WriteDataToFile(false, data, size, newCustomDriver / file.name);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
auto iz = GetI18NCategory(I18NCat::INSTALLZIP);
|
||||
g_OSD.Show(OSDType::MESSAGE_SUCCESS, iz->T("Installed!"));
|
||||
RecreateViews();
|
||||
});
|
||||
return UI::EVENT_DONE;
|
||||
}
|
26
UI/DriverManagerScreen.h
Normal file
26
UI/DriverManagerScreen.h
Normal file
@ -0,0 +1,26 @@
|
||||
#pragma once
|
||||
|
||||
#include "ppsspp_config.h"
|
||||
|
||||
#include "Common/UI/UIScreen.h"
|
||||
#include "UI/MiscScreens.h"
|
||||
#include "UI/TabbedDialogScreen.h"
|
||||
|
||||
// Per-game settings screen - enables you to configure graphic options, control options, etc
|
||||
// per game.
|
||||
class DriverManagerScreen : public TabbedUIDialogScreenWithGameBackground {
|
||||
public:
|
||||
DriverManagerScreen(const Path &gamePath);
|
||||
|
||||
const char *tag() const override { return "DriverManagerScreen"; }
|
||||
|
||||
protected:
|
||||
void CreateTabs() override;
|
||||
|
||||
private:
|
||||
UI::EventReturn OnCustomDriverInstall(UI::EventParams &e);
|
||||
UI::EventReturn OnCustomDriverUninstall(UI::EventParams &e);
|
||||
UI::EventReturn OnCustomDriverChange(UI::EventParams &e);
|
||||
|
||||
void CreateDriverTab(UI::ViewGroup *drivers);
|
||||
};
|
@ -39,6 +39,7 @@
|
||||
#include "Common/Data/Text/I18n.h"
|
||||
#include "Common/Data/Encoding/Utf8.h"
|
||||
#include "UI/EmuScreen.h"
|
||||
#include "UI/DriverManagerScreen.h"
|
||||
#include "UI/GameSettingsScreen.h"
|
||||
#include "UI/GameInfoCache.h"
|
||||
#include "UI/GamepadEmu.h"
|
||||
@ -57,8 +58,6 @@
|
||||
#include "UI/RetroAchievementScreens.h"
|
||||
|
||||
#include "Common/File/FileUtil.h"
|
||||
#include "Common/File/VFS/ZipFileReader.h"
|
||||
#include "Common/Data/Format/JSONReader.h"
|
||||
#include "Common/File/AndroidContentURI.h"
|
||||
#include "Common/OSVersion.h"
|
||||
#include "Common/TimeUtil.h"
|
||||
@ -103,20 +102,22 @@ static bool CheckKgslPresent() {
|
||||
return access(KgslPath, F_OK) == 0;
|
||||
}
|
||||
|
||||
bool SupportsCustomDriver() {
|
||||
static bool SupportsCustomDriver() {
|
||||
return android_get_device_api_level() >= 28 && CheckKgslPresent();
|
||||
}
|
||||
|
||||
#else
|
||||
|
||||
bool SupportsCustomDriver() {
|
||||
static bool SupportsCustomDriver() {
|
||||
#ifdef _DEBUG
|
||||
return true;
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
static void TriggerRestart(const char *why, bool editThenRestore, const Path &gamePath);
|
||||
|
||||
GameSettingsScreen::GameSettingsScreen(const Path &gamePath, std::string gameID, bool editThenRestore)
|
||||
: TabbedUIDialogScreenWithGameBackground(gamePath), gameID_(gameID), editThenRestore_(editThenRestore) {
|
||||
prevInflightFrames_ = g_Config.iInflightFrames;
|
||||
@ -1254,93 +1255,6 @@ void GameSettingsScreen::CreateVRSettings(UI::ViewGroup *vrSettings) {
|
||||
vrSettings->Add(new PopupMultiChoice(&g_Config.iCameraPitch, vr->T("Camera type"), cameraPitchModes, 0, 3, I18NCat::NONE, screenManager()));
|
||||
}
|
||||
|
||||
UI::EventReturn DeveloperToolsScreen::OnCustomDriverChange(UI::EventParams &e) {
|
||||
auto di = GetI18NCategory(I18NCat::DIALOG);
|
||||
|
||||
screenManager()->push(new PromptScreen(gamePath_, di->T("Changing this setting requires PPSSPP to restart."), di->T("Restart"), di->T("Cancel"), [=](bool yes) {
|
||||
if (yes) {
|
||||
TriggerRestart("GameSettingsScreen::CustomDriverYes", false, gamePath_);
|
||||
}
|
||||
}));
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn DeveloperToolsScreen::OnCustomDriverInstall(UI::EventParams &e) {
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
|
||||
System_BrowseForFile(gr->T("Install Custom Driver..."), BrowseFileType::ZIP, [this](const std::string &value, int) {
|
||||
if (value.empty()) {
|
||||
return;
|
||||
}
|
||||
|
||||
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
|
||||
|
||||
Path zipPath = Path(value);
|
||||
|
||||
// Don't bother checking the file extension. Can't always do that with files from Download (they have paths like content://com.android.providers.downloads.documents/document/msf%3A1000001095).
|
||||
// Though, it may be possible to get it in other ways.
|
||||
|
||||
std::unique_ptr<ZipFileReader> zipFileReader = std::unique_ptr<ZipFileReader>(ZipFileReader::Create(zipPath, "", true));
|
||||
if (!zipFileReader) {
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver", "couldn't open zip"));
|
||||
ERROR_LOG(SYSTEM, "Failed to open file '%s' as zip", zipPath.c_str());
|
||||
return;
|
||||
}
|
||||
|
||||
size_t metaDataSize;
|
||||
uint8_t *metaData = zipFileReader->ReadFile("meta.json", &metaDataSize);
|
||||
if (!metaData) {
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver"), "meta.json missing");
|
||||
return;
|
||||
}
|
||||
|
||||
// Validate the json file. TODO: Be a bit more detailed.
|
||||
json::JsonReader meta = json::JsonReader((const char *)metaData, metaDataSize);
|
||||
delete[] metaData;
|
||||
if (!meta.ok()) {
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver"), "meta.json not valid json");
|
||||
return;
|
||||
}
|
||||
|
||||
const JsonNode *nameNode = meta.root().get("name");
|
||||
if (!nameNode) {
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver"), "missing driver name in json");
|
||||
return;
|
||||
}
|
||||
|
||||
std::string driverName = nameNode->value.toString();
|
||||
if (driverName.empty()) {
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver"), "driver name empty");
|
||||
return;
|
||||
}
|
||||
|
||||
const Path newCustomDriver = g_Config.internalDataDirectory / "drivers" / driverName;
|
||||
NOTICE_LOG(G3D, "Installing driver into '%s'", newCustomDriver.c_str());
|
||||
File::CreateFullPath(newCustomDriver);
|
||||
|
||||
std::vector<File::FileInfo> zipListing;
|
||||
zipFileReader->GetFileListing("", &zipListing, nullptr);
|
||||
|
||||
for (auto file : zipListing) {
|
||||
File::CreateEmptyFile(newCustomDriver / file.name);
|
||||
|
||||
size_t size;
|
||||
uint8_t *data = zipFileReader->ReadFile(file.name.c_str(), &size);
|
||||
if (!data) {
|
||||
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver"), file.name.c_str());
|
||||
return;
|
||||
}
|
||||
File::WriteDataToFile(false, data, size, newCustomDriver / file.name);
|
||||
delete[] data;
|
||||
}
|
||||
|
||||
auto iz = GetI18NCategory(I18NCat::INSTALLZIP);
|
||||
g_OSD.Show(OSDType::MESSAGE_SUCCESS, iz->T("Installed!"));
|
||||
RecreateViews();
|
||||
});
|
||||
return UI::EVENT_DONE;
|
||||
}
|
||||
|
||||
UI::EventReturn GameSettingsScreen::OnAutoFrameskip(UI::EventParams &e) {
|
||||
g_Config.UpdateAfterSettingAutoFrameSkip();
|
||||
return UI::EVENT_DONE;
|
||||
@ -1562,7 +1476,7 @@ void GameSettingsScreen::CallbackMemstickFolder(bool yes) {
|
||||
}
|
||||
}
|
||||
|
||||
static void TriggerRestart(const char *why, bool editThenRestore, const Path &gamePath) {
|
||||
void TriggerRestart(const char *why, bool editThenRestore, const Path &gamePath) {
|
||||
// Extra save here to make sure the choice really gets saved even if there are shutdown bugs in
|
||||
// the GPU backend code.
|
||||
g_Config.Save(why);
|
||||
@ -1835,22 +1749,11 @@ void DeveloperToolsScreen::CreateViews() {
|
||||
}
|
||||
|
||||
if (GetGPUBackend() == GPUBackend::VULKAN && SupportsCustomDriver()) {
|
||||
const Path driverPath = g_Config.internalDataDirectory / "drivers";
|
||||
|
||||
std::vector<File::FileInfo> listing;
|
||||
File::GetFilesInDir(driverPath, &listing);
|
||||
|
||||
std::vector<std::string> availableDrivers;
|
||||
availableDrivers.push_back("Default");
|
||||
|
||||
for (auto driver : listing) {
|
||||
availableDrivers.push_back(driver.name);
|
||||
}
|
||||
auto driverChoice = list->Add(new PopupMultiChoiceDynamic(&g_Config.customDriver, gr->T("Current GPU Driver"), availableDrivers, I18NCat::NONE, screenManager()));
|
||||
driverChoice->OnChoice.Handle(this, &DeveloperToolsScreen::OnCustomDriverChange);
|
||||
|
||||
auto customDriverInstallChoice = list->Add(new Choice(gr->T("Install Custom Driver...")));
|
||||
customDriverInstallChoice->OnClick.Handle(this, &DeveloperToolsScreen::OnCustomDriverInstall);
|
||||
auto driverChoice = list->Add(new Choice(gr->T("Adreno Driver Manager")));
|
||||
driverChoice->OnClick.Add([=](UI::EventParams &e) {
|
||||
screenManager()->push(new DriverManagerScreen(gamePath_));
|
||||
return UI::EVENT_DONE;
|
||||
});
|
||||
}
|
||||
|
||||
// For now, we only implement GPU driver tests for Vulkan and OpenGL. This is simply
|
||||
|
@ -27,6 +27,8 @@
|
||||
#include "UI/MiscScreens.h"
|
||||
#include "UI/TabbedDialogScreen.h"
|
||||
|
||||
class Path;
|
||||
|
||||
// Per-game settings screen - enables you to configure graphic options, control options, etc
|
||||
// per game.
|
||||
class GameSettingsScreen : public TabbedUIDialogScreenWithGameBackground {
|
||||
@ -151,8 +153,6 @@ private:
|
||||
UI::EventReturn OnFramedumpTest(UI::EventParams &e);
|
||||
UI::EventReturn OnTouchscreenTest(UI::EventParams &e);
|
||||
UI::EventReturn OnCopyStatesToRoot(UI::EventParams &e);
|
||||
UI::EventReturn OnCustomDriverChange(UI::EventParams &e);
|
||||
UI::EventReturn OnCustomDriverInstall(UI::EventParams &e);
|
||||
|
||||
bool allowDebugger_ = false;
|
||||
bool canAllowDebugger_ = true;
|
||||
@ -240,3 +240,5 @@ private:
|
||||
void OnCompleted(DialogResult result) override;
|
||||
int restoreFlags_ = (int)(RestoreSettingsBits::SETTINGS); // RestoreSettingsBits enum
|
||||
};
|
||||
|
||||
void TriggerRestart(const char *why, bool editThenRestore, const Path &gamePath);
|
||||
|
@ -234,7 +234,7 @@ bool RemoteISOConnectScreen::FindServer(std::string &resultHost, int &resultPort
|
||||
if (scanCancelled)
|
||||
return false;
|
||||
|
||||
const char *host = entry.getString("ip", "");
|
||||
const char *host = entry.getStringOr("ip", "");
|
||||
int port = entry.getInt("p", 0);
|
||||
|
||||
if (TryServer(host, port)) {
|
||||
|
10
UI/Store.cpp
10
UI/Store.cpp
@ -475,12 +475,12 @@ void StoreScreen::ParseListing(const std::string &json) {
|
||||
e.type = ENTRY_PBPZIP;
|
||||
e.name = GetTranslatedString(game, "name");
|
||||
e.description = GetTranslatedString(game, "description", "");
|
||||
e.author = game.getString("author", "?");
|
||||
e.author = game.getStringOr("author", "?");
|
||||
e.size = game.getInt("size");
|
||||
e.downloadURL = game.getString("download-url", "");
|
||||
e.iconURL = game.getString("icon-url", "");
|
||||
e.downloadURL = game.getStringOr("download-url", "");
|
||||
e.iconURL = game.getStringOr("icon-url", "");
|
||||
e.hidden = false; // NOTE: Handling of the "hidden" flag is broken in old versions of PPSSPP. Do not use.
|
||||
const char *file = game.getString("file", nullptr);
|
||||
const char *file = game.getStringOr("file", nullptr);
|
||||
if (!file)
|
||||
continue;
|
||||
e.file = file;
|
||||
@ -596,7 +596,7 @@ std::string StoreScreen::GetTranslatedString(const json::JsonGet json, const std
|
||||
}
|
||||
const char *str = nullptr;
|
||||
if (dict) {
|
||||
str = dict.getString(key.c_str(), nullptr);
|
||||
str = dict.getStringOr(key.c_str(), nullptr);
|
||||
}
|
||||
if (str) {
|
||||
return std::string(str);
|
||||
|
@ -44,6 +44,7 @@
|
||||
<ClCompile Include="DevScreens.cpp" />
|
||||
<ClCompile Include="DiscordIntegration.cpp" />
|
||||
<ClCompile Include="DisplayLayoutScreen.cpp" />
|
||||
<ClCompile Include="DriverManagerScreen.cpp" />
|
||||
<ClCompile Include="EmuScreen.cpp" />
|
||||
<ClCompile Include="GameInfoCache.cpp" />
|
||||
<ClCompile Include="GamepadEmu.cpp" />
|
||||
@ -81,6 +82,7 @@
|
||||
<ClInclude Include="DevScreens.h" />
|
||||
<ClInclude Include="DiscordIntegration.h" />
|
||||
<ClInclude Include="DisplayLayoutScreen.h" />
|
||||
<ClInclude Include="DriverManagerScreen.h" />
|
||||
<ClInclude Include="EmuScreen.h" />
|
||||
<ClInclude Include="GameInfoCache.h" />
|
||||
<ClInclude Include="GamepadEmu.h" />
|
||||
|
@ -92,6 +92,9 @@
|
||||
<ClCompile Include="DebugOverlay.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="DriverManagerScreen.cpp">
|
||||
<Filter>Screens</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="GameInfoCache.h" />
|
||||
@ -184,6 +187,9 @@
|
||||
<ClInclude Include="DebugOverlay.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="DriverManagerScreen.h">
|
||||
<Filter>Screens</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Filter Include="Screens">
|
||||
|
@ -119,6 +119,7 @@
|
||||
<ClInclude Include="..\..\UI\DevScreens.h" />
|
||||
<ClInclude Include="..\..\UI\DiscordIntegration.h" />
|
||||
<ClInclude Include="..\..\UI\DisplayLayoutScreen.h" />
|
||||
<ClInclude Include="..\..\UI\DriverManagerScreen.h" />
|
||||
<ClInclude Include="..\..\UI\EmuScreen.h" />
|
||||
<ClInclude Include="..\..\UI\GameInfoCache.h" />
|
||||
<ClInclude Include="..\..\UI\GamepadEmu.h" />
|
||||
@ -157,6 +158,7 @@
|
||||
<ClCompile Include="..\..\UI\DevScreens.cpp" />
|
||||
<ClCompile Include="..\..\UI\DiscordIntegration.cpp" />
|
||||
<ClCompile Include="..\..\UI\DisplayLayoutScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\DriverManagerScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\EmuScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\GameInfoCache.cpp" />
|
||||
<ClCompile Include="..\..\UI\GamepadEmu.cpp" />
|
||||
|
@ -37,6 +37,7 @@
|
||||
<ClCompile Include="..\..\UI\TabbedDialogScreen.cpp" />
|
||||
<ClCompile Include="..\..\UI\RetroAchievementScreens.cpp" />
|
||||
<ClCompile Include="..\..\UI\DebugOverlay.cpp" />
|
||||
<ClCompile Include="..\..\UI\DriverManagerScreen.cpp" />
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="pch.h" />
|
||||
@ -75,5 +76,6 @@
|
||||
<ClInclude Include="..\..\UI\TabbedDialogScreen.h" />
|
||||
<ClInclude Include="..\..\UI\RetroAchievementScreens.h" />
|
||||
<ClInclude Include="..\..\UI\DebugOverlay.h" />
|
||||
<ClInclude Include="..\..\UI\DriverManagerScreen.h" />
|
||||
</ItemGroup>
|
||||
</Project>
|
@ -812,6 +812,7 @@ LOCAL_SRC_FILES := \
|
||||
$(SRC)/UI/ChatScreen.cpp \
|
||||
$(SRC)/UI/DebugOverlay.cpp \
|
||||
$(SRC)/UI/DevScreens.cpp \
|
||||
$(SRC)/UI/DriverManagerScreen.cpp \
|
||||
$(SRC)/UI/DisplayLayoutScreen.cpp \
|
||||
$(SRC)/UI/EmuScreen.cpp \
|
||||
$(SRC)/UI/MainScreen.cpp \
|
||||
|
Loading…
Reference in New Issue
Block a user