mirror of
https://github.com/Lime3DS/Lime3DS
synced 2024-12-25 16:42:39 -06:00
parent
51b6c6b848
commit
2e4f53ec2b
26 changed files with 436 additions and 28 deletions
|
@ -264,6 +264,8 @@ void Config::ReadValues() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Web Service
|
// Web Service
|
||||||
|
NetSettings::values.enable_telemetry =
|
||||||
|
sdl2_config->GetBoolean("WebService", "enable_telemetry", false);
|
||||||
NetSettings::values.web_api_url =
|
NetSettings::values.web_api_url =
|
||||||
sdl2_config->GetString("WebService", "web_api_url", "https://api.citra-emu.org");
|
sdl2_config->GetString("WebService", "web_api_url", "https://api.citra-emu.org");
|
||||||
NetSettings::values.citra_username = sdl2_config->GetString("WebService", "citra_username", "");
|
NetSettings::values.citra_username = sdl2_config->GetString("WebService", "citra_username", "");
|
||||||
|
|
|
@ -353,6 +353,9 @@ gdbstub_port=24689
|
||||||
# To LLE a service module add "LLE\<module name>=true"
|
# To LLE a service module add "LLE\<module name>=true"
|
||||||
|
|
||||||
[WebService]
|
[WebService]
|
||||||
|
# Whether or not to enable telemetry
|
||||||
|
# 0 (default): No, 1: Yes
|
||||||
|
enable_telemetry =
|
||||||
# URL for Web API
|
# URL for Web API
|
||||||
web_api_url = https://api.citra-emu.org
|
web_api_url = https://api.citra-emu.org
|
||||||
# Username and token for Citra Web Service
|
# Username and token for Citra Web Service
|
||||||
|
|
|
@ -38,6 +38,7 @@
|
||||||
#include "core/hle/service/nfc/nfc.h"
|
#include "core/hle/service/nfc/nfc.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
#include "core/savestate.h"
|
#include "core/savestate.h"
|
||||||
|
#include "core/telemetry_session.h"
|
||||||
#include "jni/android_common/android_common.h"
|
#include "jni/android_common/android_common.h"
|
||||||
#include "jni/applets/mii_selector.h"
|
#include "jni/applets/mii_selector.h"
|
||||||
#include "jni/applets/swkbd.h"
|
#include "jni/applets/swkbd.h"
|
||||||
|
@ -165,7 +166,7 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
||||||
#elif ENABLE_VULKAN
|
#elif ENABLE_VULKAN
|
||||||
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library);
|
window = std::make_unique<EmuWindow_Android_Vulkan>(s_surf, vulkan_library);
|
||||||
#else
|
#else
|
||||||
// TODO: Add a null renderer backend for this, perhaps.
|
// TODO: Add a null renderer backend for this, perhaps.
|
||||||
#error "At least one renderer must be enabled."
|
#error "At least one renderer must be enabled."
|
||||||
#endif
|
#endif
|
||||||
break;
|
break;
|
||||||
|
@ -207,6 +208,9 @@ static Core::System::ResultStatus RunCitra(const std::string& filepath) {
|
||||||
return load_result;
|
return load_result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
auto& telemetry_session = system.TelemetrySession();
|
||||||
|
telemetry_session.AddField(Common::Telemetry::FieldType::App, "Frontend", "Android");
|
||||||
|
|
||||||
stop_run = false;
|
stop_run = false;
|
||||||
pause_emulation = false;
|
pause_emulation = false;
|
||||||
|
|
||||||
|
|
|
@ -12,10 +12,10 @@ namespace Common {
|
||||||
/**
|
/**
|
||||||
* A background manager which ensures that all detached task is finished before program exits.
|
* A background manager which ensures that all detached task is finished before program exits.
|
||||||
*
|
*
|
||||||
* Some tasks prefer executing asynchronously and don't care
|
* Some tasks, telemetry submission for example, prefer executing asynchronously and don't care
|
||||||
* about the result. These tasks are suitable for std::thread::detach().
|
* about the result. These tasks are suitable for std::thread::detach(). However, this is unsafe if
|
||||||
* However, this is unsafe if the task is launched just before the program exits
|
* the task is launched just before the program exits (which is a common case for telemetry), so we
|
||||||
* so we need to block on these tasks on program exit.
|
* need to block on these tasks on program exit.
|
||||||
*
|
*
|
||||||
* To make detached task safe, a single DetachedTasks object should be placed in the main(), and
|
* To make detached task safe, a single DetachedTasks object should be placed in the main(), and
|
||||||
* call WaitForAllTasks() after all program execution but before global/static variable destruction.
|
* call WaitForAllTasks() after all program execution but before global/static variable destruction.
|
||||||
|
|
|
@ -310,6 +310,7 @@ System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::st
|
||||||
restore_plugin_context.reset();
|
restore_plugin_context.reset();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
telemetry_session->AddInitialInfo(*app_loader);
|
||||||
std::shared_ptr<Kernel::Process> process;
|
std::shared_ptr<Kernel::Process> process;
|
||||||
const Loader::ResultStatus load_result{app_loader->Load(process)};
|
const Loader::ResultStatus load_result{app_loader->Load(process)};
|
||||||
if (Loader::ResultStatus::Success != load_result) {
|
if (Loader::ResultStatus::Success != load_result) {
|
||||||
|
@ -565,6 +566,17 @@ void System::RegisterImageInterface(std::shared_ptr<Frontend::ImageInterface> im
|
||||||
}
|
}
|
||||||
|
|
||||||
void System::Shutdown(bool is_deserializing) {
|
void System::Shutdown(bool is_deserializing) {
|
||||||
|
// Log last frame performance stats
|
||||||
|
const auto perf_results = GetAndResetPerfStats();
|
||||||
|
constexpr auto performance = Common::Telemetry::FieldType::Performance;
|
||||||
|
|
||||||
|
telemetry_session->AddField(performance, "Shutdown_EmulationSpeed",
|
||||||
|
perf_results.emulation_speed * 100.0);
|
||||||
|
telemetry_session->AddField(performance, "Shutdown_Framerate", perf_results.game_fps);
|
||||||
|
telemetry_session->AddField(performance, "Shutdown_Frametime", perf_results.frametime * 1000.0);
|
||||||
|
telemetry_session->AddField(performance, "Mean_Frametime_MS",
|
||||||
|
perf_stats ? perf_stats->GetMeanFrametime() : 0);
|
||||||
|
|
||||||
// Shutdown emulation session
|
// Shutdown emulation session
|
||||||
is_powered_on = false;
|
is_powered_on = false;
|
||||||
|
|
||||||
|
|
|
@ -34,6 +34,7 @@
|
||||||
#include "core/hw/aes/ccm.h"
|
#include "core/hw/aes/ccm.h"
|
||||||
#include "core/hw/aes/key.h"
|
#include "core/hw/aes/key.h"
|
||||||
#include "core/loader/loader.h"
|
#include "core/loader/loader.h"
|
||||||
|
#include "core/telemetry_session.h"
|
||||||
|
|
||||||
SERVICE_CONSTRUCT_IMPL(Service::APT::Module)
|
SERVICE_CONSTRUCT_IMPL(Service::APT::Module)
|
||||||
|
|
||||||
|
@ -273,6 +274,10 @@ void Module::APTInterface::GetSharedFont(Kernel::HLERequestContext& ctx) {
|
||||||
IPC::RequestParser rp(ctx);
|
IPC::RequestParser rp(ctx);
|
||||||
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
|
IPC::RequestBuilder rb = rp.MakeBuilder(2, 2);
|
||||||
|
|
||||||
|
// Log in telemetry if the game uses the shared font
|
||||||
|
apt->system.TelemetrySession().AddField(Common::Telemetry::FieldType::Session,
|
||||||
|
"RequiresSharedFont", true);
|
||||||
|
|
||||||
if (!apt->shared_font_loaded) {
|
if (!apt->shared_font_loaded) {
|
||||||
// On real 3DS, font loading happens on booting. However, we load it on demand to coordinate
|
// On real 3DS, font loading happens on booting. However, we load it on demand to coordinate
|
||||||
// with CFG region auto configuration, which happens later than APT initialization.
|
// with CFG region auto configuration, which happens later than APT initialization.
|
||||||
|
|
|
@ -26,6 +26,7 @@
|
||||||
#include "core/loader/smdh.h"
|
#include "core/loader/smdh.h"
|
||||||
#include "core/memory.h"
|
#include "core/memory.h"
|
||||||
#include "core/system_titles.h"
|
#include "core/system_titles.h"
|
||||||
|
#include "core/telemetry_session.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
|
|
||||||
namespace Loader {
|
namespace Loader {
|
||||||
|
@ -273,6 +274,9 @@ ResultStatus AppLoader_NCCH::Load(std::shared_ptr<Kernel::Process>& process) {
|
||||||
overlay_ncch = &update_ncch;
|
overlay_ncch = &update_ncch;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
system.TelemetrySession().AddField(Common::Telemetry::FieldType::Session, "ProgramId",
|
||||||
|
program_id);
|
||||||
|
|
||||||
if (auto room_member = Network::GetRoomMember().lock()) {
|
if (auto room_member = Network::GetRoomMember().lock()) {
|
||||||
Network::GameInfo game_info;
|
Network::GameInfo game_info;
|
||||||
ReadTitle(game_info.name);
|
ReadTitle(game_info.name);
|
||||||
|
|
|
@ -326,6 +326,8 @@ void Config::ReadValues() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Web Service
|
// Web Service
|
||||||
|
NetSettings::values.enable_telemetry =
|
||||||
|
sdl2_config->GetBoolean("WebService", "enable_telemetry", false);
|
||||||
NetSettings::values.web_api_url =
|
NetSettings::values.web_api_url =
|
||||||
sdl2_config->GetString("WebService", "web_api_url", "https://api.citra-emu.org");
|
sdl2_config->GetString("WebService", "web_api_url", "https://api.citra-emu.org");
|
||||||
NetSettings::values.citra_username = sdl2_config->GetString("WebService", "citra_username", "");
|
NetSettings::values.citra_username = sdl2_config->GetString("WebService", "citra_username", "");
|
||||||
|
|
|
@ -361,6 +361,9 @@ renderer_debug =
|
||||||
# To LLE a service module add "LLE\<module name>=true"
|
# To LLE a service module add "LLE\<module name>=true"
|
||||||
|
|
||||||
[WebService]
|
[WebService]
|
||||||
|
# Whether or not to enable telemetry
|
||||||
|
# 0 (default): No, 1: Yes
|
||||||
|
enable_telemetry =
|
||||||
# URL for Web API
|
# URL for Web API
|
||||||
web_api_url = https://api.citra-emu.org
|
web_api_url = https://api.citra-emu.org
|
||||||
# Username and token for Citra Web Service
|
# Username and token for Citra Web Service
|
||||||
|
|
|
@ -39,6 +39,7 @@
|
||||||
#include "core/hle/service/am/am.h"
|
#include "core/hle/service/am/am.h"
|
||||||
#include "core/hle/service/cfg/cfg.h"
|
#include "core/hle/service/cfg/cfg.h"
|
||||||
#include "core/movie.h"
|
#include "core/movie.h"
|
||||||
|
#include "core/telemetry_session.h"
|
||||||
#include "input_common/main.h"
|
#include "input_common/main.h"
|
||||||
#include "network/network.h"
|
#include "network/network.h"
|
||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
|
@ -385,7 +386,7 @@ int main(int argc, char** argv) {
|
||||||
#elif ENABLE_SOFTWARE_RENDERER
|
#elif ENABLE_SOFTWARE_RENDERER
|
||||||
return std::make_unique<EmuWindow_SDL2_SW>(system, fullscreen, is_secondary);
|
return std::make_unique<EmuWindow_SDL2_SW>(system, fullscreen, is_secondary);
|
||||||
#else
|
#else
|
||||||
// TODO: Add a null renderer backend for this, perhaps.
|
// TODO: Add a null renderer backend for this, perhaps.
|
||||||
#error "At least one renderer must be enabled."
|
#error "At least one renderer must be enabled."
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
|
@ -435,6 +436,8 @@ int main(int argc, char** argv) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "SDL");
|
||||||
|
|
||||||
if (use_multiplayer) {
|
if (use_multiplayer) {
|
||||||
if (auto member = Network::GetRoomMember().lock()) {
|
if (auto member = Network::GetRoomMember().lock()) {
|
||||||
member->BindOnChatMessageRecieved(OnMessageReceived);
|
member->BindOnChatMessageRecieved(OnMessageReceived);
|
||||||
|
|
|
@ -6,13 +6,15 @@
|
||||||
#include <QMessageBox>
|
#include <QMessageBox>
|
||||||
#include <QPushButton>
|
#include <QPushButton>
|
||||||
#include <QtConcurrent/qtconcurrentrun.h>
|
#include <QtConcurrent/qtconcurrentrun.h>
|
||||||
|
#include "common/telemetry.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/telemetry_session.h"
|
||||||
#include "lime_qt/compatdb.h"
|
#include "lime_qt/compatdb.h"
|
||||||
#include "ui_compatdb.h"
|
#include "ui_compatdb.h"
|
||||||
|
|
||||||
CompatDB::CompatDB(QWidget* parent)
|
CompatDB::CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent)
|
||||||
: QWizard(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
|
: QWizard(parent, Qt::WindowTitleHint | Qt::WindowCloseButtonHint | Qt::WindowSystemMenuHint),
|
||||||
ui{std::make_unique<Ui::CompatDB>()} {
|
ui{std::make_unique<Ui::CompatDB>()}, telemetry_session{telemetry_session_} {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
connect(ui->radioButton_Perfect, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
connect(ui->radioButton_Perfect, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
||||||
connect(ui->radioButton_Great, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
connect(ui->radioButton_Great, &QRadioButton::clicked, this, &CompatDB::EnableNext);
|
||||||
|
@ -50,11 +52,15 @@ void CompatDB::Submit() {
|
||||||
case CompatDBPage::Final:
|
case CompatDBPage::Final:
|
||||||
back();
|
back();
|
||||||
LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
|
LOG_DEBUG(Frontend, "Compatibility Rating: {}", compatibility->checkedId());
|
||||||
|
telemetry_session.AddField(Common::Telemetry::FieldType::UserFeedback, "Compatibility",
|
||||||
|
compatibility->checkedId());
|
||||||
|
|
||||||
button(NextButton)->setEnabled(false);
|
button(NextButton)->setEnabled(false);
|
||||||
button(NextButton)->setText(tr("Submitting"));
|
button(NextButton)->setText(tr("Submitting"));
|
||||||
button(CancelButton)->setVisible(false);
|
button(CancelButton)->setVisible(false);
|
||||||
|
|
||||||
|
testcase_watcher.setFuture(
|
||||||
|
QtConcurrent::run([this] { return telemetry_session.SubmitTestcase(); }));
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
|
LOG_ERROR(Frontend, "Unexpected page: {}", currentId());
|
||||||
|
|
|
@ -8,6 +8,10 @@
|
||||||
#include <QFutureWatcher>
|
#include <QFutureWatcher>
|
||||||
#include <QWizard>
|
#include <QWizard>
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class TelemetrySession;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Ui {
|
namespace Ui {
|
||||||
class CompatDB;
|
class CompatDB;
|
||||||
}
|
}
|
||||||
|
@ -16,7 +20,7 @@ class CompatDB : public QWizard {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
|
|
||||||
public:
|
public:
|
||||||
explicit CompatDB(QWidget* parent = nullptr);
|
explicit CompatDB(Core::TelemetrySession& telemetry_session_, QWidget* parent = nullptr);
|
||||||
~CompatDB();
|
~CompatDB();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -27,4 +31,6 @@ private:
|
||||||
void Submit();
|
void Submit();
|
||||||
void OnTestcaseSubmitted();
|
void OnTestcaseSubmitted();
|
||||||
void EnableNext();
|
void EnableNext();
|
||||||
|
|
||||||
|
Core::TelemetrySession& telemetry_session;
|
||||||
};
|
};
|
||||||
|
|
|
@ -836,6 +836,8 @@ void Config::ReadUpdaterValues() {
|
||||||
void Config::ReadWebServiceValues() {
|
void Config::ReadWebServiceValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("WebService"));
|
qt_config->beginGroup(QStringLiteral("WebService"));
|
||||||
|
|
||||||
|
NetSettings::values.enable_telemetry =
|
||||||
|
ReadSetting(QStringLiteral("enable_telemetry"), false).toBool();
|
||||||
NetSettings::values.web_api_url =
|
NetSettings::values.web_api_url =
|
||||||
ReadSetting(QStringLiteral("web_api_url"), QStringLiteral("https://api.citra-emu.org"))
|
ReadSetting(QStringLiteral("web_api_url"), QStringLiteral("https://api.citra-emu.org"))
|
||||||
.toString()
|
.toString()
|
||||||
|
@ -1315,6 +1317,7 @@ void Config::SaveUpdaterValues() {
|
||||||
void Config::SaveWebServiceValues() {
|
void Config::SaveWebServiceValues() {
|
||||||
qt_config->beginGroup(QStringLiteral("WebService"));
|
qt_config->beginGroup(QStringLiteral("WebService"));
|
||||||
|
|
||||||
|
WriteSetting(QStringLiteral("enable_telemetry"), NetSettings::values.enable_telemetry, false);
|
||||||
WriteSetting(QStringLiteral("web_api_url"),
|
WriteSetting(QStringLiteral("web_api_url"),
|
||||||
QString::fromStdString(NetSettings::values.web_api_url),
|
QString::fromStdString(NetSettings::values.web_api_url),
|
||||||
QStringLiteral("https://api.citra-emu.org"));
|
QStringLiteral("https://api.citra-emu.org"));
|
||||||
|
|
|
@ -57,6 +57,7 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry_, Cor
|
||||||
ui->tabWidget->addTab(ui_tab.get(), tr("UI"));
|
ui->tabWidget->addTab(ui_tab.get(), tr("UI"));
|
||||||
|
|
||||||
hotkeys_tab->Populate(registry);
|
hotkeys_tab->Populate(registry);
|
||||||
|
web_tab->SetWebServiceConfigEnabled(enable_web_config);
|
||||||
|
|
||||||
PopulateSelectionList();
|
PopulateSelectionList();
|
||||||
|
|
||||||
|
|
|
@ -11,12 +11,41 @@
|
||||||
#include "network/network_settings.h"
|
#include "network/network_settings.h"
|
||||||
#include "ui_configure_web.h"
|
#include "ui_configure_web.h"
|
||||||
|
|
||||||
|
static constexpr char token_delimiter{':'};
|
||||||
|
|
||||||
|
static std::string GenerateDisplayToken(const std::string& username, const std::string& token) {
|
||||||
|
if (username.empty() || token.empty()) {
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string unencoded_display_token{username + token_delimiter + token};
|
||||||
|
QByteArray b{unencoded_display_token.c_str()};
|
||||||
|
QByteArray b64 = b.toBase64();
|
||||||
|
return b64.toStdString();
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string UsernameFromDisplayToken(const std::string& display_token) {
|
||||||
|
const std::string unencoded_display_token{
|
||||||
|
QByteArray::fromBase64(display_token.c_str()).toStdString()};
|
||||||
|
return unencoded_display_token.substr(0, unencoded_display_token.find(token_delimiter));
|
||||||
|
}
|
||||||
|
|
||||||
|
static std::string TokenFromDisplayToken(const std::string& display_token) {
|
||||||
|
const std::string unencoded_display_token{
|
||||||
|
QByteArray::fromBase64(display_token.c_str()).toStdString()};
|
||||||
|
return unencoded_display_token.substr(unencoded_display_token.find(token_delimiter) + 1);
|
||||||
|
}
|
||||||
|
|
||||||
ConfigureWeb::ConfigureWeb(QWidget* parent)
|
ConfigureWeb::ConfigureWeb(QWidget* parent)
|
||||||
: QWidget(parent), ui(std::make_unique<Ui::ConfigureWeb>()) {
|
: QWidget(parent), ui(std::make_unique<Ui::ConfigureWeb>()) {
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
|
connect(ui->button_regenerate_telemetry_id, &QPushButton::clicked, this,
|
||||||
|
&ConfigureWeb::RefreshTelemetryID);
|
||||||
|
connect(ui->button_verify_login, &QPushButton::clicked, this, &ConfigureWeb::VerifyLogin);
|
||||||
|
connect(&verify_watcher, &QFutureWatcher<bool>::finished, this, &ConfigureWeb::OnLoginVerified);
|
||||||
|
|
||||||
#ifndef USE_DISCORD_PRESENCE
|
#ifndef USE_DISCORD_PRESENCE
|
||||||
ui->discord_group->setEnabled(false);
|
ui->discord_group->setVisible(false);
|
||||||
#endif
|
#endif
|
||||||
SetConfiguration();
|
SetConfiguration();
|
||||||
}
|
}
|
||||||
|
@ -24,13 +53,113 @@ ConfigureWeb::ConfigureWeb(QWidget* parent)
|
||||||
ConfigureWeb::~ConfigureWeb() = default;
|
ConfigureWeb::~ConfigureWeb() = default;
|
||||||
|
|
||||||
void ConfigureWeb::SetConfiguration() {
|
void ConfigureWeb::SetConfiguration() {
|
||||||
|
ui->web_credentials_disclaimer->setWordWrap(true);
|
||||||
|
ui->telemetry_learn_more->setOpenExternalLinks(true);
|
||||||
|
ui->telemetry_learn_more->setText(tr("<a "
|
||||||
|
"href='https://citra-emu.org/entry/"
|
||||||
|
"telemetry-and-why-thats-a-good-thing/'><span "
|
||||||
|
"style=\"text-decoration: underline; "
|
||||||
|
"color:#039be5;\">Learn more</span></a>"));
|
||||||
|
|
||||||
|
ui->web_signup_link->setOpenExternalLinks(true);
|
||||||
|
ui->web_signup_link->setText(
|
||||||
|
tr("<a href='https://profile.citra-emu.org/'><span style=\"text-decoration: underline; "
|
||||||
|
"color:#039be5;\">Sign up</span></a>"));
|
||||||
|
ui->web_token_info_link->setOpenExternalLinks(true);
|
||||||
|
ui->web_token_info_link->setText(
|
||||||
|
tr("<a href='https://citra-emu.org/wiki/citra-web-service/'><span style=\"text-decoration: "
|
||||||
|
"underline; color:#039be5;\">What is my token?</span></a>"));
|
||||||
|
|
||||||
|
ui->toggle_telemetry->setChecked(NetSettings::values.enable_telemetry);
|
||||||
|
|
||||||
|
if (NetSettings::values.citra_username.empty()) {
|
||||||
|
ui->username->setText(tr("Unspecified"));
|
||||||
|
} else {
|
||||||
|
ui->username->setText(QString::fromStdString(NetSettings::values.citra_username));
|
||||||
|
}
|
||||||
|
|
||||||
|
ui->edit_token->setText(QString::fromStdString(
|
||||||
|
GenerateDisplayToken(NetSettings::values.citra_username, NetSettings::values.citra_token)));
|
||||||
|
|
||||||
|
// Connect after setting the values, to avoid calling OnLoginChanged now
|
||||||
|
connect(ui->edit_token, &QLineEdit::textChanged, this, &ConfigureWeb::OnLoginChanged);
|
||||||
|
ui->label_telemetry_id->setText(
|
||||||
|
tr("Telemetry ID: 0x%1").arg(QString::number(Core::GetTelemetryId(), 16).toUpper()));
|
||||||
|
user_verified = true;
|
||||||
|
|
||||||
ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence.GetValue());
|
ui->toggle_discordrpc->setChecked(UISettings::values.enable_discord_presence.GetValue());
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureWeb::ApplyConfiguration() {
|
void ConfigureWeb::ApplyConfiguration() {
|
||||||
|
NetSettings::values.enable_telemetry = ui->toggle_telemetry->isChecked();
|
||||||
UISettings::values.enable_discord_presence = ui->toggle_discordrpc->isChecked();
|
UISettings::values.enable_discord_presence = ui->toggle_discordrpc->isChecked();
|
||||||
|
if (user_verified) {
|
||||||
|
NetSettings::values.citra_username =
|
||||||
|
UsernameFromDisplayToken(ui->edit_token->text().toStdString());
|
||||||
|
NetSettings::values.citra_token =
|
||||||
|
TokenFromDisplayToken(ui->edit_token->text().toStdString());
|
||||||
|
} else {
|
||||||
|
QMessageBox::warning(
|
||||||
|
this, tr("Token not verified"),
|
||||||
|
tr("Token was not verified. The change to your token has not been saved."));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureWeb::RefreshTelemetryID() {
|
||||||
|
const u64 new_telemetry_id{Core::RegenerateTelemetryId()};
|
||||||
|
ui->label_telemetry_id->setText(
|
||||||
|
tr("Telemetry ID: 0x%1").arg(QString::number(new_telemetry_id, 16).toUpper()));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureWeb::OnLoginChanged() {
|
||||||
|
if (ui->edit_token->text().isEmpty()) {
|
||||||
|
user_verified = true;
|
||||||
|
|
||||||
|
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16);
|
||||||
|
ui->label_token_verified->setPixmap(pixmap);
|
||||||
|
} else {
|
||||||
|
user_verified = false;
|
||||||
|
|
||||||
|
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16);
|
||||||
|
ui->label_token_verified->setPixmap(pixmap);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureWeb::VerifyLogin() {
|
||||||
|
ui->button_verify_login->setDisabled(true);
|
||||||
|
ui->button_verify_login->setText(tr("Verifying..."));
|
||||||
|
verify_watcher.setFuture(QtConcurrent::run(
|
||||||
|
[username = UsernameFromDisplayToken(ui->edit_token->text().toStdString()),
|
||||||
|
token = TokenFromDisplayToken(ui->edit_token->text().toStdString())] {
|
||||||
|
return Core::VerifyLogin(username, token);
|
||||||
|
}));
|
||||||
|
}
|
||||||
|
|
||||||
|
void ConfigureWeb::OnLoginVerified() {
|
||||||
|
ui->button_verify_login->setEnabled(true);
|
||||||
|
ui->button_verify_login->setText(tr("Verify"));
|
||||||
|
if (verify_watcher.result()) {
|
||||||
|
user_verified = true;
|
||||||
|
|
||||||
|
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("checked")).pixmap(16);
|
||||||
|
ui->label_token_verified->setPixmap(pixmap);
|
||||||
|
ui->username->setText(
|
||||||
|
QString::fromStdString(UsernameFromDisplayToken(ui->edit_token->text().toStdString())));
|
||||||
|
} else {
|
||||||
|
const QPixmap pixmap = QIcon::fromTheme(QStringLiteral("failed")).pixmap(16);
|
||||||
|
ui->label_token_verified->setPixmap(pixmap);
|
||||||
|
ui->username->setText(tr("Unspecified"));
|
||||||
|
QMessageBox::critical(this, tr("Verification failed"),
|
||||||
|
tr("Verification failed. Check that you have entered your token "
|
||||||
|
"correctly, and that your internet connection is working."));
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void ConfigureWeb::RetranslateUI() {
|
void ConfigureWeb::RetranslateUI() {
|
||||||
ui->retranslateUi(this);
|
ui->retranslateUi(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ConfigureWeb::SetWebServiceConfigEnabled(bool enabled) {
|
||||||
|
ui->label_disable_info->setVisible(!enabled);
|
||||||
|
ui->groupBoxWebConfig->setEnabled(enabled);
|
||||||
|
}
|
||||||
|
|
|
@ -22,6 +22,7 @@ public:
|
||||||
void ApplyConfiguration();
|
void ApplyConfiguration();
|
||||||
void RetranslateUI();
|
void RetranslateUI();
|
||||||
void SetConfiguration();
|
void SetConfiguration();
|
||||||
|
void SetWebServiceConfigEnabled(bool enabled);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void RefreshTelemetryID();
|
void RefreshTelemetryID();
|
||||||
|
|
|
@ -14,6 +14,163 @@
|
||||||
<string>Form</string>
|
<string>Form</string>
|
||||||
</property>
|
</property>
|
||||||
<layout class="QVBoxLayout" name="verticalLayout">
|
<layout class="QVBoxLayout" name="verticalLayout">
|
||||||
|
<item>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBoxWebConfig">
|
||||||
|
<property name="title">
|
||||||
|
<string>Lime3DS Web Service</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayoutCitraWebService">
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="web_credentials_disclaimer">
|
||||||
|
<property name="text">
|
||||||
|
<string>Currently not supported by Lime. By providing your username and token, you agree to allow Citra to collect additional usage data, which may include user identifying information.</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayoutCitraUsername">
|
||||||
|
<item row="2" column="3">
|
||||||
|
<widget class="QPushButton" name="button_verify_login">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="layoutDirection">
|
||||||
|
<enum>Qt::RightToLeft</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Verify</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="0">
|
||||||
|
<widget class="QLabel" name="web_signup_link">
|
||||||
|
<property name="text">
|
||||||
|
<string>Sign up</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1" colspan="3">
|
||||||
|
<widget class="QLabel" name="username"/>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="0">
|
||||||
|
<widget class="QLabel" name="label_token">
|
||||||
|
<property name="text">
|
||||||
|
<string>Token: </string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="4">
|
||||||
|
<widget class="QLabel" name="label_token_verified"/>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_username">
|
||||||
|
<property name="text">
|
||||||
|
<string>Username: </string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="1" column="1" colspan="3">
|
||||||
|
<widget class="QLineEdit" name="edit_token">
|
||||||
|
<property name="maxLength">
|
||||||
|
<number>80</number>
|
||||||
|
</property>
|
||||||
|
<property name="echoMode">
|
||||||
|
<enum>QLineEdit::Password</enum>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="1">
|
||||||
|
<widget class="QLabel" name="web_token_info_link">
|
||||||
|
<property name="text">
|
||||||
|
<string>What is my token?</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="2" column="2">
|
||||||
|
<spacer name="horizontalSpacer">
|
||||||
|
<property name="orientation">
|
||||||
|
<enum>Qt::Horizontal</enum>
|
||||||
|
</property>
|
||||||
|
<property name="sizeHint" stdset="0">
|
||||||
|
<size>
|
||||||
|
<width>40</width>
|
||||||
|
<height>20</height>
|
||||||
|
</size>
|
||||||
|
</property>
|
||||||
|
</spacer>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="label_disable_info">
|
||||||
|
<property name="text">
|
||||||
|
<string>Web Service configuration can only be changed when a public room isn't being hosted.</string>
|
||||||
|
</property>
|
||||||
|
<property name="wordWrap">
|
||||||
|
<bool>true</bool>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QGroupBox" name="groupBox">
|
||||||
|
<property name="title">
|
||||||
|
<string>Telemetry</string>
|
||||||
|
</property>
|
||||||
|
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||||
|
<item>
|
||||||
|
<widget class="QCheckBox" name="toggle_telemetry">
|
||||||
|
<property name="text">
|
||||||
|
<string>Share anonymous usage data with the Lime3DS team</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<widget class="QLabel" name="telemetry_learn_more">
|
||||||
|
<property name="text">
|
||||||
|
<string>Learn more</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item>
|
||||||
|
<layout class="QGridLayout" name="gridLayoutTelemetryId">
|
||||||
|
<item row="0" column="0">
|
||||||
|
<widget class="QLabel" name="label_telemetry_id">
|
||||||
|
<property name="text">
|
||||||
|
<string>Telemetry ID:</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
<item row="0" column="1">
|
||||||
|
<widget class="QPushButton" name="button_regenerate_telemetry_id">
|
||||||
|
<property name="sizePolicy">
|
||||||
|
<sizepolicy hsizetype="Fixed" vsizetype="Fixed">
|
||||||
|
<horstretch>0</horstretch>
|
||||||
|
<verstretch>0</verstretch>
|
||||||
|
</sizepolicy>
|
||||||
|
</property>
|
||||||
|
<property name="layoutDirection">
|
||||||
|
<enum>Qt::RightToLeft</enum>
|
||||||
|
</property>
|
||||||
|
<property name="text">
|
||||||
|
<string>Regenerate</string>
|
||||||
|
</property>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</widget>
|
||||||
|
</item>
|
||||||
|
</layout>
|
||||||
|
</item>
|
||||||
<item>
|
<item>
|
||||||
<widget class="QGroupBox" name="discord_group">
|
<widget class="QGroupBox" name="discord_group">
|
||||||
<property name="title">
|
<property name="title">
|
||||||
|
@ -46,6 +203,10 @@
|
||||||
</layout>
|
</layout>
|
||||||
</widget>
|
</widget>
|
||||||
<tabstops>
|
<tabstops>
|
||||||
|
<tabstop>edit_token</tabstop>
|
||||||
|
<tabstop>button_verify_login</tabstop>
|
||||||
|
<tabstop>toggle_telemetry</tabstop>
|
||||||
|
<tabstop>button_regenerate_telemetry_id</tabstop>
|
||||||
<tabstop>toggle_discordrpc</tabstop>
|
<tabstop>toggle_discordrpc</tabstop>
|
||||||
</tabstops>
|
</tabstops>
|
||||||
<resources/>
|
<resources/>
|
||||||
|
|
|
@ -15,6 +15,7 @@
|
||||||
#include <QtGui>
|
#include <QtGui>
|
||||||
#include <QtWidgets>
|
#include <QtWidgets>
|
||||||
#include <fmt/format.h>
|
#include <fmt/format.h>
|
||||||
|
#include "core/telemetry_session.h"
|
||||||
#ifdef __APPLE__
|
#ifdef __APPLE__
|
||||||
#include <unistd.h> // for chdir
|
#include <unistd.h> // for chdir
|
||||||
#endif
|
#endif
|
||||||
|
@ -127,6 +128,27 @@ constexpr int default_mouse_timeout = 2500;
|
||||||
* is a bitfield "callout_flags" options, used to track if a message has already been shown to the
|
* is a bitfield "callout_flags" options, used to track if a message has already been shown to the
|
||||||
* user. This is 32-bits - if we have more than 32 callouts, we should retire and recycle old ones.
|
* user. This is 32-bits - if we have more than 32 callouts, we should retire and recycle old ones.
|
||||||
*/
|
*/
|
||||||
|
enum class CalloutFlag : uint32_t {
|
||||||
|
Telemetry = 0x1,
|
||||||
|
};
|
||||||
|
|
||||||
|
void GMainWindow::ShowTelemetryCallout() {
|
||||||
|
if (UISettings::values.callout_flags.GetValue() &
|
||||||
|
static_cast<uint32_t>(CalloutFlag::Telemetry)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
UISettings::values.callout_flags =
|
||||||
|
UISettings::values.callout_flags.GetValue() | static_cast<uint32_t>(CalloutFlag::Telemetry);
|
||||||
|
const QString telemetry_message =
|
||||||
|
tr("<a href='https://citra-emu.org/entry/telemetry-and-why-thats-a-good-thing/'>Anonymous "
|
||||||
|
"data is collected</a> to help improve Citra. "
|
||||||
|
"<br/><br/>Would you like to share your usage data with us?");
|
||||||
|
if (QMessageBox::question(this, tr("Telemetry"), telemetry_message) == QMessageBox::Yes) {
|
||||||
|
NetSettings::values.enable_telemetry = true;
|
||||||
|
system.ApplySettings();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const int GMainWindow::max_recent_files_item;
|
const int GMainWindow::max_recent_files_item;
|
||||||
|
|
||||||
|
@ -241,6 +263,9 @@ GMainWindow::GMainWindow(Core::System& system_)
|
||||||
game_list->LoadCompatibilityList();
|
game_list->LoadCompatibilityList();
|
||||||
game_list->PopulateAsync(UISettings::values.game_dirs);
|
game_list->PopulateAsync(UISettings::values.game_dirs);
|
||||||
|
|
||||||
|
// Show one-time "callout" messages to the user
|
||||||
|
ShowTelemetryCallout();
|
||||||
|
|
||||||
mouse_hide_timer.setInterval(default_mouse_timeout);
|
mouse_hide_timer.setInterval(default_mouse_timeout);
|
||||||
connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor);
|
connect(&mouse_hide_timer, &QTimer::timeout, this, &GMainWindow::HideMouseCursor);
|
||||||
connect(ui->menubar, &QMenuBar::hovered, this, &GMainWindow::OnMouseActivity);
|
connect(ui->menubar, &QMenuBar::hovered, this, &GMainWindow::OnMouseActivity);
|
||||||
|
@ -1222,6 +1247,7 @@ bool GMainWindow::LoadROM(const QString& filename) {
|
||||||
|
|
||||||
game_path = filename;
|
game_path = filename;
|
||||||
|
|
||||||
|
system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", "Qt");
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1967,7 +1993,7 @@ void GMainWindow::OnLoadComplete() {
|
||||||
|
|
||||||
void GMainWindow::OnMenuReportCompatibility() {
|
void GMainWindow::OnMenuReportCompatibility() {
|
||||||
if (!NetSettings::values.citra_token.empty() && !NetSettings::values.citra_username.empty()) {
|
if (!NetSettings::values.citra_token.empty() && !NetSettings::values.citra_username.empty()) {
|
||||||
CompatDB compatdb{this};
|
CompatDB compatdb{system.TelemetrySession(), this};
|
||||||
compatdb.exec();
|
compatdb.exec();
|
||||||
} else {
|
} else {
|
||||||
QMessageBox::critical(this, tr("Missing Citra Account"),
|
QMessageBox::critical(this, tr("Missing Citra Account"),
|
||||||
|
|
|
@ -152,6 +152,7 @@ private:
|
||||||
void BootGame(const QString& filename);
|
void BootGame(const QString& filename);
|
||||||
void ShutdownGame();
|
void ShutdownGame();
|
||||||
|
|
||||||
|
void ShowTelemetryCallout();
|
||||||
void SetDiscordEnabled(bool state);
|
void SetDiscordEnabled(bool state);
|
||||||
void LoadAmiibo(const QString& filename);
|
void LoadAmiibo(const QString& filename);
|
||||||
|
|
||||||
|
|
|
@ -5,6 +5,7 @@
|
||||||
#include <glad/glad.h>
|
#include <glad/glad.h>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
|
#include "core/telemetry_session.h"
|
||||||
#include "video_core/custom_textures/custom_format.h"
|
#include "video_core/custom_textures/custom_format.h"
|
||||||
#include "video_core/renderer_opengl/gl_driver.h"
|
#include "video_core/renderer_opengl/gl_driver.h"
|
||||||
#include "video_core/renderer_opengl/gl_vars.h"
|
#include "video_core/renderer_opengl/gl_vars.h"
|
||||||
|
@ -69,11 +70,12 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum
|
||||||
level = Common::Log::Level::Debug;
|
level = Common::Log::Level::Debug;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
LOG_GENERIC(Common::Log::Class::Render_OpenGL, level, "{} {} {}: {}", GetSource(source),
|
LOG_GENERIC(Common::Log::Class::Render_OpenGL, level, "{} {} {}: {}", GetSource(source),
|
||||||
GetType(type), id, message);
|
GetType(type), id, message);
|
||||||
}
|
}
|
||||||
|
|
||||||
Driver::Driver() {
|
Driver::Driver(Core::TelemetrySession& telemetry_session_) : telemetry_session{telemetry_session_} {
|
||||||
const bool enable_debug = Settings::values.renderer_debug.GetValue();
|
const bool enable_debug = Settings::values.renderer_debug.GetValue();
|
||||||
if (enable_debug) {
|
if (enable_debug) {
|
||||||
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
glEnable(GL_DEBUG_OUTPUT_SYNCHRONOUS);
|
||||||
|
@ -133,6 +135,12 @@ void Driver::ReportDriverInfo() {
|
||||||
LOG_INFO(Render_OpenGL, "GL_VERSION: {}", gl_version);
|
LOG_INFO(Render_OpenGL, "GL_VERSION: {}", gl_version);
|
||||||
LOG_INFO(Render_OpenGL, "GL_VENDOR: {}", gpu_vendor);
|
LOG_INFO(Render_OpenGL, "GL_VENDOR: {}", gpu_vendor);
|
||||||
LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model);
|
LOG_INFO(Render_OpenGL, "GL_RENDERER: {}", gpu_model);
|
||||||
|
|
||||||
|
// Add the information to the telemetry system
|
||||||
|
constexpr auto user_system = Common::Telemetry::FieldType::UserSystem;
|
||||||
|
telemetry_session.AddField(user_system, "GPU_Vendor", std::string{gpu_vendor});
|
||||||
|
telemetry_session.AddField(user_system, "GPU_Model", std::string{gpu_model});
|
||||||
|
telemetry_session.AddField(user_system, "GPU_OpenGL_Version", std::string{gl_version});
|
||||||
}
|
}
|
||||||
|
|
||||||
void Driver::DeduceGLES() {
|
void Driver::DeduceGLES() {
|
||||||
|
|
|
@ -7,6 +7,10 @@
|
||||||
#include <string_view>
|
#include <string_view>
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class TelemetrySession;
|
||||||
|
}
|
||||||
|
|
||||||
namespace VideoCore {
|
namespace VideoCore {
|
||||||
enum class CustomPixelFormat : u32;
|
enum class CustomPixelFormat : u32;
|
||||||
}
|
}
|
||||||
|
@ -44,7 +48,7 @@ enum class DriverBug {
|
||||||
*/
|
*/
|
||||||
class Driver {
|
class Driver {
|
||||||
public:
|
public:
|
||||||
Driver();
|
Driver(Core::TelemetrySession& telemetry_session);
|
||||||
~Driver();
|
~Driver();
|
||||||
|
|
||||||
/// Returns true of the driver has a particular bug stated in the DriverBug enum
|
/// Returns true of the driver has a particular bug stated in the DriverBug enum
|
||||||
|
@ -139,6 +143,7 @@ private:
|
||||||
void FindBugs();
|
void FindBugs();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
Core::TelemetrySession& telemetry_session;
|
||||||
Vendor vendor = Vendor::Unknown;
|
Vendor vendor = Vendor::Unknown;
|
||||||
DriverBug bugs{};
|
DriverBug bugs{};
|
||||||
bool is_suitable{};
|
bool is_suitable{};
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "core/telemetry_session.h"
|
||||||
#include "video_core/pica/regs_framebuffer.h"
|
#include "video_core/pica/regs_framebuffer.h"
|
||||||
#include "video_core/pica/regs_lighting.h"
|
#include "video_core/pica/regs_lighting.h"
|
||||||
#include "video_core/pica/regs_texturing.h"
|
#include "video_core/pica/regs_texturing.h"
|
||||||
|
@ -75,6 +76,9 @@ inline GLenum WrapMode(Pica::TexturingRegs::TextureConfig::WrapMode mode) {
|
||||||
}
|
}
|
||||||
|
|
||||||
if (index > 3) {
|
if (index > 3) {
|
||||||
|
Core::System::GetInstance().TelemetrySession().AddField(
|
||||||
|
Common::Telemetry::FieldType::Session, "VideoCore_Pica_UnsupportedTextureWrapMode",
|
||||||
|
static_cast<u32>(index));
|
||||||
LOG_WARNING(Render_OpenGL, "Using texture wrap mode {}", index);
|
LOG_WARNING(Render_OpenGL, "Using texture wrap mode {}", index);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -75,9 +75,9 @@ static std::array<GLfloat, 3 * 2> MakeOrthographicMatrix(const float width, cons
|
||||||
RendererOpenGL::RendererOpenGL(Core::System& system, Pica::PicaCore& pica_,
|
RendererOpenGL::RendererOpenGL(Core::System& system, Pica::PicaCore& pica_,
|
||||||
Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window)
|
Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window)
|
||||||
: VideoCore::RendererBase{system, window, secondary_window}, pica{pica_},
|
: VideoCore::RendererBase{system, window, secondary_window}, pica{pica_},
|
||||||
rasterizer{system.Memory(), pica, system.CustomTexManager(), *this, driver}, frame_dumper{
|
driver{system.TelemetrySession()}, rasterizer{system.Memory(), pica,
|
||||||
system,
|
system.CustomTexManager(), *this, driver},
|
||||||
window} {
|
frame_dumper{system, window} {
|
||||||
const bool has_debug_tool = driver.HasDebugTool();
|
const bool has_debug_tool = driver.HasDebugTool();
|
||||||
window.mailbox = std::make_unique<OGLTextureMailbox>(has_debug_tool);
|
window.mailbox = std::make_unique<OGLTextureMailbox>(has_debug_tool);
|
||||||
if (secondary_window) {
|
if (secondary_window) {
|
||||||
|
|
|
@ -53,9 +53,9 @@ constexpr static std::array<vk::DescriptorSetLayoutBinding, 1> PRESENT_BINDINGS
|
||||||
RendererVulkan::RendererVulkan(Core::System& system, Pica::PicaCore& pica_,
|
RendererVulkan::RendererVulkan(Core::System& system, Pica::PicaCore& pica_,
|
||||||
Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window)
|
Frontend::EmuWindow& window, Frontend::EmuWindow* secondary_window)
|
||||||
: RendererBase{system, window, secondary_window}, memory{system.Memory()}, pica{pica_},
|
: RendererBase{system, window, secondary_window}, memory{system.Memory()}, pica{pica_},
|
||||||
instance{window, Settings::values.physical_device.GetValue()}, scheduler{instance},
|
instance{system.TelemetrySession(), window, Settings::values.physical_device.GetValue()},
|
||||||
renderpass_cache{instance, scheduler}, pool{instance}, main_window{window, instance,
|
scheduler{instance}, renderpass_cache{instance, scheduler}, pool{instance},
|
||||||
scheduler},
|
main_window{window, instance, scheduler},
|
||||||
vertex_buffer{instance, scheduler, vk::BufferUsageFlagBits::eVertexBuffer,
|
vertex_buffer{instance, scheduler, vk::BufferUsageFlagBits::eVertexBuffer,
|
||||||
VERTEX_BUFFER_SIZE},
|
VERTEX_BUFFER_SIZE},
|
||||||
rasterizer{memory,
|
rasterizer{memory,
|
||||||
|
|
|
@ -9,6 +9,7 @@
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "core/frontend/emu_window.h"
|
#include "core/frontend/emu_window.h"
|
||||||
|
#include "core/telemetry_session.h"
|
||||||
#include "video_core/custom_textures/custom_format.h"
|
#include "video_core/custom_textures/custom_format.h"
|
||||||
#include "video_core/renderer_vulkan/vk_instance.h"
|
#include "video_core/renderer_vulkan/vk_instance.h"
|
||||||
#include "video_core/renderer_vulkan/vk_platform.h"
|
#include "video_core/renderer_vulkan/vk_platform.h"
|
||||||
|
@ -137,7 +138,8 @@ Instance::Instance(bool enable_validation, bool dump_command_buffers)
|
||||||
enable_validation, dump_command_buffers)},
|
enable_validation, dump_command_buffers)},
|
||||||
physical_devices{instance->enumeratePhysicalDevices()} {}
|
physical_devices{instance->enumeratePhysicalDevices()} {}
|
||||||
|
|
||||||
Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index)
|
Instance::Instance(Core::TelemetrySession& telemetry, Frontend::EmuWindow& window,
|
||||||
|
u32 physical_device_index)
|
||||||
: library{OpenLibrary(&window)}, instance{CreateInstance(
|
: library{OpenLibrary(&window)}, instance{CreateInstance(
|
||||||
*library, window.GetWindowInfo().type,
|
*library, window.GetWindowInfo().type,
|
||||||
Settings::values.renderer_debug.GetValue(),
|
Settings::values.renderer_debug.GetValue(),
|
||||||
|
@ -159,9 +161,10 @@ Instance::Instance(Frontend::EmuWindow& window, u32 physical_device_index)
|
||||||
VK_VERSION_MAJOR(properties.apiVersion), VK_VERSION_MINOR(properties.apiVersion)));
|
VK_VERSION_MAJOR(properties.apiVersion), VK_VERSION_MINOR(properties.apiVersion)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CollectTelemetryParameters(telemetry);
|
||||||
CreateDevice();
|
CreateDevice();
|
||||||
CreateFormatTable();
|
|
||||||
CollectToolingInfo();
|
CollectToolingInfo();
|
||||||
|
CreateFormatTable();
|
||||||
CreateCustomFormatTable();
|
CreateCustomFormatTable();
|
||||||
CreateAttribTable();
|
CreateAttribTable();
|
||||||
}
|
}
|
||||||
|
@ -642,10 +645,7 @@ void Instance::CreateAllocator() {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Instance::CollectToolingInfo() {
|
void Instance::CollectTelemetryParameters(Core::TelemetrySession& telemetry) {
|
||||||
if (!tooling_info) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
const vk::StructureChain property_chain =
|
const vk::StructureChain property_chain =
|
||||||
physical_device
|
physical_device
|
||||||
.getProperties2<vk::PhysicalDeviceProperties2, vk::PhysicalDeviceDriverProperties>();
|
.getProperties2<vk::PhysicalDeviceProperties2, vk::PhysicalDeviceDriverProperties>();
|
||||||
|
@ -664,6 +664,19 @@ void Instance::CollectToolingInfo() {
|
||||||
LOG_INFO(Render_Vulkan, "VK_DRIVER: {}", driver_name);
|
LOG_INFO(Render_Vulkan, "VK_DRIVER: {}", driver_name);
|
||||||
LOG_INFO(Render_Vulkan, "VK_DEVICE: {}", model_name);
|
LOG_INFO(Render_Vulkan, "VK_DEVICE: {}", model_name);
|
||||||
LOG_INFO(Render_Vulkan, "VK_VERSION: {}", api_version);
|
LOG_INFO(Render_Vulkan, "VK_VERSION: {}", api_version);
|
||||||
|
|
||||||
|
static constexpr auto field = Common::Telemetry::FieldType::UserSystem;
|
||||||
|
telemetry.AddField(field, "GPU_Vendor", vendor_name);
|
||||||
|
telemetry.AddField(field, "GPU_Model", model_name);
|
||||||
|
telemetry.AddField(field, "GPU_Vulkan_Driver", driver_name);
|
||||||
|
telemetry.AddField(field, "GPU_Vulkan_Version", api_version);
|
||||||
|
telemetry.AddField(field, "GPU_Vulkan_Extensions", extensions);
|
||||||
|
}
|
||||||
|
|
||||||
|
void Instance::CollectToolingInfo() {
|
||||||
|
if (!tooling_info) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
const auto tools = physical_device.getToolPropertiesEXT();
|
const auto tools = physical_device.getToolPropertiesEXT();
|
||||||
for (const vk::PhysicalDeviceToolProperties& tool : tools) {
|
for (const vk::PhysicalDeviceToolProperties& tool : tools) {
|
||||||
const std::string_view name = tool.name;
|
const std::string_view name = tool.name;
|
||||||
|
|
|
@ -10,6 +10,10 @@
|
||||||
#include "video_core/rasterizer_cache/pixel_format.h"
|
#include "video_core/rasterizer_cache/pixel_format.h"
|
||||||
#include "video_core/renderer_vulkan/vk_platform.h"
|
#include "video_core/renderer_vulkan/vk_platform.h"
|
||||||
|
|
||||||
|
namespace Core {
|
||||||
|
class TelemetrySession;
|
||||||
|
}
|
||||||
|
|
||||||
namespace Frontend {
|
namespace Frontend {
|
||||||
class EmuWindow;
|
class EmuWindow;
|
||||||
}
|
}
|
||||||
|
@ -37,7 +41,8 @@ struct FormatTraits {
|
||||||
class Instance {
|
class Instance {
|
||||||
public:
|
public:
|
||||||
explicit Instance(bool validation = false, bool dump_command_buffers = false);
|
explicit Instance(bool validation = false, bool dump_command_buffers = false);
|
||||||
explicit Instance(Frontend::EmuWindow& window, u32 physical_device_index);
|
explicit Instance(Core::TelemetrySession& telemetry, Frontend::EmuWindow& window,
|
||||||
|
u32 physical_device_index);
|
||||||
~Instance();
|
~Instance();
|
||||||
|
|
||||||
/// Returns the FormatTraits struct for the provided pixel format
|
/// Returns the FormatTraits struct for the provided pixel format
|
||||||
|
@ -280,7 +285,8 @@ private:
|
||||||
/// Creates the VMA allocator handle
|
/// Creates the VMA allocator handle
|
||||||
void CreateAllocator();
|
void CreateAllocator();
|
||||||
|
|
||||||
// Collects logging gpu info
|
/// Collects telemetry information from the device.
|
||||||
|
void CollectTelemetryParameters(Core::TelemetrySession& telemetry);
|
||||||
void CollectToolingInfo();
|
void CollectToolingInfo();
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
|
Loading…
Reference in a new issue