Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
hrydgard
GitHub Repository: hrydgard/ppsspp
Path: blob/master/UI/DriverManagerScreen.cpp
5659 views
1
#include "Common/File/VFS/ZipFileReader.h"
2
#include "Common/Data/Format/JSONReader.h"
3
#include "Common/Data/Text/I18n.h"
4
#include "Common/System/Request.h"
5
#include "Common/System/OSD.h"
6
#include "Common/Log.h"
7
#include "Common/StringUtils.h"
8
#include "Common/UI/PopupScreens.h"
9
#include "Common/UI/Notice.h"
10
11
#include "Core/Config.h"
12
#include "Core/System.h"
13
14
#include "Common/UI/View.h"
15
#include "UI/DriverManagerScreen.h"
16
#include "UI/GameSettingsScreen.h" // for triggerrestart
17
#include "UI/OnScreenDisplay.h"
18
#include "UI/MiscScreens.h"
19
20
static Path GetDriverPath() {
21
if (g_Config.internalDataDirectory.empty()) {
22
Path curDir = File::GetCurDirectory();
23
// This is the case when testing on PC
24
return GetSysDirectory(DIRECTORY_PSP) / "drivers";
25
} else {
26
// On Android, this is set to something usable.
27
return g_Config.internalDataDirectory / "drivers";
28
}
29
}
30
31
// Example meta.json:
32
// {
33
// "schemaVersion": 1,
34
// "name" : "Turnip driver revision 14",
35
// "description" : "Compiled from Mesa source.",
36
// "author" : "KIMCHI",
37
// "packageVersion" : "1",
38
// "vendor" : "Mesa",
39
// "driverVersion" : "Vulkan 1.3.274",
40
// "minApi" : 27,
41
// "libraryName" : "vulkan.ad07XX.so"
42
// }
43
44
struct DriverMeta {
45
int minApi;
46
std::string name;
47
std::string description;
48
std::string vendor;
49
std::string driverVersion;
50
51
bool Read(std::string_view str, std::string *errorStr) {
52
// Validate the json file. TODO: Be a bit more detailed.
53
json::JsonReader meta = json::JsonReader((const char *)str.data(), str.size());
54
if (!meta.ok()) {
55
*errorStr = "meta.json not valid json";
56
return false;
57
}
58
59
int schemaVersion = meta.root().getInt("schemaVersion");
60
if (schemaVersion > 1) {
61
*errorStr = "unknown schemaVersion in meta.json";
62
return false;
63
}
64
65
if (!meta.root().getString("name", &name) || name.empty()) {
66
*errorStr = "missing driver name in json";
67
return false;
68
}
69
meta.root().getString("description", &description);
70
meta.root().getString("vendor", &vendor);
71
meta.root().getString("driverVersion", &driverVersion);
72
minApi = meta.root().getInt("minApi");
73
return true;
74
}
75
};
76
77
// Compound view, creating a FileChooserChoice inside.
78
class DriverChoice : public UI::LinearLayout {
79
public:
80
DriverChoice(const std::string &driverName, bool current, UI::LayoutParams *layoutParams = nullptr);
81
82
UI::Event OnUse;
83
UI::Event OnDelete;
84
std::string name_;
85
};
86
87
DriverChoice::DriverChoice(const std::string &driverName, bool current, UI::LayoutParams *layoutParams) : UI::LinearLayout(ORIENT_VERTICAL, layoutParams), name_(driverName) {
88
using namespace UI;
89
SetSpacing(2.0f);
90
if (!layoutParams) {
91
layoutParams_->width = FILL_PARENT;
92
layoutParams_->height = 220;
93
}
94
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
95
auto di = GetI18NCategory(I18NCat::DIALOG);
96
97
// Read the meta data
98
DriverMeta meta{};
99
bool isDefault = driverName.empty();
100
if (isDefault) {
101
meta.description = gr->T("Default GPU driver");
102
}
103
104
Path metaPath = GetDriverPath() / driverName / "meta.json";
105
std::string metaJson;
106
if (File::ReadTextFileToString(metaPath, &metaJson)) {
107
std::string errorStr;
108
meta.Read(metaJson, &errorStr);
109
}
110
Add(new Spacer(12.0));
111
112
#if PPSSPP_PLATFORM(ANDROID)
113
bool usable = isDefault || meta.minApi <= System_GetPropertyInt(SYSPROP_SYSTEMVERSION);
114
#else
115
// For testing only
116
bool usable = isDefault || true;
117
#endif
118
119
Add(new ItemHeader(driverName.empty() ? gr->T("Default GPU driver") : driverName))->SetLarge(true);
120
if (current) {
121
Add(new NoticeView(NoticeLevel::SUCCESS, gr->T("Current GPU driver"), ""));
122
}
123
124
auto horizBar = Add(new UI::LinearLayout(ORIENT_HORIZONTAL));
125
std::string desc = meta.description;
126
if (!desc.empty()) desc += "\n";
127
if (!isDefault)
128
desc += meta.vendor + ": " + meta.driverVersion;
129
horizBar->Add(new TextView(desc));
130
if (!current && !isDefault) {
131
horizBar->Add(new Choice(ImageID("I_TRASHCAN"), new LinearLayoutParams(ITEM_HEIGHT, ITEM_HEIGHT)))->OnClick.Add([=](UI::EventParams &) {
132
UI::EventParams e{};
133
e.s = name_;
134
OnDelete.Trigger(e);
135
});
136
}
137
if (usable) {
138
if (!current) {
139
Add(new Choice(di->T("Select")))->OnClick.Add([=](UI::EventParams &) {
140
UI::EventParams e{};
141
e.s = name_;
142
OnUse.Trigger(e);
143
});
144
}
145
} else {
146
Add(new NoticeView(NoticeLevel::WARN, ApplySafeSubstitutions(gr->T("Driver requires Android API version %1, current is %2"), meta.minApi, System_GetPropertyInt(SYSPROP_SYSTEMVERSION)),""));
147
}
148
}
149
150
DriverManagerScreen::DriverManagerScreen(const Path & gamePath) : UITabbedBaseDialogScreen(gamePath) {}
151
152
void DriverManagerScreen::CreateTabs() {
153
using namespace UI;
154
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
155
156
AddTab("DriverManagerDrivers", gr->T("Drivers"), [this](UI::LinearLayout *parent) {
157
CreateDriverTab(parent);
158
});
159
}
160
161
void DriverManagerScreen::CreateDriverTab(UI::ViewGroup *drivers) {
162
using namespace UI;
163
auto di = GetI18NCategory(I18NCat::DIALOG);
164
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
165
166
drivers->Add(new ItemHeader(gr->T("AdrenoTools driver manager")));
167
auto customDriverInstallChoice = drivers->Add(new Choice(gr->T("Install custom driver...")));
168
drivers->Add(new Choice(di->T("More info")))->OnClick.Add([=](UI::EventParams &e) {
169
System_LaunchUrl(LaunchUrlType::BROWSER_URL, "https://www.ppsspp.org/docs/reference/custom-drivers/");
170
});
171
172
customDriverInstallChoice->OnClick.Handle(this, &DriverManagerScreen::OnCustomDriverInstall);
173
174
drivers->Add(new ItemHeader(gr->T("Drivers")));
175
bool isDefault = g_Config.sCustomDriver.empty();
176
drivers->Add(new DriverChoice("", isDefault))->OnUse.Handle(this, &DriverManagerScreen::OnCustomDriverChange);
177
178
const Path driverPath = GetDriverPath();
179
std::vector<File::FileInfo> listing;
180
if (File::GetFilesInDir(driverPath, &listing)) {
181
for (auto driver : listing) {
182
auto choice = drivers->Add(new DriverChoice(driver.name, g_Config.sCustomDriver == driver.name));
183
choice->OnUse.Handle(this, &DriverManagerScreen::OnCustomDriverChange);
184
choice->OnDelete.Handle(this, &DriverManagerScreen::OnCustomDriverUninstall);
185
}
186
}
187
drivers->Add(new Spacer(12.0));
188
}
189
190
void DriverManagerScreen::OnCustomDriverChange(UI::EventParams &e) {
191
auto di = GetI18NCategory(I18NCat::DIALOG);
192
193
screenManager()->push(new PromptScreen(gamePath_, di->T("Changing this setting requires PPSSPP to restart."), di->T("Restart"), di->T("Cancel"), [=](bool yes) {
194
if (yes) {
195
INFO_LOG(Log::G3D, "Switching driver to '%s'", e.s.c_str());
196
g_Config.sCustomDriver = e.s;
197
TriggerRestart("GameSettingsScreen::CustomDriverYes", false, gamePath_);
198
}
199
}));
200
}
201
202
void DriverManagerScreen::OnCustomDriverUninstall(UI::EventParams &e) {
203
if (e.s.empty()) {
204
return;
205
}
206
INFO_LOG(Log::G3D, "Uninstalling driver: %s", e.s.c_str());
207
208
Path folder = GetDriverPath() / e.s;
209
File::DeleteDirRecursively(folder);
210
211
RecreateViews();
212
}
213
214
void DriverManagerScreen::OnCustomDriverInstall(UI::EventParams &e) {
215
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
216
217
System_BrowseForFile(GetRequesterToken(), gr->T("Install custom driver..."), BrowseFileType::ZIP, [this](const std::string &value, int) {
218
if (value.empty()) {
219
return;
220
}
221
222
auto gr = GetI18NCategory(I18NCat::GRAPHICS);
223
224
Path zipPath = Path(value);
225
226
// 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).
227
// Though, it may be possible to get it in other ways.
228
229
std::unique_ptr<ZipFileReader> zipFileReader = std::unique_ptr<ZipFileReader>(ZipFileReader::Create(zipPath, "", true));
230
if (!zipFileReader) {
231
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver", "couldn't open zip"));
232
ERROR_LOG(Log::System, "Failed to open file '%s' as zip", zipPath.c_str());
233
return;
234
}
235
236
size_t metaDataSize;
237
uint8_t *metaData = zipFileReader->ReadFile("meta.json", &metaDataSize);
238
if (!metaData) {
239
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver"), "meta.json missing");
240
return;
241
}
242
243
DriverMeta meta;
244
std::string errorStr;
245
if (!meta.Read(std::string_view((const char *)metaData, metaDataSize), &errorStr)) {
246
delete[] metaData;
247
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver"), errorStr);
248
return;
249
}
250
delete[] metaData;
251
252
const Path newCustomDriver = GetDriverPath() / meta.name;
253
NOTICE_LOG(Log::G3D, "Installing driver into '%s'", newCustomDriver.c_str());
254
File::CreateFullPath(newCustomDriver);
255
256
std::vector<File::FileInfo> zipListing;
257
zipFileReader->GetFileListing("", &zipListing, nullptr);
258
259
for (auto file : zipListing) {
260
File::CreateEmptyFile(newCustomDriver / file.name);
261
262
size_t size;
263
uint8_t *data = zipFileReader->ReadFile(file.name.c_str(), &size);
264
if (!data) {
265
g_OSD.Show(OSDType::MESSAGE_ERROR, gr->T("The chosen ZIP file doesn't contain a valid driver"), file.name.c_str());
266
return;
267
}
268
File::WriteDataToFile(false, data, size, newCustomDriver / file.name);
269
delete[] data;
270
}
271
272
auto iz = GetI18NCategory(I18NCat::INSTALLZIP);
273
g_OSD.Show(OSDType::MESSAGE_SUCCESS, iz->T("Installed!"));
274
RecreateViews();
275
});
276
}
277
278