From 03eb2ea69639ebe6ff960c6a078ce28c5b0a0315 Mon Sep 17 00:00:00 2001 From: baldurk Date: Fri, 7 Oct 2016 19:15:00 +0200 Subject: [PATCH] Save and load persistant config file --- qrenderdoc/Code/CaptureContext.cpp | 3 +- qrenderdoc/Code/CaptureContext.h | 10 +- qrenderdoc/Code/PersistantConfig.cpp | 243 ++++++++++++++++++++ qrenderdoc/Code/PersistantConfig.h | 148 ++++++++++++ qrenderdoc/Code/main.cpp | 19 +- qrenderdoc/Windows/MainWindow.cpp | 6 +- qrenderdoc/qrenderdoc.pro | 2 + qrenderdoc/qrenderdoc_local.vcxproj | 2 + qrenderdoc/qrenderdoc_local.vcxproj.filters | 6 + 9 files changed, 431 insertions(+), 8 deletions(-) create mode 100644 qrenderdoc/Code/PersistantConfig.cpp create mode 100644 qrenderdoc/Code/PersistantConfig.h diff --git a/qrenderdoc/Code/CaptureContext.cpp b/qrenderdoc/Code/CaptureContext.cpp index 72bbe2860..b632b3b1d 100644 --- a/qrenderdoc/Code/CaptureContext.cpp +++ b/qrenderdoc/Code/CaptureContext.cpp @@ -32,7 +32,8 @@ #include "Windows/MainWindow.h" CaptureContext::CaptureContext(QString paramFilename, QString remoteHost, uint32_t remoteIdent, - bool temp) + bool temp, PersistantConfig &cfg) + : Config(cfg) { m_LogLoaded = false; m_LoadInProgress = false; diff --git a/qrenderdoc/Code/CaptureContext.h b/qrenderdoc/Code/CaptureContext.h index f79bdce0e..fa8272e57 100644 --- a/qrenderdoc/Code/CaptureContext.h +++ b/qrenderdoc/Code/CaptureContext.h @@ -32,6 +32,7 @@ #include #include #include "CommonPipelineState.h" +#include "PersistantConfig.h" #include "RenderManager.h" #if defined(RENDERDOC_PLATFORM_LINUX) @@ -56,14 +57,15 @@ class MainWindow; class CaptureContext { public: - CaptureContext(QString paramFilename, QString remoteHost, uint32_t remoteIdent, bool temp); + CaptureContext(QString paramFilename, QString remoteHost, uint32_t remoteIdent, bool temp, + PersistantConfig &cfg); ~CaptureContext(); bool isRunning(); - QString ConfigFile(const QString &filename); + static QString ConfigFile(const QString &filename); - QString TempLogFilename(QString appname); + static QString TempLogFilename(QString appname); ////////////////////////////////////////////////////////////////////////////// // Control functions @@ -140,6 +142,8 @@ public: VulkanPipelineState CurVulkanPipelineState; CommonPipelineState CurPipelineState; + PersistantConfig &Config; + private: RenderManager m_Renderer; diff --git a/qrenderdoc/Code/PersistantConfig.cpp b/qrenderdoc/Code/PersistantConfig.cpp new file mode 100644 index 000000000..5ba8bde3d --- /dev/null +++ b/qrenderdoc/Code/PersistantConfig.cpp @@ -0,0 +1,243 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#include "PersistantConfig.h" +#include +#include +#include +#include "renderdoc_replay.h" + +// helper templates to convert some more complex types to/from appropriate variants +template +variantType convertToVariant(const origType &val) +{ + return variantType(val); +} + +template <> +QVariantMap convertToVariant(const QStringMap &val) +{ + QVariantMap ret; + for(const QString &k : val.keys()) + { + ret[k] = val[k]; + } + return ret; +} + +template <> +QVariantList convertToVariant(const QList &val) +{ + QVariantList ret; + ret.reserve(val.count()); + for(const QString &s : val) + ret.push_back(s); + return ret; +} + +template +origType convertFromVariant(const variantType &val) +{ + return origType(val); +} + +template <> +QStringMap convertFromVariant(const QVariantMap &val) +{ + QStringMap ret; + for(const QString &k : val.keys()) + { + ret[k] = val[k].toString(); + } + return ret; +} + +template <> +QList convertFromVariant(const QVariantList &val) +{ + QList ret; + ret.reserve(val.count()); + for(const QVariant &s : val) + ret.push_back(s.toString()); + return ret; +} + +bool PersistantConfig::Deserialize(QString filename) +{ + QFile f(filename); + + // silently allow missing configs + if(!f.exists()) + return true; + + if(f.open(QIODevice::ReadOnly | QIODevice::Text)) + { + QByteArray json = f.readAll(); + + if(json.isEmpty()) + { + qCritical() << "Read invalid empty JSON data from file " << f.errorString(); + return false; + } + + QJsonDocument doc = QJsonDocument::fromJson(json); + + if(doc.isEmpty() || doc.isNull()) + { + qCritical() << "Failed to convert file to JSON document"; + return false; + } + + QVariantMap values = doc.toVariant().toMap(); + + if(values.isEmpty() || !values.contains("renderdocConfigData")) + { + qCritical() << "Converted config data is invalid or unrecognised"; + return false; + } + + applyValues(values); + + return true; + } + + qInfo() << "Couldn't load layout from " << filename << " " << f.errorString(); + + return false; +} + +bool PersistantConfig::Serialize(QString filename) +{ + QVariantMap values = storeValues(); + + // marker that this is indeed a valid config to load from + values["renderdocConfigData"] = 1; + + QFile f(filename); + if(f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) + { + QJsonDocument doc = QJsonDocument::fromVariant(values); + + if(doc.isEmpty() || doc.isNull()) + { + qCritical() << "Failed to convert config data to JSON document"; + return false; + } + + QByteArray jsontext = doc.toJson(QJsonDocument::Indented); + + qint64 ret = f.write(jsontext); + + if(ret != jsontext.size()) + { + qCritical() << "Failed to write JSON data to file: " << ret << " " << f.errorString(); + return false; + } + + return true; + } + + qWarning() << "Couldn't write to " << filename << " " << f.errorString(); + + return false; +} + +QVariantMap PersistantConfig::storeValues() const +{ + QVariantMap ret; + +#undef CONFIG_SETTING_VAL +#undef CONFIG_SETTING + +#define CONFIG_SETTING_VAL(access, variantType, type, name, defaultValue) \ + ret[#name] = convertToVariant(name); +#define CONFIG_SETTING(access, variantType, type, name) \ + ret[#name] = convertToVariant(name); + + CONFIG_SETTINGS() + + return ret; +} + +void PersistantConfig::applyValues(const QVariantMap &values) +{ +#undef CONFIG_SETTING_VAL +#undef CONFIG_SETTING + +#define CONFIG_SETTING_VAL(access, variantType, type, name, defaultValue) \ + if(values.contains(#name)) \ + name = convertFromVariant(values[#name].value()); +#define CONFIG_SETTING(access, variantType, type, name) \ + if(values.contains(#name)) \ + name = convertFromVariant(values[#name].value()); + + CONFIG_SETTINGS() +} + +void PersistantConfig::SetupFormatting() +{ + /* + Formatter.MinFigures = Formatter_MinFigures; + Formatter.MaxFigures = Formatter_MaxFigures; + Formatter.ExponentialNegCutoff = Formatter_NegExp; + Formatter.ExponentialPosCutoff = Formatter_PosExp; + + PreferredFont = Font_PreferMonospaced + ? new System.Drawing.Font("Consolas", 9.25F, System.Drawing.FontStyle.Regular, + System.Drawing.GraphicsUnit.Point, ((byte)(0))) + : new System.Drawing.Font("Tahoma", 8.25F); + */ +} + +void PersistantConfig::AddRecentFile(QList &recentList, const QString &file, int maxItems) +{ + QDir dir(file); + QString path = dir.canonicalPath(); + + if(!recentList.contains(path)) + { + recentList.push_back(path); + if(recentList.count() >= maxItems) + recentList.removeAt(0); + } + else + { + recentList.removeOne(path); + recentList.push_back(path); + } +} + +void PersistantConfig::SetConfigSetting(QString name, QString value) +{ + ConfigSettings[name] = value; + RENDERDOC_SetConfigSetting(name.toUtf8().data(), value.toUtf8().data()); +} + +QString PersistantConfig::GetConfigSetting(QString name) +{ + if(ConfigSettings.contains(name)) + return ConfigSettings[name]; + + return ""; +} diff --git a/qrenderdoc/Code/PersistantConfig.h b/qrenderdoc/Code/PersistantConfig.h new file mode 100644 index 000000000..889af32f1 --- /dev/null +++ b/qrenderdoc/Code/PersistantConfig.h @@ -0,0 +1,148 @@ +/****************************************************************************** + * The MIT License (MIT) + * + * Copyright (c) 2016 Baldur Karlsson + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in + * all copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN + * THE SOFTWARE. + ******************************************************************************/ + +#pragma once + +#include +#include +#include +#include +#include + +typedef QMap QStringMap; + +#define CONFIG_SETTING_VAL(access, variantType, type, name, defaultValue) \ + access: \ + type name = defaultValue; +#define CONFIG_SETTING(access, variantType, type, name) \ + access: \ + type name; + +#define CONFIG_SETTINGS() \ + \ +CONFIG_SETTING_VAL(public, QString, QString, LastLogPath, "") \ + \ +CONFIG_SETTING(public, QVariantList, QList, RecentLogFiles) \ + \ +CONFIG_SETTING_VAL(public, QString, QString, LastCapturePath, "") \ + \ +CONFIG_SETTING_VAL(public, QString, QString, LastCaptureExe, "") \ + \ +CONFIG_SETTING(public, QVariantList, QList, RecentCaptureSettings) \ + \ +CONFIG_SETTING_VAL(public, int, int, CallstackLevelSkip, 0) \ + \ +CONFIG_SETTING_VAL(public, QString, QString, TemporaryCaptureDirectory, "") \ + \ +CONFIG_SETTING_VAL(public, QString, QString, DefaultCaptureSaveDirectory, "") \ + \ +CONFIG_SETTING_VAL(public, bool, bool, TextureViewer_ResetRange, false) \ + \ +CONFIG_SETTING_VAL(public, bool, bool, TextureViewer_PerTexSettings, true) \ + \ +CONFIG_SETTING_VAL(public, bool, bool, ShaderViewer_FriendlyNaming, true) \ + \ +CONFIG_SETTING_VAL(public, bool, bool, AlwaysReplayLocally, false) \ + \ +CONFIG_SETTING_VAL(public, int, int, LocalProxy, 0) \ + \ +CONFIG_SETTING_VAL(public, int, TimeUnit, EventBrowser_TimeUnit, TimeUnit::Microseconds) \ + \ +CONFIG_SETTING_VAL(public, bool, bool, EventBrowser_HideEmpty, false) \ + \ +CONFIG_SETTING_VAL(public, bool, bool, EventBrowser_ApplyColours, true) \ + \ +CONFIG_SETTING_VAL(public, bool, bool, EventBrowser_ColourEventRow, true) \ + \ +CONFIG_SETTING_VAL(public, int, int, Formatter_MinFigures, 2) \ + \ +CONFIG_SETTING_VAL(public, int, int, Formatter_MaxFigures, 5) \ + \ +CONFIG_SETTING_VAL(public, int, int, Formatter_NegExp, 5) \ + \ +CONFIG_SETTING_VAL(public, int, int, Formatter_PosExp, 7) \ + \ +CONFIG_SETTING_VAL(public, bool, bool, Font_PreferMonospaced, false) \ + \ +CONFIG_SETTING_VAL(public, bool, bool, CheckUpdate_AllowChecks, true) \ + \ +CONFIG_SETTING_VAL(public, bool, bool, CheckUpdate_UpdateAvailable, false) \ + \ +CONFIG_SETTING_VAL(public, QString, QString, CheckUpdate_UpdateResponse, "") \ + \ +CONFIG_SETTING_VAL(public, QDateTime, QDateTime, CheckUpdate_LastUpdate, \ + QDateTime(QDate(2012, 06, 27), QTime(0, 0, 0))) \ + \ +CONFIG_SETTING_VAL(public, QDateTime, QDateTime, DegradedLog_LastUpdate, \ + QDateTime(QDate(2015, 01, 01), QTime(0, 0, 0))) \ + \ +CONFIG_SETTING_VAL(public, bool, bool, Tips_SeenFirst, false) \ + \ +CONFIG_SETTING_VAL(public, bool, bool, AllowGlobalHook, false) \ + \ +CONFIG_SETTING(private, QVariantMap, QStringMap, ConfigSettings) + +class PersistantConfig +{ +public: + enum class TimeUnit : int + { + Seconds = 0, + Milliseconds, + Microseconds, + Nanoseconds, + }; + + CONFIG_SETTINGS() + +public: + PersistantConfig() {} + bool Deserialize(QString filename); + bool Serialize(QString filename); + + void SetupFormatting(); + + static QString UnitPrefix(TimeUnit t) + { + if(t == TimeUnit::Seconds) + return "s"; + else if(t == TimeUnit::Milliseconds) + return "ms"; + else if(t == TimeUnit::Microseconds) + return "µs"; + else if(t == TimeUnit::Nanoseconds) + return "ns"; + + return "s"; + } + + static void AddRecentFile(QList &recentList, const QString &file, int maxItems); + + void SetConfigSetting(QString name, QString value); + QString GetConfigSetting(QString name); + +private: + QVariantMap storeValues() const; + void applyValues(const QVariantMap &values); +}; diff --git a/qrenderdoc/Code/main.cpp b/qrenderdoc/Code/main.cpp index 7d05cb167..4e08cc8dc 100644 --- a/qrenderdoc/Code/main.cpp +++ b/qrenderdoc/Code/main.cpp @@ -116,13 +116,30 @@ int main(int argc, char *argv[]) QApplication application(argc, argv_mod); { - CaptureContext ctx(filename, remoteHost, remoteIdent, temp); + PersistantConfig config; + + QString configFilename = CaptureContext::ConfigFile("UI.config"); + + if(!config.Deserialize(configFilename)) + { + RDDialog::critical( + NULL, "Error loading config", + QString( + "Error loading config file\n%1\nA default config is loaded and will be saved out.") + .arg(configFilename)); + } + + config.SetupFormatting(); + + CaptureContext ctx(filename, remoteHost, remoteIdent, temp, config); while(ctx.isRunning()) { application.processEvents(QEventLoop::WaitForMoreEvents); QCoreApplication::sendPostedEvents(); } + + config.Serialize(configFilename); } delete[] argv_mod; diff --git a/qrenderdoc/Windows/MainWindow.cpp b/qrenderdoc/Windows/MainWindow.cpp index cc78ebfd9..6005fe3d3 100644 --- a/qrenderdoc/Windows/MainWindow.cpp +++ b/qrenderdoc/Windows/MainWindow.cpp @@ -227,9 +227,6 @@ QVariantMap MainWindow::saveState() { QVariantMap state = ui->toolWindowManager->saveState(); - // marker that this is indeed a valid state to load from - state["renderdocLayoutData"] = 1; - state["mainWindowGeometry"] = saveGeometry().toBase64(); return state; @@ -250,6 +247,9 @@ bool MainWindow::SaveLayout(int layout) QVariantMap state = saveState(); + // marker that this is indeed a valid state to load from + state["renderdocLayoutData"] = 1; + QFile f(path); if(f.open(QIODevice::WriteOnly | QIODevice::Truncate | QIODevice::Text)) { diff --git a/qrenderdoc/qrenderdoc.pro b/qrenderdoc/qrenderdoc.pro index 2b0999003..8c9826207 100644 --- a/qrenderdoc/qrenderdoc.pro +++ b/qrenderdoc/qrenderdoc.pro @@ -89,6 +89,7 @@ SOURCES += Code/main.cpp \ 3rdparty/toolwindowmanager/ToolWindowManagerArea.cpp \ 3rdparty/toolwindowmanager/ToolWindowManagerWrapper.cpp \ Code/RenderManager.cpp \ + Code/PersistantConfig.cpp \ Code/CaptureContext.cpp \ Widgets/RDLineEdit.cpp \ 3rdparty/flowlayout/FlowLayout.cpp \ @@ -107,6 +108,7 @@ HEADERS += Windows/MainWindow.h \ 3rdparty/toolwindowmanager/ToolWindowManagerWrapper.h \ Code/CaptureContext.h \ Code/RenderManager.h \ + Code/PersistantConfig.h \ Widgets/RDLineEdit.h \ 3rdparty/flowlayout/FlowLayout.h \ Widgets/ResourcePreview.h \ diff --git a/qrenderdoc/qrenderdoc_local.vcxproj b/qrenderdoc/qrenderdoc_local.vcxproj index 057ee1612..c994b237c 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj +++ b/qrenderdoc/qrenderdoc_local.vcxproj @@ -277,6 +277,7 @@ + @@ -318,6 +319,7 @@ + diff --git a/qrenderdoc/qrenderdoc_local.vcxproj.filters b/qrenderdoc/qrenderdoc_local.vcxproj.filters index 8916e42d2..8af2e2790 100644 --- a/qrenderdoc/qrenderdoc_local.vcxproj.filters +++ b/qrenderdoc/qrenderdoc_local.vcxproj.filters @@ -133,6 +133,9 @@ Generated Files + + Generated Files + @@ -189,6 +192,9 @@ Code + + Generated Files +