diff --git a/qrenderdoc/Code/Interface/Analytics.cpp b/qrenderdoc/Code/Interface/Analytics.cpp index 00c96e678..56740a042 100644 --- a/qrenderdoc/Code/Interface/Analytics.cpp +++ b/qrenderdoc/Code/Interface/Analytics.cpp @@ -73,6 +73,7 @@ namespace enum class AnalyticsState { Nothing, + Disabled, PromptFirstTime, SubmitReport, }; @@ -177,25 +178,25 @@ void saveTo(QVariantMap &parent, const QString &name, const T &el, bool reportin } // add a macro to either document, load, or save, depending on our state. -#define ANALYTIC_SERIALISE(varname) \ - if(type == AnalyticsSerialiseType::Documenting) \ - { \ - QString var = lit(#varname); \ - int idx = var.indexOf(QLatin1Char('.')); \ - if(idx >= 0) \ - var = var.mid(idx + 1); \ - doc += lit("%1 (%2): %3
") \ - .arg(var) \ - .arg(QString::fromUtf8(TypeNamevarname)>())) \ - .arg(docs.varname); \ - } \ - else if(type == AnalyticsSerialiseType::Loading) \ - { \ - loadFrom(values, lit(#varname), Analytics::db->varname); \ - } \ - else \ - { \ - saveTo(values, lit(#varname), Analytics::db->varname, reporting); \ +#define ANALYTIC_SERIALISE(varname) \ + if(type == AnalyticsSerialiseType::Documenting) \ + { \ + QString var = lit(#varname); \ + int idx = var.indexOf(QLatin1Char('.')); \ + if(idx >= 0) \ + var = var.mid(idx + 1); \ + doc += lit("%1 (%2): %3
") \ + .arg(var) \ + .arg(QString::fromUtf8(TypeName())) \ + .arg(docs.varname); \ + } \ + else if(type == AnalyticsSerialiseType::Loading) \ + { \ + loadFrom(values, lit(#varname), serdb.varname); \ + } \ + else \ + { \ + saveTo(values, lit(#varname), serdb.varname, reporting); \ } // only used during documenting @@ -309,13 +310,10 @@ static struct AnalyticsDocumentation } DOCUMENT_ANALYTIC_SECTION(CaptureFeatures, "Capture API Usage"); } docs; -void AnalyticsSerialise(QVariantMap &values, AnalyticsSerialiseType type) +void AnalyticsSerialise(Analytics &serdb, QVariantMap &values, AnalyticsSerialiseType type) { bool reporting = type == AnalyticsSerialiseType::Reporting; - if(!Analytics::db) - return; - static_assert(sizeof(Analytics) == 147, "Sizeof Analytics has changed - update serialisation."); QString doc; @@ -425,7 +423,8 @@ void AnalyticsSerialise(QVariantMap &values, AnalyticsSerialiseType type) ANALYTIC_SERIALISE(CaptureFeatures.D3D12Bundle); } - values[lit("doc")] = doc; + if(type == AnalyticsSerialiseType::Documenting) + values[lit("doc")] = doc; } }; // anonymous namespace @@ -434,21 +433,35 @@ Analytics *Analytics::db = NULL; void Analytics::Save() { - if(analyticsSaveLocation.isEmpty()) + if(analyticsSaveLocation.isEmpty() || analyticsState == AnalyticsState::Disabled || + Analytics::db == NULL) return; QVariantMap values; // call to the serialise function to save into the 'values' map - AnalyticsSerialise(values, AnalyticsSerialiseType::Saving); + AnalyticsSerialise(*Analytics::db, values, AnalyticsSerialiseType::Saving); QFile f(analyticsSaveLocation); if(f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) SaveToJSON(values, f, analyticsJSONMagic, analyticsJSONVersion); } +void Analytics::Disable() +{ + // do not save any values + Analytics::db = NULL; + analyticsSaveLocation = QString(); + analyticsState = AnalyticsState::Disabled; +} + void Analytics::Load() { + // refuse to load if we were previously disabled, just in case this function is called somehow. We + // require a full restart with the analytics enabled for it to start collecting. + if(analyticsState == AnalyticsState::Disabled) + return; + // allocate space for the Analytics singleton Analytics::db = &actualDB; @@ -467,7 +480,7 @@ void Analytics::Load() bool success = LoadFromJSON(values, f, analyticsJSONMagic, analyticsJSONVersion); if(success) - AnalyticsSerialise(values, AnalyticsSerialiseType::Loading); + AnalyticsSerialise(*Analytics::db, values, AnalyticsSerialiseType::Loading); } } @@ -491,9 +504,10 @@ void Analytics::Load() void Analytics::DocumentReport() { - QVariantMap dummy; - AnalyticsSerialise(dummy, AnalyticsSerialiseType::Documenting); - QString reportText = dummy[lit("doc")].toString(); + Analytics dummyDB; + QVariantMap dummyMap; + AnalyticsSerialise(dummyDB, dummyMap, AnalyticsSerialiseType::Documenting); + QString reportText = dummyMap[lit("doc")].toString(); { QDialog dialog; @@ -523,20 +537,25 @@ void Analytics::DocumentReport() void Analytics::Prompt(ICaptureContext &ctx, PersistantConfig &config) { - if(analyticsState == AnalyticsState::PromptFirstTime) + if(analyticsState == AnalyticsState::Disabled) + { + // do nothing, we're disabled + return; + } + else if(analyticsState == AnalyticsState::PromptFirstTime) { QWidget *mainWindow = ctx.GetMainWindow()->Widget(); AnalyticsPromptDialog prompt(config, mainWindow); RDDialog::show(&prompt); } - else if(analyticsState == AnalyticsState::SubmitReport) + else if(analyticsState == AnalyticsState::SubmitReport && Analytics::db != NULL) { QWidget *mainWindow = ctx.GetMainWindow()->Widget(); QVariantMap values; - AnalyticsSerialise(values, AnalyticsSerialiseType::Reporting); + AnalyticsSerialise(*Analytics::db, values, AnalyticsSerialiseType::Reporting); QBuffer buf; buf.open(QBuffer::WriteOnly); @@ -586,6 +605,10 @@ void Load() { } +void Disable() +{ +} + void Prompt(ICaptureContext &ctx, PersistantConfig &config) { } diff --git a/qrenderdoc/Code/Interface/Analytics.h b/qrenderdoc/Code/Interface/Analytics.h index 5143fadc2..36d649646 100644 --- a/qrenderdoc/Code/Interface/Analytics.h +++ b/qrenderdoc/Code/Interface/Analytics.h @@ -112,6 +112,9 @@ struct Analytics { // utility function - loads the analytics from disk and initialise the Analytics::db member. static void Load(); + // utility function - explicitly disables the analytics and sets it into a black-hole mode that + // does nothing. + static void Disable(); // utility function - performs any UI-level prompting, such as asking the user if they want to // opt-out, or manually vetting a report for uploading. static void Prompt(ICaptureContext &ctx, PersistantConfig &config); @@ -307,6 +310,7 @@ struct ICaptureContext; namespace Analytics { +void Disable(); void Load(); void Prompt(ICaptureContext &ctx, PersistantConfig &config); void DocumentReport(); diff --git a/qrenderdoc/Code/qrenderdoc.cpp b/qrenderdoc/Code/qrenderdoc.cpp index 6bf57c3b2..a5d957030 100644 --- a/qrenderdoc/Code/qrenderdoc.cpp +++ b/qrenderdoc/Code/qrenderdoc.cpp @@ -290,7 +290,9 @@ int main(int argc, char *argv[]) .arg(configFilename)); } - if(!config.Analytics_TotalOptOut) + if(config.Analytics_TotalOptOut) + Analytics::Disable(); + else Analytics::Load(); bool isDarkTheme = IsDarkTheme(); diff --git a/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp b/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp index 83d4888d9..686eb0066 100644 --- a/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp +++ b/qrenderdoc/Windows/Dialogs/SettingsDialog.cpp @@ -167,6 +167,37 @@ SettingsDialog::SettingsDialog(ICaptureContext &ctx, QWidget *parent) ui->AlwaysReplayLocally->setChecked(m_Ctx.Config().AlwaysReplayLocally); +#if RENDERDOC_ANALYTICS_ENABLE + if(m_Ctx.Config().Analytics_TotalOptOut) + { + ui->analyticsAutoSubmit->setChecked(false); + ui->analyticsManualCheck->setChecked(false); + ui->analyticsOptOut->setChecked(true); + + // once we've started with analytics disabled, only a restart can re-enable them. + ui->analyticsAutoSubmit->setText(ui->analyticsAutoSubmit->text() + tr(" (Requires Restart)")); + ui->analyticsManualCheck->setText(ui->analyticsManualCheck->text() + tr(" (Requires Restart)")); + } + else if(m_Ctx.Config().Analytics_ManualCheck) + { + ui->analyticsAutoSubmit->setChecked(false); + ui->analyticsManualCheck->setChecked(true); + ui->analyticsOptOut->setChecked(false); + } + else + { + ui->analyticsAutoSubmit->setChecked(true); + ui->analyticsManualCheck->setChecked(false); + ui->analyticsOptOut->setChecked(false); + } +#else + ui->analyticsDescribeLabel->setText(tr("Analytics was disabled at compile time.")); + + ui->analyticsAutoSubmit->setEnabled(false); + ui->analyticsManualCheck->setEnabled(false); + ui->analyticsOptOut->setEnabled(false); +#endif + ui->AllowGlobalHook->setChecked(m_Ctx.Config().AllowGlobalHook); ui->EventBrowser_TimeUnit->setCurrentIndex((int)m_Ctx.Config().EventBrowser_TimeUnit); @@ -319,6 +350,47 @@ void SettingsDialog::on_AlwaysReplayLocally_toggled(bool checked) m_Ctx.Config().Save(); } +void SettingsDialog::on_analyticsAutoSubmit_toggled(bool checked) +{ + if(checked) + { + m_Ctx.Config().Analytics_ManualCheck = false; + m_Ctx.Config().Analytics_TotalOptOut = false; + + m_Ctx.Config().Save(); + } +} + +void SettingsDialog::on_analyticsManualCheck_toggled(bool checked) +{ + if(checked) + { + m_Ctx.Config().Analytics_ManualCheck = true; + m_Ctx.Config().Analytics_TotalOptOut = false; + + m_Ctx.Config().Save(); + } +} + +void SettingsDialog::on_analyticsOptOut_toggled(bool checked) +{ + if(checked) + { + m_Ctx.Config().Analytics_ManualCheck = false; + m_Ctx.Config().Analytics_TotalOptOut = true; + + // immediately disable the analytics collection and ensure it can't send any reports. + Analytics::Disable(); + + m_Ctx.Config().Save(); + } +} + +void SettingsDialog::on_analyticsDescribeLabel_linkActivated(const QString &link) +{ + Analytics::DocumentReport(); +} + // core void SettingsDialog::on_chooseSearchPaths_clicked() { diff --git a/qrenderdoc/Windows/Dialogs/SettingsDialog.h b/qrenderdoc/Windows/Dialogs/SettingsDialog.h index e167e7634..4919a02a6 100644 --- a/qrenderdoc/Windows/Dialogs/SettingsDialog.h +++ b/qrenderdoc/Windows/Dialogs/SettingsDialog.h @@ -60,6 +60,9 @@ private slots: void on_CheckUpdate_AllowChecks_toggled(bool checked); void on_Font_PreferMonospaced_toggled(bool checked); void on_AlwaysReplayLocally_toggled(bool checked); + void on_analyticsAutoSubmit_toggled(bool checked); + void on_analyticsManualCheck_toggled(bool checked); + void on_analyticsOptOut_toggled(bool checked); // core void on_chooseSearchPaths_clicked(); @@ -100,6 +103,8 @@ private slots: // manual slots void formatter_valueChanged(int value); + void on_analyticsDescribeLabel_linkActivated(const QString &link); + private: Ui::SettingsDialog *ui; diff --git a/qrenderdoc/Windows/Dialogs/SettingsDialog.ui b/qrenderdoc/Windows/Dialogs/SettingsDialog.ui index 91faba70a..8f5f98f7c 100644 --- a/qrenderdoc/Windows/Dialogs/SettingsDialog.ui +++ b/qrenderdoc/Windows/Dialogs/SettingsDialog.ui @@ -6,8 +6,8 @@ 0 0 - 614 - 470 + 561 + 519 @@ -73,7 +73,7 @@ QTabWidget::West - 6 + 0 true @@ -82,7 +82,7 @@ General - + 0 @@ -101,108 +101,6 @@ General - - - - Any numbers larger than this exponent will be displayed in scientific notation. -e.g. 1000 * 10 = 1e4 - - - Positive exponential cutoff value - - - - - - - Wherever possible a monospaced font will be used instead of the default font - - - Prefer monospaced fonts in UI (restart required) - - - - - - - Decimals will display at least this many digits. -e.g. a value of 2 means 0 will display as 0.00, 0.5 as 0.50 - - - 2 - - - - - - - Changes the default directory for the save dialog when saving capture files. - -Defaults to blank, which follows system default behaviour. - - - Default save directory for captures - - - - - - - Any numbers smaller than this exponent will be displayed in scientific notation. -E.g. a value of 3 means 0.005 / 10 = 5E-4 - - - Negative exponential cutoff value - - - - - - - Decimals will display at least this many digits. -e.g. a value of 2 means 0 will display as 0.00, 0.5 as 0.50 - - - Minimum decimal places on float values - - - - - - - Enables functionality on the capture application window that will insert RenderDoc automatically -into all new processes created - then inject into the target (matching) executable. - -Useful for capturing programs indirectly that can't easily be launched directly by RenderDoc - -Since this is a global system hook it must be used carefully and only when necessary! - - - Allow global process hooking - be careful! - - - - - - - No more significant figures than this will be displayed on floats. -e.g. a value of 5 means 0.123456789 will display as 0.12345 - - - Maximum significant figures on decimals - - - - - - - Allows RenderDoc to phone home to https://renderdoc.org to anonymously check for new versions. - - - Allow periodic anonymous update checks - - - @@ -231,12 +129,6 @@ E.g. a value of 3 means 0.005 / 10 = 5E-4 Qt::Vertical - - - 20 - 216 - - @@ -394,6 +286,148 @@ This option overrides that and will always replay locally if the local context i + + + + Any numbers larger than this exponent will be displayed in scientific notation. +e.g. 1000 * 10 = 1e4 + + + Positive exponential cutoff value + + + + + + + Wherever possible a monospaced font will be used instead of the default font + + + Prefer monospaced fonts in UI (restart required) + + + + + + + Decimals will display at least this many digits. +e.g. a value of 2 means 0 will display as 0.00, 0.5 as 0.50 + + + 2 + + + + + + + Changes the default directory for the save dialog when saving capture files. + +Defaults to blank, which follows system default behaviour. + + + Default save directory for captures + + + + + + + Any numbers smaller than this exponent will be displayed in scientific notation. +E.g. a value of 3 means 0.005 / 10 = 5E-4 + + + Negative exponential cutoff value + + + + + + + Decimals will display at least this many digits. +e.g. a value of 2 means 0 will display as 0.00, 0.5 as 0.50 + + + Minimum decimal places on float values + + + + + + + Enables functionality on the capture application window that will insert RenderDoc automatically +into all new processes created - then inject into the target (matching) executable. + +Useful for capturing programs indirectly that can't easily be launched directly by RenderDoc + +Since this is a global system hook it must be used carefully and only when necessary! + + + Allow global process hooking - be careful! + + + + + + + No more significant figures than this will be displayed on floats. +e.g. a value of 5 means 0.123456789 will display as 0.12345 + + + Maximum significant figures on decimals + + + + + + + Allows RenderDoc to phone home to https://renderdoc.org to anonymously check for new versions. + + + Allow periodic anonymous update checks + + + + + + + + + + Anonymous Analytics + + + + + + <html><head/><body><p><a href="#analyticsDescribe"><span style=" text-decoration: underline; color:#0000ff;">Click here</span></a> to see currently reported data.</p></body></html> + + + + + + + Gather anonymous low-detail statistics and submit automatically. + + + true + + + + + + + Gather anonymous low-detail statistics, but manually verify before submitting. + + + + + + + Do not gather or submit any statistics. + + +