CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutSign UpSign In
hrydgard

CoCalc provides the best real-time collaborative environment for Jupyter Notebooks, LaTeX documents, and SageMath, scalable from individual users to large groups and classes!

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