mirror of
https://github.com/baldurk/renderdoc.git
synced 2026-05-06 01:50:38 +00:00
Add configuration system for core renderdoc module
* This allows persistent config storage and registering tweak variables that works independent of the UI's configuration. * Config vars can be debug only, which means they will be compiled out in stable version releases. This allows for debug-logging tweaks that are available in all builds (including nightly builds) for diagnostic purposes, but have zero overhead in stable releases. * Variables have a loose hierarchy defined with _ or . to separate nodes.
This commit is contained in:
@@ -153,6 +153,16 @@ bool PersistantConfig::Serialize(const rdcstr &filename)
|
||||
return false;
|
||||
}
|
||||
|
||||
struct LegacyData
|
||||
{
|
||||
QString _Android_SDKPath;
|
||||
QString _Android_JDKPath;
|
||||
uint32_t _Android_MaxConnectTimeout = 30;
|
||||
bool _ExternalTool_RGPIntegration = false;
|
||||
bool _ShaderViewer_FriendlyNaming = true;
|
||||
QVariantMap _ConfigSettings;
|
||||
};
|
||||
|
||||
QVariantMap PersistantConfig::storeValues() const
|
||||
{
|
||||
QVariantMap ret;
|
||||
@@ -167,6 +177,15 @@ QVariantMap PersistantConfig::storeValues() const
|
||||
|
||||
CONFIG_SETTINGS()
|
||||
|
||||
// store any legacy values even though we don't need them
|
||||
|
||||
ret[lit("Android_SDKPath")] = m_Legacy->_Android_SDKPath;
|
||||
ret[lit("Android_JDKPath")] = m_Legacy->_Android_JDKPath;
|
||||
ret[lit("Android_MaxConnectTimeout")] = m_Legacy->_Android_MaxConnectTimeout;
|
||||
ret[lit("ExternalTool_RGPIntegration")] = m_Legacy->_ExternalTool_RGPIntegration;
|
||||
ret[lit("ShaderViewer_FriendlyNaming")] = m_Legacy->_ShaderViewer_FriendlyNaming;
|
||||
ret[lit("ConfigSettings")] = m_Legacy->_ConfigSettings;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -197,6 +216,85 @@ void PersistantConfig::applyValues(const QVariantMap &values)
|
||||
// apply reasonable bounds to font scale to avoid invalid values
|
||||
// 25% - 400%
|
||||
Font_GlobalScale = qBound(0.25f, Font_GlobalScale, 4.0f);
|
||||
|
||||
// port old values that were saved here but are now saved in core.
|
||||
// We only want to do this once, but we want to leave these values in the config to allow for
|
||||
// people running old versions after running a new version - we don't want to remove all of their
|
||||
// settings yet.
|
||||
// So what we do is store an extra setting indicating that it's been ported - if that setting is
|
||||
// present we just store/save them blindly. This does mean they can change but we won't re-port
|
||||
// them.
|
||||
// After the new config ships in a stable release we can remove this as we don't generally support
|
||||
// forwards compatibility, only backwards compatibility, so it will be OK to drop the config
|
||||
// settings.
|
||||
bool processed = false;
|
||||
if(values.contains(lit("ConfigSettings")) &&
|
||||
values[lit("ConfigSettings")].toMap().contains(lit("modern.config.ported")))
|
||||
processed = true;
|
||||
|
||||
bool saveConfig = false;
|
||||
|
||||
#define CORE_SETTING(variantType, oldName, newName, data) \
|
||||
if(values.contains(lit(#oldName))) \
|
||||
{ \
|
||||
m_Legacy->_##oldName = values[lit(#oldName)].value<variantType>(); \
|
||||
if(!processed) \
|
||||
{ \
|
||||
SDObject *setting = RENDERDOC_SetConfigSetting(newName); \
|
||||
if(setting) \
|
||||
setting->data = m_Legacy->_##oldName; \
|
||||
saveConfig = true; \
|
||||
} \
|
||||
}
|
||||
|
||||
CORE_SETTING(QString, Android_SDKPath, "Android.SDKDirPath", data.str);
|
||||
CORE_SETTING(QString, Android_JDKPath, "Android.JDKDirPath", data.str);
|
||||
CORE_SETTING(uint32_t, Android_MaxConnectTimeout, "Android.MaxConnectTimeout", data.basic.u);
|
||||
CORE_SETTING(bool, ExternalTool_RGPIntegration, "AMD.RGP.Enable", data.basic.b);
|
||||
CORE_SETTING(bool, ShaderViewer_FriendlyNaming, "DXBC.Disassembly.FriendlyNaming", data.basic.b);
|
||||
|
||||
if(values.contains(lit("ConfigSettings")))
|
||||
{
|
||||
QVariantMap &settings = m_Legacy->_ConfigSettings;
|
||||
settings = values[lit("ConfigSettings")].toMap();
|
||||
|
||||
if(!processed)
|
||||
{
|
||||
if(settings.contains(lit("shader.debug.searchPaths")))
|
||||
{
|
||||
QStringList searchPaths = settings[lit("shader.debug.searchPaths")].toString().split(
|
||||
QLatin1Char(';'), QString::SkipEmptyParts);
|
||||
|
||||
SDObject *debug = RENDERDOC_SetConfigSetting("DXBC.Debug.SearchDirPaths");
|
||||
|
||||
debug->DeleteChildren();
|
||||
debug->data.children.resize(searchPaths.size());
|
||||
|
||||
for(int i = 0; i < searchPaths.size(); i++)
|
||||
debug->data.children[i] = makeSDString("$el", searchPaths[i]);
|
||||
}
|
||||
|
||||
if(settings.contains(lit("d3d12ShaderDebugging")))
|
||||
{
|
||||
RENDERDOC_SetConfigSetting("D3D12_ShaderDebugging")->data.basic.b =
|
||||
settings[lit("d3d12ShaderDebugging")].toBool();
|
||||
}
|
||||
|
||||
if(settings.contains(lit("vulkanShaderDebugging")))
|
||||
{
|
||||
RENDERDOC_SetConfigSetting("Vulkan_ShaderDebugging")->data.basic.b =
|
||||
settings[lit("vulkanShaderDebugging")].toBool();
|
||||
}
|
||||
|
||||
saveConfig = true;
|
||||
}
|
||||
|
||||
// mark the settings as ported so we don't do it again
|
||||
settings[lit("modern.config.ported")] = true;
|
||||
}
|
||||
|
||||
if(saveConfig)
|
||||
RENDERDOC_SaveConfigSettings();
|
||||
}
|
||||
|
||||
static QMutex RemoteHostLock;
|
||||
@@ -265,20 +363,6 @@ void PersistantConfig::RemoveRemoteHost(RemoteHost host)
|
||||
|
||||
void PersistantConfig::UpdateEnumeratedProtocolDevices()
|
||||
{
|
||||
QString androidSDKPath = (!Android_SDKPath.isEmpty() && QFile::exists(Android_SDKPath))
|
||||
? QString(Android_SDKPath)
|
||||
: QString();
|
||||
|
||||
SetConfigSetting("androidSDKPath", androidSDKPath);
|
||||
|
||||
QString androidJDKPath = (!Android_JDKPath.isEmpty() && QFile::exists(Android_JDKPath))
|
||||
? QString(Android_JDKPath)
|
||||
: QString();
|
||||
|
||||
SetConfigSetting("androidJDKPath", androidJDKPath);
|
||||
|
||||
SetConfigSetting("MaxConnectTimeout", QString::number(Android_MaxConnectTimeout));
|
||||
|
||||
rdcarray<RemoteHost> enumeratedDevices;
|
||||
|
||||
rdcarray<rdcstr> protocols;
|
||||
@@ -350,24 +434,20 @@ bool PersistantConfig::SetStyle()
|
||||
return false;
|
||||
}
|
||||
|
||||
PersistantConfig::PersistantConfig()
|
||||
{
|
||||
m_Legacy = new LegacyData;
|
||||
}
|
||||
|
||||
PersistantConfig::~PersistantConfig()
|
||||
{
|
||||
delete m_Legacy;
|
||||
}
|
||||
|
||||
bool PersistantConfig::Load(const rdcstr &filename)
|
||||
{
|
||||
bool ret = Deserialize(filename);
|
||||
|
||||
// perform some sanitisation to make sure config is always in sensible state
|
||||
for(const rdcstrpair &key : ConfigSettings)
|
||||
{
|
||||
// redundantly set each setting so it is flushed to the core dll
|
||||
SetConfigSetting(key.first, key.second);
|
||||
}
|
||||
|
||||
RENDERDOC_SetConfigSetting("Disassembly_FriendlyNaming", ShaderViewer_FriendlyNaming ? "1" : "0");
|
||||
RENDERDOC_SetConfigSetting("ExternalTool_RGPIntegration", ExternalTool_RGPIntegration ? "1" : "0");
|
||||
|
||||
RDDialog::DefaultBrowsePath = LastFileBrowsePath;
|
||||
|
||||
// localhost should always be available as a remote host
|
||||
@@ -501,9 +581,6 @@ bool PersistantConfig::Save()
|
||||
if(m_Filename.isEmpty())
|
||||
return true;
|
||||
|
||||
RENDERDOC_SetConfigSetting("Disassembly_FriendlyNaming", ShaderViewer_FriendlyNaming ? "1" : "0");
|
||||
RENDERDOC_SetConfigSetting("ExternalTool_RGPIntegration", ExternalTool_RGPIntegration ? "1" : "0");
|
||||
|
||||
LastFileBrowsePath = RDDialog::DefaultBrowsePath;
|
||||
|
||||
// truncate the lists to a maximum of 9 items, allow more to exist in memory
|
||||
@@ -557,36 +634,6 @@ void AddRecentFile(rdcarray<rdcstr> &recentList, const rdcstr &file)
|
||||
recentList.push_back(path);
|
||||
}
|
||||
|
||||
void PersistantConfig::SetConfigSetting(const rdcstr &name, const rdcstr &value)
|
||||
{
|
||||
if(name.isEmpty())
|
||||
return;
|
||||
|
||||
bool found = false;
|
||||
for(rdcstrpair &kv : ConfigSettings)
|
||||
{
|
||||
if(kv.first == name)
|
||||
{
|
||||
kv.second = value;
|
||||
found = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!found)
|
||||
ConfigSettings.push_back(make_rdcpair(name, value));
|
||||
RENDERDOC_SetConfigSetting(name.data(), value.data());
|
||||
}
|
||||
|
||||
rdcstr PersistantConfig::GetConfigSetting(const rdcstr &name)
|
||||
{
|
||||
for(const rdcstrpair &kv : ConfigSettings)
|
||||
if(kv.first == name)
|
||||
return kv.second;
|
||||
|
||||
return "";
|
||||
}
|
||||
|
||||
ShaderProcessingTool::ShaderProcessingTool(const QVariant &var)
|
||||
{
|
||||
QVariantMap map = var.toMap();
|
||||
|
||||
@@ -302,8 +302,6 @@ DECLARE_REFLECTION_STRUCT(BugReport);
|
||||
\
|
||||
CONFIG_SETTING_VAL(public, bool, bool, TextureViewer_PerTexYFlip, false) \
|
||||
\
|
||||
CONFIG_SETTING_VAL(public, bool, bool, ShaderViewer_FriendlyNaming, true) \
|
||||
\
|
||||
CONFIG_SETTING_VAL(public, bool, bool, AlwaysReplayLocally, false) \
|
||||
\
|
||||
CONFIG_SETTING_VAL(public, int, int, LocalProxyAPI, -1) \
|
||||
@@ -336,12 +334,6 @@ DECLARE_REFLECTION_STRUCT(BugReport);
|
||||
\
|
||||
CONFIG_SETTING_VAL(public, bool, bool, Font_PreferMonospaced, false) \
|
||||
\
|
||||
CONFIG_SETTING_VAL(public, QString, rdcstr, Android_SDKPath, "") \
|
||||
\
|
||||
CONFIG_SETTING_VAL(public, QString, rdcstr, Android_JDKPath, "") \
|
||||
\
|
||||
CONFIG_SETTING_VAL(public, int, int, Android_MaxConnectTimeout, 30) \
|
||||
\
|
||||
CONFIG_SETTING_VAL(public, QDateTime, rdcdatetime, UnsupportedAndroid_LastUpdate, \
|
||||
rdcdatetime(2015, 01, 01)) \
|
||||
\
|
||||
@@ -359,8 +351,6 @@ DECLARE_REFLECTION_STRUCT(BugReport);
|
||||
CONFIG_SETTING_VAL(public, QDateTime, rdcdatetime, DegradedCapture_LastUpdate, \
|
||||
rdcdatetime(2015, 01, 01)) \
|
||||
\
|
||||
CONFIG_SETTING_VAL(public, bool, bool, ExternalTool_RGPIntegration, false) \
|
||||
\
|
||||
CONFIG_SETTING_VAL(public, QString, rdcstr, ExternalTool_RadeonGPUProfiler, "") \
|
||||
\
|
||||
CONFIG_SETTING_VAL(public, bool, bool, Tips_HasSeenFirst, false) \
|
||||
@@ -385,8 +375,6 @@ DECLARE_REFLECTION_STRUCT(BugReport);
|
||||
\
|
||||
CONFIG_SETTING(public, QVariantList, rdcarray<rdcstr>, AlwaysLoad_Extensions) \
|
||||
\
|
||||
CONFIG_SETTING(private, QVariantMap, rdcstrpairs, ConfigSettings) \
|
||||
\
|
||||
CONFIG_SETTING(private, QVariantList, rdcarray<RemoteHost>, RemoteHostList)
|
||||
|
||||
DOCUMENT(R"(The unit that GPU durations are displayed in.
|
||||
@@ -458,6 +446,8 @@ As the name suggests, this is used for tracking a 'recent file' list.
|
||||
)");
|
||||
void RemoveRecentFile(rdcarray<rdcstr> &recentList, const rdcstr &file);
|
||||
|
||||
struct LegacyData;
|
||||
|
||||
DOCUMENT2(R"(A persistant config file that is automatically loaded and saved, which contains any
|
||||
settings and information that needs to be preserved from one run to the next.
|
||||
|
||||
@@ -533,13 +523,6 @@ For more information about some of these settings that are user-facing see
|
||||
|
||||
Defaults to ``False``.
|
||||
|
||||
.. data:: ShaderViewer_FriendlyNaming
|
||||
|
||||
``True`` if the :class:`ShaderViewer` should replace register names with the high-level language
|
||||
variable names where possible.
|
||||
|
||||
Defaults to ``True``.
|
||||
|
||||
.. data:: AlwaysReplayLocally
|
||||
|
||||
``True`` if when loading a capture that was originally captured on a remote device but uses an
|
||||
@@ -655,24 +638,6 @@ For more information about some of these settings that are user-facing see
|
||||
|
||||
Defaults to ``False``.
|
||||
|
||||
.. data:: Android_SDKPath
|
||||
|
||||
The path to the root of the android SDK, to locate android tools to use for android remote hosts.
|
||||
|
||||
Defaults to using the tools distributed with RenderDoc.
|
||||
|
||||
.. data:: Android_JDKPath
|
||||
|
||||
The path to the root of the Java JDK, to locate java for running android java tools.
|
||||
|
||||
Defaults to using the JAVA_HOME environment variable, if set.
|
||||
|
||||
.. data:: Android_MaxConnectTimeout
|
||||
|
||||
The maximum timeout in seconds to wait when launching an Android package.
|
||||
|
||||
Defaults to ``30``.
|
||||
|
||||
.. data:: UnsupportedAndroid_LastUpdate
|
||||
|
||||
A date containing the last time that the user was warned about an Android device being older than
|
||||
@@ -713,10 +678,6 @@ For more information about some of these settings that are user-facing see
|
||||
A date containing the last time that the user was warned about captures being loaded in degraded
|
||||
support. This prevents the user being spammed if their hardware is low spec.
|
||||
|
||||
.. data:: ExternalTool_RGPIntegration
|
||||
|
||||
Whether to enable integration with the external Radeon GPU Profiler tool.
|
||||
|
||||
.. data:: ExternalTool_RadeonGPUProfiler
|
||||
|
||||
The path to the executable of the external Radeon GPU Profiler tool.
|
||||
@@ -788,7 +749,6 @@ For more information about some of these settings that are user-facing see
|
||||
A list of strings with extension packages to always load on startup, without needing manual
|
||||
enabling.
|
||||
|
||||
|
||||
)");
|
||||
class PersistantConfig
|
||||
{
|
||||
@@ -822,7 +782,7 @@ public:
|
||||
DOCUMENT("");
|
||||
CONFIG_SETTINGS()
|
||||
public:
|
||||
PersistantConfig() {}
|
||||
PersistantConfig();
|
||||
~PersistantConfig();
|
||||
|
||||
DOCUMENT(R"(Loads the config from a given filename. This happens automatically on startup, so it's
|
||||
@@ -854,21 +814,6 @@ loading. It can explicitly save and close before relaunching.
|
||||
DOCUMENT("Configures the :class:`Formatter` class with the settings from this config.");
|
||||
void SetupFormatting();
|
||||
|
||||
DOCUMENT(R"(Sets an arbitrary dynamic setting similar to a key-value store. This can be used for
|
||||
storing custom settings to be persisted without needing to modify code.
|
||||
|
||||
:param str name: The name of the setting. Any existing setting will be overwritten.
|
||||
:param str value: The contents of the setting.
|
||||
)");
|
||||
void SetConfigSetting(const rdcstr &name, const rdcstr &value);
|
||||
DOCUMENT(R"(Retrieves an arbitrary dynamic setting. See :meth:`SetConfigSetting`.
|
||||
|
||||
:param str name: The name of the setting.
|
||||
:return: The value of the setting, or the empty string if the setting did not exist.
|
||||
:rtype: ``str``
|
||||
)");
|
||||
rdcstr GetConfigSetting(const rdcstr &name);
|
||||
|
||||
DOCUMENT(R"(Sets the UI style to the value in :data:`UIStyle`.
|
||||
|
||||
Changing the style after the application has started may not properly update everything, so to be
|
||||
@@ -891,4 +836,8 @@ private:
|
||||
#endif
|
||||
|
||||
rdcstr m_Filename;
|
||||
|
||||
// legacy storage for config settings that were ported into the core config. We keep them here
|
||||
// so we can store them out again, to keep the config the same for a while even if it's unused
|
||||
LegacyData *m_Legacy;
|
||||
};
|
||||
|
||||
@@ -107,6 +107,10 @@ bool PersistantConfig::SetStyle()
|
||||
return false;
|
||||
}
|
||||
|
||||
PersistantConfig::PersistantConfig()
|
||||
{
|
||||
}
|
||||
|
||||
PersistantConfig::~PersistantConfig()
|
||||
{
|
||||
}
|
||||
@@ -159,15 +163,6 @@ void RemoveRecentFile(rdcarray<rdcstr> &recentList, const rdcstr &file)
|
||||
{
|
||||
}
|
||||
|
||||
void PersistantConfig::SetConfigSetting(const rdcstr &name, const rdcstr &value)
|
||||
{
|
||||
}
|
||||
|
||||
rdcstr PersistantConfig::GetConfigSetting(const rdcstr &name)
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
// RemoteHost.cpp stubs
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
@@ -0,0 +1,701 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 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 "ConfigEditor.h"
|
||||
#include <float.h>
|
||||
#include <QDoubleSpinBox>
|
||||
#include <QSpinBox>
|
||||
#include "Code/QRDUtils.h"
|
||||
#include "Code/Resources.h"
|
||||
#include "Widgets/Extended/RDHeaderView.h"
|
||||
#include "Widgets/Extended/RDLineEdit.h"
|
||||
#include "Widgets/OrderedListEditor.h"
|
||||
#include "ui_ConfigEditor.h"
|
||||
|
||||
static QString valueString(const SDObject *o)
|
||||
{
|
||||
if(o->type.basetype == SDBasic::String)
|
||||
return o->data.str;
|
||||
|
||||
if(o->type.basetype == SDBasic::UnsignedInteger)
|
||||
return Formatter::Format(o->data.basic.u);
|
||||
|
||||
if(o->type.basetype == SDBasic::SignedInteger)
|
||||
return Formatter::Format(o->data.basic.i);
|
||||
|
||||
if(o->type.basetype == SDBasic::Float)
|
||||
return Formatter::Format(o->data.basic.d);
|
||||
|
||||
if(o->type.basetype == SDBasic::Boolean)
|
||||
return o->data.basic.b ? lit("True") : lit("False");
|
||||
|
||||
if(o->type.basetype == SDBasic::Array)
|
||||
return lit("{...}");
|
||||
|
||||
return lit("??");
|
||||
}
|
||||
|
||||
static bool anyChildChanged(const SDObject *o)
|
||||
{
|
||||
SDObject *def = o->FindChild("default");
|
||||
SDObject *val = o->FindChild("value");
|
||||
|
||||
if(val && def)
|
||||
return !val->HasEqualValue(def);
|
||||
|
||||
for(const SDObject *c : o->data.children)
|
||||
{
|
||||
if(anyChildChanged(c))
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
class SettingModel : public QAbstractItemModel
|
||||
{
|
||||
public:
|
||||
SettingModel(ConfigEditor *view) : QAbstractItemModel(view), m_Viewer(view)
|
||||
{
|
||||
populateParents(m_Viewer->m_Config, QModelIndex());
|
||||
}
|
||||
|
||||
void refresh()
|
||||
{
|
||||
emit beginResetModel();
|
||||
emit endResetModel();
|
||||
}
|
||||
|
||||
QModelIndex index(int row, int column, const QModelIndex &parent = QModelIndex()) const override
|
||||
{
|
||||
SDObject *o = obj(parent);
|
||||
|
||||
if(row < 0 || row > rowCount(parent))
|
||||
return QModelIndex();
|
||||
|
||||
return createIndex(row, column, o->data.children[row]);
|
||||
}
|
||||
|
||||
QModelIndex parent(const QModelIndex &index) const override
|
||||
{
|
||||
SDObject *o = obj(index);
|
||||
|
||||
if(o == m_Viewer->m_Config)
|
||||
return QModelIndex();
|
||||
|
||||
QModelIndex ret = parents[o];
|
||||
|
||||
if(!ret.isValid())
|
||||
return ret;
|
||||
|
||||
return createIndex(ret.row(), index.column(), ret.internalPointer());
|
||||
}
|
||||
|
||||
int rowCount(const QModelIndex &parent = QModelIndex()) const override
|
||||
{
|
||||
SDObject *o = obj(parent);
|
||||
|
||||
// values don't have children
|
||||
if(o->FindChild("value"))
|
||||
return 0;
|
||||
|
||||
return o->data.children.count();
|
||||
}
|
||||
|
||||
enum Columns
|
||||
{
|
||||
Column_Name,
|
||||
Column_Value,
|
||||
Column_ResetButton,
|
||||
Column_Count,
|
||||
};
|
||||
|
||||
Qt::ItemFlags flags(const QModelIndex &index) const override
|
||||
{
|
||||
if(!index.isValid())
|
||||
return 0;
|
||||
|
||||
Qt::ItemFlags ret = QAbstractItemModel::flags(index);
|
||||
|
||||
if(index.column() == Column_Value)
|
||||
{
|
||||
SDObject *o = obj(index);
|
||||
SDObject *value = o->FindChild("value");
|
||||
|
||||
if(value)
|
||||
{
|
||||
ret |= Qt::ItemIsEditable;
|
||||
if(value->type.basetype == SDBasic::Boolean)
|
||||
ret |= Qt::ItemIsUserCheckable;
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
int columnCount(const QModelIndex &parent = QModelIndex()) const override { return Column_Count; }
|
||||
QVariant headerData(int section, Qt::Orientation orientation, int role) const override
|
||||
{
|
||||
if(orientation == Qt::Horizontal && role == Qt::DisplayRole)
|
||||
{
|
||||
switch(section)
|
||||
{
|
||||
case Column_Name: return lit("Setting");
|
||||
case Column_Value: return lit("Value");
|
||||
case Column_ResetButton: return lit("Reset");
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
bool setData(const QModelIndex &index, const QVariant &val, int role) override
|
||||
{
|
||||
SDObject *o = NULL;
|
||||
|
||||
if(role == Qt::UserRole)
|
||||
{
|
||||
// if we have setData for user role, that means we got reset. Just need to emit data changed
|
||||
o = obj(index);
|
||||
}
|
||||
else if(index.column() == Column_Value)
|
||||
{
|
||||
o = obj(index);
|
||||
|
||||
SDObject *value = o->FindChild("value");
|
||||
|
||||
if(role == Qt::CheckStateRole && value)
|
||||
{
|
||||
value->data.basic.b = (val.toInt() == Qt::CheckState::Checked);
|
||||
}
|
||||
else
|
||||
{
|
||||
// didn't change anything we care about
|
||||
o = NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if(o)
|
||||
{
|
||||
// dataChanged this index and all parents (in case a section became non-customised, or
|
||||
// customised, and it wasn't before)
|
||||
QModelIndex idx = index;
|
||||
while(idx.isValid())
|
||||
{
|
||||
o = obj(idx);
|
||||
emit dataChanged(createIndex(idx.row(), 0, o), createIndex(idx.row(), Column_Count, o),
|
||||
{Qt::DisplayRole, Qt::CheckStateRole, Qt::FontRole});
|
||||
|
||||
idx = parents[o];
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
QVariant data(const QModelIndex &index, int role = Qt::DisplayRole) const override
|
||||
{
|
||||
if(index.isValid())
|
||||
{
|
||||
SDObject *o = obj(index);
|
||||
int col = index.column();
|
||||
|
||||
SDObject *value = o->FindChild("value");
|
||||
|
||||
if(role == Qt::UserRole)
|
||||
{
|
||||
return QVariant::fromValue((quintptr)o);
|
||||
}
|
||||
else if(role == Qt::DisplayRole)
|
||||
{
|
||||
switch(col)
|
||||
{
|
||||
case Column_Name: return o->name;
|
||||
case Column_Value:
|
||||
return value && value->type.basetype != SDBasic::Boolean ? valueString(value)
|
||||
: QVariant();
|
||||
case Column_ResetButton: return anyChildChanged(o) ? lit("...") : QVariant();
|
||||
default: break;
|
||||
}
|
||||
}
|
||||
else if(role == Qt::CheckStateRole && col == Column_Value)
|
||||
{
|
||||
if(value && value->type.basetype == SDBasic::Boolean)
|
||||
return value->data.basic.b ? Qt::CheckState::Checked : Qt::CheckState::Unchecked;
|
||||
return QVariant();
|
||||
}
|
||||
else if(role == Qt::TextAlignmentRole && col == Column_ResetButton)
|
||||
{
|
||||
return Qt::AlignHCenter + Qt::AlignTop;
|
||||
}
|
||||
else if(role == Qt::ToolTipRole)
|
||||
{
|
||||
SDObject *desc = o->FindChild("description");
|
||||
if(desc)
|
||||
return desc->AsString();
|
||||
}
|
||||
else if(role == Qt::FontRole)
|
||||
{
|
||||
if(anyChildChanged(o))
|
||||
{
|
||||
QFont font;
|
||||
font.setBold(true);
|
||||
return font;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return QVariant();
|
||||
}
|
||||
|
||||
private:
|
||||
SDObject *obj(const QModelIndex &parent) const
|
||||
{
|
||||
SDObject *ret = (SDObject *)parent.internalPointer();
|
||||
if(ret == NULL)
|
||||
ret = m_Viewer->m_Config;
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Qt models need child->parent relationships. We don't have that with SDObject but they are
|
||||
// immutable so we can cache them
|
||||
QMap<SDObject *, QModelIndex> parents;
|
||||
|
||||
void populateParents(SDObject *o, QModelIndex parent)
|
||||
{
|
||||
if(o->FindChild("value"))
|
||||
return;
|
||||
|
||||
int i = 0;
|
||||
for(SDObject *c : o->GetChildren())
|
||||
{
|
||||
parents[c] = parent;
|
||||
populateParents(c, index(i++, 0, parent));
|
||||
}
|
||||
}
|
||||
|
||||
ConfigEditor *m_Viewer;
|
||||
};
|
||||
|
||||
class SettingFilterModel : public QSortFilterProxyModel
|
||||
{
|
||||
public:
|
||||
explicit SettingFilterModel(ConfigEditor *view) : QSortFilterProxyModel(view), m_Viewer(view) {}
|
||||
void setFilter(QString text)
|
||||
{
|
||||
m_Text = text;
|
||||
m_KeyText = m_Text;
|
||||
m_KeyText.replace(QLatin1Char('.'), QLatin1Char('_'));
|
||||
emit beginResetModel();
|
||||
emit endResetModel();
|
||||
}
|
||||
|
||||
protected:
|
||||
virtual bool filterAcceptsRow(int source_row, const QModelIndex &source_parent) const override
|
||||
{
|
||||
if(m_Text.isEmpty())
|
||||
return true;
|
||||
|
||||
SDObject *o = obj(source_parent);
|
||||
|
||||
return matchesAnyChild(o->data.children[source_row]);
|
||||
}
|
||||
|
||||
bool matchesAnyChild(SDObject *o) const
|
||||
{
|
||||
if(QString(o->name).contains(m_Text, Qt::CaseInsensitive))
|
||||
return true;
|
||||
|
||||
if(o->FindChild("value"))
|
||||
{
|
||||
if(QString(o->FindChild("key")->AsString()).contains(m_KeyText, Qt::CaseInsensitive))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
for(SDObject *c : o->GetChildren())
|
||||
if(matchesAnyChild(c))
|
||||
return true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private:
|
||||
SDObject *obj(const QModelIndex &parent) const
|
||||
{
|
||||
SDObject *ret = (SDObject *)parent.internalPointer();
|
||||
if(ret == NULL)
|
||||
ret = m_Viewer->m_Config;
|
||||
return ret;
|
||||
}
|
||||
ConfigEditor *m_Viewer;
|
||||
|
||||
QString m_Text;
|
||||
QString m_KeyText;
|
||||
};
|
||||
|
||||
SettingDelegate::SettingDelegate(ConfigEditor *editor, RDTreeView *parent)
|
||||
: QStyledItemDelegate(parent), m_Editor(editor), m_View(parent)
|
||||
{
|
||||
}
|
||||
|
||||
SettingDelegate::~SettingDelegate()
|
||||
{
|
||||
}
|
||||
|
||||
void SettingDelegate::paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
if(index.column() == SettingModel::Column_ResetButton)
|
||||
{
|
||||
SDObject *o = (SDObject *)index.data(Qt::UserRole).toULongLong();
|
||||
|
||||
SDObject *def = o->FindChild("default");
|
||||
SDObject *val = o->FindChild("value");
|
||||
|
||||
if(val && def && !val->HasEqualValue(def))
|
||||
{
|
||||
// draw the item without text, so we get the proper background/selection/etc.
|
||||
// we'd like to be able to use the parent delegate's paint here, but either it calls to
|
||||
// QStyledItemDelegate which will re-fetch the text (bleh), or it calls to the manual
|
||||
// delegate which could do anything. So for this case we just use the style and skip the
|
||||
// delegate and hope it works out.
|
||||
QStyleOptionViewItem opt = option;
|
||||
QStyledItemDelegate::initStyleOption(&opt, index);
|
||||
opt.text.clear();
|
||||
m_Editor->style()->drawControl(QStyle::CE_ItemViewItem, &opt, painter, m_Editor);
|
||||
|
||||
QStyleOptionToolButton buttonOpt;
|
||||
|
||||
int size = m_Editor->style()->pixelMetric(QStyle::PM_SmallIconSize, 0, m_Editor);
|
||||
|
||||
buttonOpt.iconSize = QSize(size, size);
|
||||
buttonOpt.subControls = 0;
|
||||
buttonOpt.activeSubControls = 0;
|
||||
buttonOpt.features = QStyleOptionToolButton::None;
|
||||
buttonOpt.arrowType = Qt::NoArrow;
|
||||
buttonOpt.state = QStyle::State_Active | QStyle::State_Enabled | QStyle::State_AutoRaise;
|
||||
|
||||
buttonOpt.rect = option.rect.adjusted(0, 0, -1, -1);
|
||||
buttonOpt.icon = Icons::arrow_undo();
|
||||
|
||||
if(m_View->currentHoverIndex() == index)
|
||||
buttonOpt.state |= QStyle::State_MouseOver;
|
||||
|
||||
m_Editor->style()->drawComplexControl(QStyle::CC_ToolButton, &buttonOpt, painter, m_Editor);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::paint(painter, option, index);
|
||||
}
|
||||
|
||||
QSize SettingDelegate::sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const
|
||||
{
|
||||
return QStyledItemDelegate::sizeHint(option, index);
|
||||
}
|
||||
|
||||
bool SettingDelegate::editorEvent(QEvent *event, QAbstractItemModel *model,
|
||||
const QStyleOptionViewItem &option, const QModelIndex &index)
|
||||
{
|
||||
if(event->type() == QEvent::MouseButtonRelease && index.column() == SettingModel::Column_ResetButton)
|
||||
{
|
||||
SDObject *o = (SDObject *)index.data(Qt::UserRole).toULongLong();
|
||||
|
||||
SDObject *def = o->FindChild("default");
|
||||
SDObject *val = o->FindChild("value");
|
||||
|
||||
if(def && val)
|
||||
{
|
||||
val->data.str = def->data.str;
|
||||
memcpy(&val->data.basic, &def->data.basic, sizeof(val->data.basic));
|
||||
|
||||
val->DeleteChildren();
|
||||
|
||||
for(size_t c = 0; c < def->data.children.size(); c++)
|
||||
val->data.children.push_back(def->data.children[c]->Duplicate());
|
||||
|
||||
// call setData() to emit the dataChanged for this element and all parents
|
||||
model->setData(index, QVariant(), Qt::UserRole);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return QStyledItemDelegate::editorEvent(event, model, option, index);
|
||||
}
|
||||
|
||||
QWidget *SettingDelegate::createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
QWidget *ret = NULL;
|
||||
|
||||
SDObject *o = (SDObject *)index.data(Qt::UserRole).toULongLong();
|
||||
SDObject *val = o->FindChild("value");
|
||||
if(val)
|
||||
{
|
||||
// bools should have checkboxes
|
||||
if(val->type.basetype == SDBasic::Boolean)
|
||||
{
|
||||
qWarning() << "Unexpected createEditor for boolean " << QString(o->name);
|
||||
return ret;
|
||||
}
|
||||
|
||||
// for numbers, provide a spinbox
|
||||
if(val->type.basetype == SDBasic::UnsignedInteger || val->type.basetype == SDBasic::SignedInteger)
|
||||
{
|
||||
QSpinBox *spin = new QSpinBox(parent);
|
||||
ret = spin;
|
||||
if(val->type.basetype == SDBasic::UnsignedInteger)
|
||||
spin->setMinimum(0);
|
||||
else
|
||||
spin->setMinimum(INT_MIN);
|
||||
spin->setMaximum(INT_MAX);
|
||||
}
|
||||
else if(val->type.basetype == SDBasic::Float)
|
||||
{
|
||||
QDoubleSpinBox *spin = new QDoubleSpinBox(parent);
|
||||
ret = spin;
|
||||
spin->setSingleStep(0.1);
|
||||
spin->setMinimum(-FLT_MAX);
|
||||
spin->setMaximum(FLT_MAX);
|
||||
}
|
||||
else if(val->type.basetype == SDBasic::String)
|
||||
{
|
||||
if(QString(o->name).contains(lit("DirPath"), Qt::CaseSensitive))
|
||||
{
|
||||
QString dir = RDDialog::getExistingDirectory(
|
||||
m_Editor, tr("Browse for %1").arg(o->FindChild("key")->AsString()));
|
||||
|
||||
if(!dir.isEmpty())
|
||||
{
|
||||
val->data.str = dir;
|
||||
|
||||
// we've handled the edit synchronously, don't create an edit widget
|
||||
ret = NULL;
|
||||
|
||||
// call setData() to emit the dataChanged for this element and all parents
|
||||
m_View->model()->setData(index, QVariant(), Qt::UserRole);
|
||||
}
|
||||
}
|
||||
else if(QString(o->name).contains(lit("Path"), Qt::CaseSensitive))
|
||||
{
|
||||
QString file = RDDialog::getOpenFileName(
|
||||
m_Editor, tr("Browse for %1").arg(o->FindChild("key")->AsString()));
|
||||
|
||||
if(!file.isEmpty())
|
||||
{
|
||||
val->data.str = file;
|
||||
|
||||
// we've handled the edit synchronously, don't create an edit widget
|
||||
ret = NULL;
|
||||
|
||||
// call setData() to emit the dataChanged for this element and all parents
|
||||
m_View->model()->setData(index, QVariant(), Qt::UserRole);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
RDLineEdit *line = new RDLineEdit(parent);
|
||||
ret = line;
|
||||
|
||||
QObject::connect(line, &RDLineEdit::keyPress, this, &SettingDelegate::editorKeyPress);
|
||||
}
|
||||
}
|
||||
else if(val->type.basetype == SDBasic::Array)
|
||||
{
|
||||
// only support arrays of strings. Pop up a separate editor to handle this
|
||||
QDialog listEditor;
|
||||
|
||||
listEditor.setWindowTitle(tr("Edit values of %1").arg(QString(o->FindChild("key")->AsString())));
|
||||
listEditor.setWindowFlags(listEditor.windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
BrowseMode mode = BrowseMode::None;
|
||||
|
||||
if(QString(o->name).contains(lit("DirPath"), Qt::CaseSensitive))
|
||||
mode = BrowseMode::Folder;
|
||||
else if(QString(o->name).contains(lit("Path"), Qt::CaseSensitive))
|
||||
mode = BrowseMode::File;
|
||||
|
||||
OrderedListEditor list(tr("Entry"), mode);
|
||||
|
||||
QVBoxLayout layout;
|
||||
QDialogButtonBox okCancel;
|
||||
okCancel.setStandardButtons(QDialogButtonBox::Cancel | QDialogButtonBox::Ok);
|
||||
layout.addWidget(&list);
|
||||
layout.addWidget(&okCancel);
|
||||
|
||||
QObject::connect(&okCancel, &QDialogButtonBox::accepted, &listEditor, &QDialog::accept);
|
||||
QObject::connect(&okCancel, &QDialogButtonBox::rejected, &listEditor, &QDialog::reject);
|
||||
|
||||
listEditor.setLayout(&layout);
|
||||
|
||||
QStringList items;
|
||||
|
||||
for(SDObject *c : val->data.children)
|
||||
items << c->data.str;
|
||||
|
||||
list.setItems(items);
|
||||
|
||||
int res = RDDialog::show(&listEditor);
|
||||
|
||||
if(res)
|
||||
{
|
||||
items = list.getItems();
|
||||
|
||||
val->DeleteChildren();
|
||||
val->data.children.resize(items.size());
|
||||
|
||||
for(int i = 0; i < items.size(); i++)
|
||||
val->data.children[i] = makeSDString("$el", items[i]);
|
||||
}
|
||||
|
||||
// we've handled the edit synchronously, don't create an edit widget
|
||||
ret = NULL;
|
||||
|
||||
// call setData() to emit the dataChanged for this element and all parents
|
||||
m_View->model()->setData(index, QVariant(), Qt::UserRole);
|
||||
}
|
||||
else
|
||||
{
|
||||
qWarning() << "Unexpected type of " << QString(o->name)
|
||||
<< " to edit: " << ToQStr(val->type.basetype);
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
void SettingDelegate::editorKeyPress(QKeyEvent *ev)
|
||||
{
|
||||
QLineEdit *line = qobject_cast<QLineEdit *>(QObject::sender());
|
||||
|
||||
if(ev->key() == Qt::Key_Return || ev->key() == Qt::Key_Enter)
|
||||
{
|
||||
commitData(line);
|
||||
closeEditor(line);
|
||||
}
|
||||
else if(ev->key() == Qt::Key_Escape)
|
||||
{
|
||||
closeEditor(line);
|
||||
}
|
||||
}
|
||||
|
||||
void SettingDelegate::setEditorData(QWidget *editor, const QModelIndex &index) const
|
||||
{
|
||||
SDObject *o = (SDObject *)index.data(Qt::UserRole).toULongLong();
|
||||
SDObject *val = o->FindChild("value");
|
||||
if(val)
|
||||
{
|
||||
if(val->type.basetype == SDBasic::Boolean)
|
||||
{
|
||||
qWarning() << "Unexpected setEditorData for boolean " << QString(o->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if(val->type.basetype == SDBasic::UnsignedInteger)
|
||||
qobject_cast<QSpinBox *>(editor)->setValue(val->AsUInt32() & 0x7fffffffU);
|
||||
else if(val->type.basetype == SDBasic::SignedInteger)
|
||||
qobject_cast<QSpinBox *>(editor)->setValue(val->AsInt32());
|
||||
else if(val->type.basetype == SDBasic::Float)
|
||||
qobject_cast<QDoubleSpinBox *>(editor)->setValue(val->AsDouble());
|
||||
else if(val->type.basetype == SDBasic::String)
|
||||
qobject_cast<QLineEdit *>(editor)->setText(val->AsString());
|
||||
else
|
||||
qWarning() << "Unexpected type of " << QString(o->name) << ": " << ToQStr(val->type.basetype);
|
||||
}
|
||||
}
|
||||
|
||||
void SettingDelegate::setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const
|
||||
{
|
||||
SDObject *o = (SDObject *)index.data(Qt::UserRole).toULongLong();
|
||||
SDObject *val = o->FindChild("value");
|
||||
if(val)
|
||||
{
|
||||
if(val->type.basetype == SDBasic::Boolean)
|
||||
{
|
||||
qWarning() << "Unexpected setModelData for boolean " << QString(o->name);
|
||||
return;
|
||||
}
|
||||
|
||||
if(val->type.basetype == SDBasic::UnsignedInteger)
|
||||
val->data.basic.u = qMax(0, qobject_cast<QSpinBox *>(editor)->value());
|
||||
else if(val->type.basetype == SDBasic::SignedInteger)
|
||||
val->data.basic.i = qobject_cast<QSpinBox *>(editor)->value();
|
||||
else if(val->type.basetype == SDBasic::Float)
|
||||
val->data.basic.d = qobject_cast<QSpinBox *>(editor)->value();
|
||||
else if(val->type.basetype == SDBasic::String)
|
||||
val->data.str = qobject_cast<QLineEdit *>(editor)->text();
|
||||
else
|
||||
qWarning() << "Unexpected type of " << QString(o->name) << ": " << ToQStr(val->type.basetype);
|
||||
}
|
||||
}
|
||||
|
||||
ConfigEditor::ConfigEditor(QWidget *parent) : QDialog(parent), ui(new Ui::ConfigEditor)
|
||||
{
|
||||
ui->setupUi(this);
|
||||
setWindowFlags(windowFlags() & ~Qt::WindowContextHelpButtonHint);
|
||||
|
||||
m_Config = RENDERDOC_SetConfigSetting("");
|
||||
|
||||
m_SettingModel = new SettingModel(this);
|
||||
m_FilterModel = new SettingFilterModel(this);
|
||||
|
||||
m_FilterModel->setSourceModel(m_SettingModel);
|
||||
ui->settings->setModel(m_FilterModel);
|
||||
|
||||
{
|
||||
RDHeaderView *header = new RDHeaderView(Qt::Horizontal, ui->settings);
|
||||
ui->settings->setHeader(header);
|
||||
|
||||
header->setColumnStretchHints({-1, 1, -1});
|
||||
}
|
||||
|
||||
ui->settings->setItemDelegate(new SettingDelegate(this, ui->settings));
|
||||
}
|
||||
|
||||
ConfigEditor::~ConfigEditor()
|
||||
{
|
||||
delete ui;
|
||||
}
|
||||
|
||||
void ConfigEditor::on_filter_textChanged(const QString &text)
|
||||
{
|
||||
RDTreeViewExpansionState state;
|
||||
ui->settings->saveExpansion(state, 0);
|
||||
m_FilterModel->setFilter(text);
|
||||
ui->settings->applyExpansion(state, 0);
|
||||
}
|
||||
|
||||
void ConfigEditor::keyPressEvent(QKeyEvent *e)
|
||||
{
|
||||
if(e->key() == Qt::Key_Enter || e->key() == Qt::Key_Return)
|
||||
return;
|
||||
QDialog::keyPressEvent(e);
|
||||
}
|
||||
@@ -0,0 +1,99 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2020 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 <QDialog>
|
||||
#include <QString>
|
||||
#include <QStyledItemDelegate>
|
||||
#include <QVector>
|
||||
|
||||
struct SDObject;
|
||||
|
||||
namespace Ui
|
||||
{
|
||||
class ConfigEditor;
|
||||
}
|
||||
|
||||
class ConfigEditor;
|
||||
class SettingModel;
|
||||
class SettingFilterModel;
|
||||
class RDTreeView;
|
||||
|
||||
class SettingDelegate : public QStyledItemDelegate
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
ConfigEditor *m_Editor;
|
||||
RDTreeView *m_View;
|
||||
|
||||
public:
|
||||
explicit SettingDelegate(ConfigEditor *editor, RDTreeView *parent);
|
||||
~SettingDelegate();
|
||||
void paint(QPainter *painter, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
|
||||
QSize sizeHint(const QStyleOptionViewItem &option, const QModelIndex &index) const override;
|
||||
|
||||
bool editorEvent(QEvent *event, QAbstractItemModel *model, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) override;
|
||||
|
||||
QWidget *createEditor(QWidget *parent, const QStyleOptionViewItem &option,
|
||||
const QModelIndex &index) const override;
|
||||
|
||||
void setEditorData(QWidget *editor, const QModelIndex &index) const override;
|
||||
|
||||
void setModelData(QWidget *editor, QAbstractItemModel *model,
|
||||
const QModelIndex &index) const override;
|
||||
|
||||
public slots:
|
||||
void editorKeyPress(QKeyEvent *ev);
|
||||
};
|
||||
|
||||
class ConfigEditor : public QDialog
|
||||
{
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ConfigEditor(QWidget *parent = 0);
|
||||
~ConfigEditor();
|
||||
|
||||
private slots:
|
||||
// automatic slots
|
||||
void on_filter_textChanged(const QString &text);
|
||||
|
||||
private:
|
||||
void keyPressEvent(QKeyEvent *e) override;
|
||||
|
||||
SettingModel *m_SettingModel = NULL;
|
||||
SettingFilterModel *m_FilterModel = NULL;
|
||||
|
||||
SDObject *m_Config = NULL;
|
||||
|
||||
friend class SettingModel;
|
||||
friend class SettingFilterModel;
|
||||
friend class SettingDelegate;
|
||||
|
||||
Ui::ConfigEditor *ui;
|
||||
};
|
||||
@@ -0,0 +1,136 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>ConfigEditor</class>
|
||||
<widget class="QDialog" name="ConfigEditor">
|
||||
<property name="windowModality">
|
||||
<enum>Qt::ApplicationModal</enum>
|
||||
</property>
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>800</width>
|
||||
<height>600</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Advanced Config Editor</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout">
|
||||
<item>
|
||||
<widget class="QLabel" name="warning">
|
||||
<property name="palette">
|
||||
<palette>
|
||||
<active>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>255</red>
|
||||
<green>0</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</active>
|
||||
<inactive>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>255</red>
|
||||
<green>0</green>
|
||||
<blue>0</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</inactive>
|
||||
<disabled>
|
||||
<colorrole role="WindowText">
|
||||
<brush brushstyle="SolidPattern">
|
||||
<color alpha="255">
|
||||
<red>106</red>
|
||||
<green>104</green>
|
||||
<blue>100</blue>
|
||||
</color>
|
||||
</brush>
|
||||
</colorrole>
|
||||
</disabled>
|
||||
</palette>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<pointsize>14</pointsize>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Editing any of these settings could cause crashes or unpredictable behaviour. Be sure you know what you are doing before editing any of them!</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLineEdit" name="filter">
|
||||
<property name="placeholderText">
|
||||
<string>Filter the settings</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="RDTreeView" name="settings"/>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QDialogButtonBox" name="buttons">
|
||||
<property name="standardButtons">
|
||||
<set>QDialogButtonBox::Close</set>
|
||||
</property>
|
||||
<property name="centerButtons">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<customwidgets>
|
||||
<customwidget>
|
||||
<class>RDTreeView</class>
|
||||
<extends>QTreeView</extends>
|
||||
<header>Widgets/Extended/RDTreeView.h</header>
|
||||
</customwidget>
|
||||
</customwidgets>
|
||||
<resources/>
|
||||
<connections>
|
||||
<connection>
|
||||
<sender>buttons</sender>
|
||||
<signal>accepted()</signal>
|
||||
<receiver>ConfigEditor</receiver>
|
||||
<slot>accept()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>225</x>
|
||||
<y>379</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>225</x>
|
||||
<y>200</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
<connection>
|
||||
<sender>buttons</sender>
|
||||
<signal>rejected()</signal>
|
||||
<receiver>ConfigEditor</receiver>
|
||||
<slot>reject()</slot>
|
||||
<hints>
|
||||
<hint type="sourcelabel">
|
||||
<x>225</x>
|
||||
<y>379</y>
|
||||
</hint>
|
||||
<hint type="destinationlabel">
|
||||
<x>225</x>
|
||||
<y>200</y>
|
||||
</hint>
|
||||
</hints>
|
||||
</connection>
|
||||
</connections>
|
||||
</ui>
|
||||
@@ -34,6 +34,7 @@
|
||||
#include "Widgets/OrderedListEditor.h"
|
||||
#include "Widgets/ReplayOptionsSelector.h"
|
||||
#include "CaptureDialog.h"
|
||||
#include "ConfigEditor.h"
|
||||
#include "ui_SettingsDialog.h"
|
||||
|
||||
SettingsDialog::SettingsDialog(ICaptureContext &ctx, QWidget *parent)
|
||||
@@ -121,17 +122,19 @@ SettingsDialog::SettingsDialog(ICaptureContext &ctx, QWidget *parent)
|
||||
ui->deleteShaderTool->setEnabled(false);
|
||||
ui->editShaderTool->setEnabled(false);
|
||||
|
||||
ui->ExternalTool_RGPIntegration->setChecked(m_Ctx.Config().ExternalTool_RGPIntegration);
|
||||
ui->ExternalTool_RGPIntegration->setChecked(RENDERDOC_GetConfigSetting("AMD.RGP.Enable")->AsBool());
|
||||
ui->ExternalTool_RadeonGPUProfiler->setText(m_Ctx.Config().ExternalTool_RadeonGPUProfiler);
|
||||
|
||||
ui->Android_SDKPath->setText(m_Ctx.Config().Android_SDKPath);
|
||||
ui->Android_JDKPath->setText(m_Ctx.Config().Android_JDKPath);
|
||||
ui->Android_MaxConnectTimeout->setValue(m_Ctx.Config().Android_MaxConnectTimeout);
|
||||
ui->Android_SDKPath->setText(RENDERDOC_GetConfigSetting("Android.SDKDirPath")->AsString());
|
||||
ui->Android_JDKPath->setText(RENDERDOC_GetConfigSetting("Android.JDKDirPath")->AsString());
|
||||
ui->Android_MaxConnectTimeout->setValue(
|
||||
RENDERDOC_GetConfigSetting("Android.MaxConnectTimeout")->AsUInt32());
|
||||
|
||||
ui->TextureViewer_ResetRange->setChecked(m_Ctx.Config().TextureViewer_ResetRange);
|
||||
ui->TextureViewer_PerTexSettings->setChecked(m_Ctx.Config().TextureViewer_PerTexSettings);
|
||||
ui->TextureViewer_PerTexYFlip->setChecked(m_Ctx.Config().TextureViewer_PerTexYFlip);
|
||||
ui->ShaderViewer_FriendlyNaming->setChecked(m_Ctx.Config().ShaderViewer_FriendlyNaming);
|
||||
ui->ShaderViewer_FriendlyNaming->setChecked(
|
||||
RENDERDOC_GetConfigSetting("DXBC.Disassembly.FriendlyNaming")->AsBool());
|
||||
ui->CheckUpdate_AllowChecks->setChecked(m_Ctx.Config().CheckUpdate_AllowChecks);
|
||||
ui->Font_PreferMonospaced->setChecked(m_Ctx.Config().Font_PreferMonospaced);
|
||||
|
||||
@@ -411,6 +414,15 @@ void SettingsDialog::on_analyticsDescribeLabel_linkActivated(const QString &link
|
||||
}
|
||||
|
||||
// core
|
||||
void SettingsDialog::on_configEditor_clicked()
|
||||
{
|
||||
ConfigEditor editor;
|
||||
|
||||
RDDialog::show(&editor);
|
||||
|
||||
RENDERDOC_SaveConfigSettings();
|
||||
}
|
||||
|
||||
void SettingsDialog::on_chooseSearchPaths_clicked()
|
||||
{
|
||||
QDialog listEditor;
|
||||
@@ -431,22 +443,38 @@ void SettingsDialog::on_chooseSearchPaths_clicked()
|
||||
|
||||
listEditor.setLayout(&layout);
|
||||
|
||||
QString setting = m_Ctx.Config().GetConfigSetting("shader.debug.searchPaths");
|
||||
const SDObject *getPaths = RENDERDOC_GetConfigSetting("DXBC.Debug.SearchDirPaths");
|
||||
|
||||
list.setItems(setting.split(QLatin1Char(';'), QString::SkipEmptyParts));
|
||||
QStringList items;
|
||||
|
||||
for(SDObject *c : getPaths->data.children)
|
||||
items << c->data.str;
|
||||
|
||||
list.setItems(items);
|
||||
|
||||
int res = RDDialog::show(&listEditor);
|
||||
|
||||
if(res)
|
||||
m_Ctx.Config().SetConfigSetting(lit("shader.debug.searchPaths"),
|
||||
list.getItems().join(QLatin1Char(';')));
|
||||
{
|
||||
items = list.getItems();
|
||||
|
||||
SDObject *setPaths = RENDERDOC_SetConfigSetting("DXBC.Debug.SearchDirPaths");
|
||||
|
||||
setPaths->DeleteChildren();
|
||||
setPaths->data.children.resize(items.size());
|
||||
|
||||
for(int i = 0; i < items.size(); i++)
|
||||
setPaths->data.children[i] = makeSDString("$el", items[i]);
|
||||
|
||||
RENDERDOC_SaveConfigSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDialog::on_ExternalTool_RGPIntegration_toggled(bool checked)
|
||||
{
|
||||
m_Ctx.Config().ExternalTool_RGPIntegration = checked;
|
||||
RENDERDOC_SetConfigSetting("AMD.RGP.Enable")->data.basic.b = checked;
|
||||
|
||||
m_Ctx.Config().Save();
|
||||
RENDERDOC_SaveConfigSettings();
|
||||
}
|
||||
|
||||
void SettingsDialog::on_ExternalTool_RadeonGPUProfiler_textEdited(const QString &rgp)
|
||||
@@ -499,9 +527,9 @@ void SettingsDialog::on_TextureViewer_ResetRange_toggled(bool checked)
|
||||
// shader viewer
|
||||
void SettingsDialog::on_ShaderViewer_FriendlyNaming_toggled(bool checked)
|
||||
{
|
||||
m_Ctx.Config().ShaderViewer_FriendlyNaming = ui->ShaderViewer_FriendlyNaming->isChecked();
|
||||
RENDERDOC_SetConfigSetting("DXBC.Disassembly.FriendlyNaming")->data.basic.b = checked;
|
||||
|
||||
m_Ctx.Config().Save();
|
||||
RENDERDOC_SaveConfigSettings();
|
||||
}
|
||||
|
||||
void SettingsDialog::addProcessor(const ShaderProcessingTool &tool)
|
||||
@@ -926,55 +954,60 @@ void SettingsDialog::on_browseTempCaptureDirectory_clicked()
|
||||
|
||||
void SettingsDialog::on_browseAndroidSDKPath_clicked()
|
||||
{
|
||||
QString adb = RDDialog::getExistingDirectory(
|
||||
QString sdk = RDDialog::getExistingDirectory(
|
||||
this, tr("Locate SDK root folder (containing build-tools, platform-tools)"),
|
||||
QFileInfo(m_Ctx.Config().Android_SDKPath).absoluteDir().path());
|
||||
QFileInfo(RENDERDOC_GetConfigSetting("Android.SDKDirPath")->AsString()).absoluteDir().path());
|
||||
|
||||
if(!adb.isEmpty())
|
||||
if(!sdk.isEmpty())
|
||||
{
|
||||
ui->Android_SDKPath->setText(adb);
|
||||
m_Ctx.Config().Android_SDKPath = adb;
|
||||
}
|
||||
ui->Android_SDKPath->setText(sdk);
|
||||
RENDERDOC_SetConfigSetting("Android.SDKDirPath")->data.str = sdk;
|
||||
|
||||
m_Ctx.Config().Save();
|
||||
RENDERDOC_SaveConfigSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDialog::on_Android_SDKPath_textEdited(const QString &adb)
|
||||
void SettingsDialog::on_Android_SDKPath_textEdited(const QString &sdk)
|
||||
{
|
||||
if(QFileInfo::exists(adb) || adb.isEmpty())
|
||||
m_Ctx.Config().Android_SDKPath = adb;
|
||||
if(QFileInfo::exists(sdk) || sdk.isEmpty())
|
||||
{
|
||||
RENDERDOC_SetConfigSetting("Android.SDKDirPath")->data.str = sdk;
|
||||
|
||||
m_Ctx.Config().Save();
|
||||
RENDERDOC_SaveConfigSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDialog::on_browseJDKPath_clicked()
|
||||
{
|
||||
QString adb =
|
||||
RDDialog::getExistingDirectory(this, tr("Locate JDK root folder (containing bin, jre, lib)"),
|
||||
QFileInfo(m_Ctx.Config().Android_JDKPath).absoluteDir().path());
|
||||
QString jdk = RDDialog::getExistingDirectory(
|
||||
this, tr("Locate JDK root folder (containing bin, jre, lib)"),
|
||||
QFileInfo(RENDERDOC_GetConfigSetting("Android.JDKDirPath")->AsString()).absoluteDir().path());
|
||||
|
||||
if(!adb.isEmpty())
|
||||
if(!jdk.isEmpty())
|
||||
{
|
||||
ui->Android_JDKPath->setText(adb);
|
||||
m_Ctx.Config().Android_JDKPath = adb;
|
||||
}
|
||||
ui->Android_JDKPath->setText(jdk);
|
||||
RENDERDOC_SetConfigSetting("Android.JDKDirPath")->data.str = jdk;
|
||||
|
||||
m_Ctx.Config().Save();
|
||||
RENDERDOC_SaveConfigSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDialog::on_Android_JDKPath_textEdited(const QString &adb)
|
||||
void SettingsDialog::on_Android_JDKPath_textEdited(const QString &jdk)
|
||||
{
|
||||
if(QFileInfo::exists(adb) || adb.isEmpty())
|
||||
m_Ctx.Config().Android_JDKPath = adb;
|
||||
if(QFileInfo::exists(jdk) || jdk.isEmpty())
|
||||
{
|
||||
RENDERDOC_SetConfigSetting("Android.JDKDirPath")->data.str = jdk;
|
||||
|
||||
m_Ctx.Config().Save();
|
||||
RENDERDOC_SaveConfigSettings();
|
||||
}
|
||||
}
|
||||
|
||||
void SettingsDialog::on_Android_MaxConnectTimeout_valueChanged(double timeout)
|
||||
{
|
||||
m_Ctx.Config().Android_MaxConnectTimeout = ui->Android_MaxConnectTimeout->value();
|
||||
RENDERDOC_SetConfigSetting("Android.MaxConnectTimeout")->data.basic.u =
|
||||
(uint32_t)ui->Android_MaxConnectTimeout->value();
|
||||
|
||||
m_Ctx.Config().Save();
|
||||
RENDERDOC_SaveConfigSettings();
|
||||
}
|
||||
|
||||
void SettingsDialog::on_UIStyle_currentIndexChanged(int index)
|
||||
|
||||
@@ -71,6 +71,7 @@ private slots:
|
||||
void on_analyticsOptOut_toggled(bool checked);
|
||||
|
||||
// core
|
||||
void on_configEditor_clicked();
|
||||
void on_chooseSearchPaths_clicked();
|
||||
void on_ExternalTool_RGPIntegration_toggled(bool checked);
|
||||
void on_ExternalTool_RadeonGPUProfiler_textEdited(const QString &rgp);
|
||||
@@ -108,8 +109,8 @@ private slots:
|
||||
void on_browseAndroidSDKPath_clicked();
|
||||
void on_browseJDKPath_clicked();
|
||||
void on_Android_MaxConnectTimeout_valueChanged(double timeout);
|
||||
void on_Android_SDKPath_textEdited(const QString &path);
|
||||
void on_Android_JDKPath_textEdited(const QString &path);
|
||||
void on_Android_SDKPath_textEdited(const QString &sdk);
|
||||
void on_Android_JDKPath_textEdited(const QString &jdk);
|
||||
|
||||
// manual slots
|
||||
void formatter_valueChanged(int value);
|
||||
|
||||
@@ -482,27 +482,7 @@ e.g. 1000 * 10 = 1e4</string>
|
||||
<string>Core</string>
|
||||
</property>
|
||||
<layout class="QGridLayout" name="gridLayout_2">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Shader debug search paths</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="chooseSearchPaths">
|
||||
<property name="text">
|
||||
<string>Choose paths</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0" colspan="2">
|
||||
<item row="3" column="0" colspan="2">
|
||||
<widget class="QLabel" name="label_17">
|
||||
<property name="toolTip">
|
||||
<string>Locates the RadeonGPUProfiler.exe which will be used to interop with when generating and opening RGP profiles.</string>
|
||||
@@ -512,24 +492,14 @@ e.g. 1000 * 10 = 1e4</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="0">
|
||||
<item row="4" column="0">
|
||||
<widget class="QLineEdit" name="ExternalTool_RadeonGPUProfiler">
|
||||
<property name="toolTip">
|
||||
<string>Locates the RadeonGPUProfiler.exe which will be used to interop with when generating and opening RGP profiles.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="3" column="1">
|
||||
<widget class="QPushButton" name="browseRGPPath">
|
||||
<property name="toolTip">
|
||||
<string>Locates the RadeonGPUProfiler.exe which will be used to interop with when generating and opening RGP profiles.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="4" column="0" colspan="2">
|
||||
<item row="5" column="0" colspan="2">
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
@@ -542,7 +512,49 @@ e.g. 1000 * 10 = 1e4</string>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item row="4" column="1">
|
||||
<widget class="QPushButton" name="browseRGPPath">
|
||||
<property name="toolTip">
|
||||
<string>Locates the RadeonGPUProfiler.exe which will be used to interop with when generating and opening RGP profiles.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Browse</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="toolTip">
|
||||
<string>RenderDoc can optionally have integration with AMD's Radeon GPU Profiler, to allow capturing RGP from RenderDoc and allowing interop between the two.
|
||||
|
||||
After interop is enabled you will need to reload any capture.</string>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Enable Radeon GPU Profiler integration (requires capture reload)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_11">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Shader debug search paths</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QPushButton" name="chooseSearchPaths">
|
||||
<property name="text">
|
||||
<string>Choose paths</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QCheckBox" name="ExternalTool_RGPIntegration">
|
||||
<property name="toolTip">
|
||||
<string>RenderDoc can optionally have integration with AMD's Radeon GPU Profiler, to allow capturing RGP from RenderDoc and allowing interop between the two.
|
||||
@@ -554,15 +566,17 @@ After interop is enabled you will need to reload any capture.</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="label_18">
|
||||
<property name="toolTip">
|
||||
<string>RenderDoc can optionally have integration with AMD's Radeon GPU Profiler, to allow capturing RGP from RenderDoc and allowing interop between the two.
|
||||
|
||||
After interop is enabled you will need to reload any capture.</string>
|
||||
</property>
|
||||
<item row="0" column="1">
|
||||
<widget class="QPushButton" name="configEditor">
|
||||
<property name="text">
|
||||
<string>Enable Radeon GPU Profiler integration (requires capture reload)</string>
|
||||
<string>Config Editor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_28">
|
||||
<property name="text">
|
||||
<string>Open Advanced Config Editor</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -237,6 +237,7 @@ SOURCES += Code/qrenderdoc.cpp \
|
||||
Widgets/FindReplace.cpp \
|
||||
Widgets/Extended/RDSplitter.cpp \
|
||||
Windows/Dialogs/TipsDialog.cpp \
|
||||
Windows/Dialogs/ConfigEditor.cpp \
|
||||
Windows/PythonShell.cpp \
|
||||
Windows/Dialogs/PerformanceCounterSelection.cpp \
|
||||
Windows/PerformanceCounterViewer.cpp \
|
||||
@@ -315,6 +316,7 @@ HEADERS += Code/CaptureContext.h \
|
||||
Widgets/FindReplace.h \
|
||||
Widgets/Extended/RDSplitter.h \
|
||||
Windows/Dialogs/TipsDialog.h \
|
||||
Windows/Dialogs/ConfigEditor.h \
|
||||
Windows/PythonShell.h \
|
||||
Windows/Dialogs/PerformanceCounterSelection.h \
|
||||
Windows/PerformanceCounterViewer.h \
|
||||
@@ -356,6 +358,7 @@ FORMS += Windows/Dialogs/AboutDialog.ui \
|
||||
Windows/Dialogs/EnvironmentEditor.ui \
|
||||
Widgets/FindReplace.ui \
|
||||
Windows/Dialogs/TipsDialog.ui \
|
||||
Windows/Dialogs/ConfigEditor.ui \
|
||||
Windows/PythonShell.ui \
|
||||
Windows/Dialogs/PerformanceCounterSelection.ui \
|
||||
Windows/PerformanceCounterViewer.ui \
|
||||
|
||||
@@ -663,6 +663,7 @@
|
||||
<ClCompile Include="$(IntDir)generated\moc_TextureSaveDialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)generated\moc_TextureViewer.cpp" />
|
||||
<ClCompile Include="$(IntDir)generated\moc_TipsDialog.cpp" />
|
||||
<ClCompile Include="$(IntDir)generated\moc_ConfigEditor.cpp" />
|
||||
<ClCompile Include="$(IntDir)generated\moc_ThumbnailStrip.cpp" />
|
||||
<ClCompile Include="$(IntDir)generated\moc_ReplayOptionsSelector.cpp" />
|
||||
<ClCompile Include="$(IntDir)generated\moc_ToolWindowManager.cpp" />
|
||||
@@ -738,6 +739,7 @@
|
||||
<ClCompile Include="Windows\Dialogs\SuggestRemoteDialog.cpp" />
|
||||
<ClCompile Include="Windows\Dialogs\TextureSaveDialog.cpp" />
|
||||
<ClCompile Include="Windows\Dialogs\TipsDialog.cpp" />
|
||||
<ClCompile Include="Windows\Dialogs\ConfigEditor.cpp" />
|
||||
<ClCompile Include="Windows\Dialogs\VirtualFileDialog.cpp" />
|
||||
<ClCompile Include="Windows\EventBrowser.cpp" />
|
||||
<ClCompile Include="3rdparty\flowlayout\FlowLayout.cpp">
|
||||
@@ -957,6 +959,7 @@
|
||||
<ClInclude Include="$(IntDir)generated\ui_SuggestRemoteDialog.h" />
|
||||
<ClInclude Include="$(IntDir)generated\ui_TextureSaveDialog.h" />
|
||||
<ClInclude Include="$(IntDir)generated\ui_TipsDialog.h" />
|
||||
<ClInclude Include="$(IntDir)generated\ui_ConfigEditor.h" />
|
||||
<ClInclude Include="$(IntDir)generated\ui_TextureViewer.h" />
|
||||
<ClInclude Include="$(IntDir)generated\ui_ThumbnailStrip.h" />
|
||||
<ClInclude Include="$(IntDir)generated\ui_ReplayOptionsSelector.h" />
|
||||
@@ -1262,6 +1265,12 @@
|
||||
<Message>MOC %(Filename).h</Message>
|
||||
<Outputs>$(IntDir)generated\moc_%(Filename).cpp</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Windows\Dialogs\ConfigEditor.h">
|
||||
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Command>"$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe" -DUNICODE -DWIN32 -DWIN64 -D_WIN32 -D_WIN64 -DRENDERDOC_PLATFORM_WIN32 -DSCINTILLA_QT=1 -DSCI_LEXER=1 -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -D_MSC_VER=1900 -I"$(ProjectDir)." -I"$(SolutionDir)\renderdoc\api\replay" -I"$(ProjectDir)3rdparty\qt\$(Platform)\mkspecs/win32-msvc2015" -I"$(ProjectDir)3rdparty\qt\include" -I"$(ProjectDir)3rdparty\qt\include\QtWidgets" -I"$(ProjectDir)3rdparty\qt\include\QtGui" -I"$(ProjectDir)3rdparty\qt\include\QtCore" "%(Fullpath)" -o "$(IntDir)generated\moc_%(Filename).cpp"</Command>
|
||||
<Message>MOC %(Filename).h</Message>
|
||||
<Outputs>$(IntDir)generated\moc_%(Filename).cpp</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Windows\Dialogs\VirtualFileDialog.h">
|
||||
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Command>"$(ProjectDir)3rdparty\qt\$(Platform)\bin\moc.exe" -DUNICODE -DWIN32 -DWIN64 -D_WIN32 -D_WIN64 -DRENDERDOC_PLATFORM_WIN32 -DSCINTILLA_QT=1 -DSCI_LEXER=1 -DQT_NO_DEBUG -DQT_WIDGETS_LIB -DQT_GUI_LIB -DQT_CORE_LIB -D_MSC_VER=1900 -I"$(ProjectDir)." -I"$(SolutionDir)\renderdoc\api\replay" -I"$(ProjectDir)3rdparty\qt\$(Platform)\mkspecs/win32-msvc2015" -I"$(ProjectDir)3rdparty\qt\include" -I"$(ProjectDir)3rdparty\qt\include\QtWidgets" -I"$(ProjectDir)3rdparty\qt\include\QtGui" -I"$(ProjectDir)3rdparty\qt\include\QtCore" "%(Fullpath)" -o "$(IntDir)generated\moc_%(Filename).cpp"</Command>
|
||||
@@ -1540,6 +1549,12 @@
|
||||
<Message>UIC %(Filename).ui</Message>
|
||||
<Outputs>$(IntDir)generated\ui_%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Windows\Dialogs\ConfigEditor.ui">
|
||||
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Command>"$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe" "%(Fullpath)" -o "$(IntDir)generated\ui_%(Filename).h"</Command>
|
||||
<Message>UIC %(Filename).ui</Message>
|
||||
<Outputs>$(IntDir)generated\ui_%(Filename).h</Outputs>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Windows\Dialogs\VirtualFileDialog.ui">
|
||||
<AdditionalInputs>%(Fullpath);$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe;%(AdditionalInputs)</AdditionalInputs>
|
||||
<Command>"$(ProjectDir)3rdparty\qt\$(Platform)\bin\uic.exe" "%(Fullpath)" -o "$(IntDir)generated\ui_%(Filename).h"</Command>
|
||||
|
||||
@@ -729,6 +729,12 @@
|
||||
<ClCompile Include="Code\BufferFormatter.cpp">
|
||||
<Filter>Code</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="$(IntDir)generated\moc_ConfigEditor.cpp">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="Windows\Dialogs\ConfigEditor.cpp">
|
||||
<Filter>Windows\Dialogs</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClInclude Include="3rdparty\flowlayout\FlowLayout.h">
|
||||
@@ -1088,6 +1094,9 @@
|
||||
<ClInclude Include="$(IntDir)generated\ui_ReplayOptionsSelector.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="$(IntDir)generated\ui_ConfigEditor.h">
|
||||
<Filter>Generated Files</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="Code\pyrenderdoc\pyconversion.h">
|
||||
@@ -1478,7 +1487,15 @@
|
||||
<CustomBuild Include="Widgets\ReplayOptionsSelector.h">
|
||||
<Filter>Widgets</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Widgets\ReplayOptionsSelector.ui" />
|
||||
<CustomBuild Include="Widgets\ReplayOptionsSelector.ui">
|
||||
<Filter>Widgets</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Windows\Dialogs\ConfigEditor.h">
|
||||
<Filter>Windows\Dialogs</Filter>
|
||||
</CustomBuild>
|
||||
<CustomBuild Include="Windows\Dialogs\ConfigEditor.ui">
|
||||
<Filter>Windows\Dialogs</Filter>
|
||||
</CustomBuild>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<Image Include="Resources\action.png">
|
||||
|
||||
@@ -132,6 +132,8 @@ set(sources
|
||||
core/target_control.cpp
|
||||
core/remote_server.cpp
|
||||
core/remote_server.h
|
||||
core/settings.cpp
|
||||
core/settings.h
|
||||
core/replay_proxy.cpp
|
||||
core/replay_proxy.h
|
||||
core/intervals.h
|
||||
|
||||
@@ -30,10 +30,15 @@
|
||||
#include "common/threading.h"
|
||||
#include "core/core.h"
|
||||
#include "core/remote_server.h"
|
||||
#include "core/settings.h"
|
||||
#include "replay/replay_driver.h"
|
||||
#include "strings/string_utils.h"
|
||||
#include "android_utils.h"
|
||||
|
||||
RDOC_CONFIG(uint32_t, Android_MaxConnectTimeout, 30,
|
||||
"Maximum time in seconds to try connecting to the target app before giving up. "
|
||||
"Useful primarily for apps that take a very long time to start up.");
|
||||
|
||||
namespace Android
|
||||
{
|
||||
void adbForwardPorts(uint16_t portbase, const rdcstr &deviceID, uint16_t jdwpPort, int pid,
|
||||
@@ -1166,10 +1171,7 @@ ExecuteResult AndroidRemoteServer::ExecuteAndInject(const char *a, const char *w
|
||||
|
||||
ret.status = ReplayStatus::InjectionFailed;
|
||||
|
||||
uint32_t elapsed = 0,
|
||||
timeout =
|
||||
1000 *
|
||||
RDCMAX(5, atoi(RenderDoc::Inst().GetConfigSetting("MaxConnectTimeout").c_str()));
|
||||
uint32_t elapsed = 0, timeout = 1000 * RDCMAX(5U, Android_MaxConnectTimeout);
|
||||
while(elapsed < timeout)
|
||||
{
|
||||
// Check if the target app has started yet and we can connect to it.
|
||||
|
||||
@@ -24,9 +24,18 @@
|
||||
|
||||
#include "common/formatting.h"
|
||||
#include "core/core.h"
|
||||
#include "core/settings.h"
|
||||
#include "strings/string_utils.h"
|
||||
#include "android_utils.h"
|
||||
|
||||
RDOC_CONFIG(rdcstr, Android_SDKDirPath, "",
|
||||
"The location of the root of the Android SDK. This path "
|
||||
"should contain folders such as build-tools and platform-tools.");
|
||||
|
||||
RDOC_CONFIG(rdcstr, Android_JDKDirPath, "",
|
||||
"The location of the root of the Java JDK. This path "
|
||||
"should contain folders such as bin and lib.");
|
||||
|
||||
namespace Android
|
||||
{
|
||||
static bool adbKillServer = false;
|
||||
@@ -178,8 +187,8 @@ rdcstr getToolPath(ToolDir subdir, const rdcstr &toolname, bool checkExist)
|
||||
// its client-server setup, so if we run our bundled adb that might be newer than the user's, they
|
||||
// will then get fighting back and forth when trying to run their own.
|
||||
|
||||
rdcstr sdk = RenderDoc::Inst().GetConfigSetting("androidSDKPath");
|
||||
rdcstr jdk = RenderDoc::Inst().GetConfigSetting("androidJDKPath");
|
||||
rdcstr sdk = Android_SDKDirPath;
|
||||
rdcstr jdk = Android_JDKDirPath;
|
||||
|
||||
ToolPathCache &cache = getCache();
|
||||
|
||||
|
||||
@@ -1987,12 +1987,32 @@ DOCUMENT(R"(Returns the current process's memory usage in bytes
|
||||
)");
|
||||
extern "C" RENDERDOC_API uint64_t RENDERDOC_CC RENDERDOC_GetCurrentProcessMemoryUsage();
|
||||
|
||||
DOCUMENT("Internal function for retrieving a config setting.");
|
||||
extern "C" RENDERDOC_API const char *RENDERDOC_CC RENDERDOC_GetConfigSetting(const char *name);
|
||||
DOCUMENT(R"(Return a read-only handle to the :class:`SDObject` corresponding to a given setting's
|
||||
value object.
|
||||
|
||||
DOCUMENT("Internal function for setting a config setting.");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetConfigSetting(const char *name,
|
||||
const char *value);
|
||||
If an empty string is passed, the root object is returned containing all settings and setting
|
||||
categories. Categories contain other categories and settings, settings contain children that include
|
||||
the setting's value, description, etc.
|
||||
|
||||
If no such setting exists, `None` is returned.
|
||||
|
||||
:return: The specified setting.
|
||||
:rtype: ``SDObject``
|
||||
)");
|
||||
extern "C" RENDERDOC_API const SDObject *RENDERDOC_CC RENDERDOC_GetConfigSetting(const char *name);
|
||||
|
||||
DOCUMENT(R"(Return a mutable handle to the :class:`SDObject` corresponding to a given setting's
|
||||
value object.
|
||||
|
||||
If no such setting exists, `None` is returned.
|
||||
|
||||
:return: The specified setting.
|
||||
:rtype: ``SDObject``
|
||||
)");
|
||||
extern "C" RENDERDOC_API SDObject *RENDERDOC_CC RENDERDOC_SetConfigSetting(const char *name);
|
||||
|
||||
DOCUMENT("Internal function for saving config settings.");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SaveConfigSettings();
|
||||
|
||||
DOCUMENT("Internal function for setting UI theme colors.");
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetColors(FloatVector darkChecker,
|
||||
|
||||
@@ -22,6 +22,27 @@
|
||||
* THE SOFTWARE.
|
||||
******************************************************************************/
|
||||
|
||||
template <>
|
||||
rdcstr DoStringise(const SDBasic &el)
|
||||
{
|
||||
BEGIN_ENUM_STRINGISE(SDBasic);
|
||||
{
|
||||
STRINGISE_ENUM_CLASS(Chunk);
|
||||
STRINGISE_ENUM_CLASS(Struct);
|
||||
STRINGISE_ENUM_CLASS(Array);
|
||||
STRINGISE_ENUM_CLASS(Null);
|
||||
STRINGISE_ENUM_CLASS(Buffer);
|
||||
STRINGISE_ENUM_CLASS(String);
|
||||
STRINGISE_ENUM_CLASS(Enum);
|
||||
STRINGISE_ENUM_CLASS(UnsignedInteger);
|
||||
STRINGISE_ENUM_CLASS(SignedInteger);
|
||||
STRINGISE_ENUM_CLASS(Float);
|
||||
STRINGISE_ENUM_CLASS(Boolean);
|
||||
STRINGISE_ENUM_CLASS(Character);
|
||||
}
|
||||
END_ENUM_STRINGISE();
|
||||
}
|
||||
|
||||
template <>
|
||||
rdcstr DoStringise(const ReplayStatus &el)
|
||||
{
|
||||
|
||||
@@ -404,16 +404,9 @@ struct SDObject
|
||||
data.basic.u = 0;
|
||||
}
|
||||
|
||||
~SDObject()
|
||||
{
|
||||
for(size_t i = 0; i < data.children.size(); i++)
|
||||
delete data.children[i];
|
||||
|
||||
data.children.clear();
|
||||
}
|
||||
|
||||
~SDObject() { DeleteChildren(); }
|
||||
DOCUMENT("Create a deep copy of this object.");
|
||||
SDObject *Duplicate()
|
||||
SDObject *Duplicate() const
|
||||
{
|
||||
SDObject *ret = new SDObject();
|
||||
ret->name = name;
|
||||
@@ -437,6 +430,32 @@ struct SDObject
|
||||
DOCUMENT("The :class:`SDObjectData` with the contents of this object.");
|
||||
SDObjectData data;
|
||||
|
||||
DOCUMENT("Checks if the given object has the same value as this one.");
|
||||
bool HasEqualValue(const SDObject *o) const
|
||||
{
|
||||
bool ret = true;
|
||||
|
||||
if(data.str != o->data.str)
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
else if(data.basic.u != o->data.basic.u)
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
else if(data.children.size() != o->data.children.size())
|
||||
{
|
||||
ret = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
for(size_t c = 0; c < o->data.children.size(); c++)
|
||||
ret &= data.children[c]->HasEqualValue(o->data.children[c]);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
DOCUMENT("Add a new child object by duplicating it.");
|
||||
inline void AddChild(SDObject *child) { data.children.push_back(child->Duplicate()); }
|
||||
DOCUMENT("Find a child object by a given name.");
|
||||
@@ -456,6 +475,15 @@ struct SDObject
|
||||
return NULL;
|
||||
}
|
||||
|
||||
DOCUMENT("Delete all child objects.");
|
||||
inline void DeleteChildren()
|
||||
{
|
||||
for(size_t i = 0; i < data.children.size(); i++)
|
||||
delete data.children[i];
|
||||
|
||||
data.children.clear();
|
||||
}
|
||||
|
||||
DOCUMENT("Get the number of child objects.");
|
||||
inline size_t NumChildren() const { return data.children.size(); }
|
||||
DOCUMENT("Get a ``list`` of :class:`SDObject` children.");
|
||||
@@ -479,7 +507,7 @@ struct SDObject
|
||||
inline double AsDouble() const { return data.basic.d; }
|
||||
inline float AsFloat() const { return (float)data.basic.d; }
|
||||
inline char AsChar() const { return data.basic.c; }
|
||||
inline rdcstr AsString() const { return data.str; }
|
||||
inline const rdcstr &AsString() const { return data.str; }
|
||||
inline uint64_t AsUInt64() const { return (uint64_t)data.basic.u; }
|
||||
inline int64_t AsInt64() const { return (int64_t)data.basic.i; }
|
||||
inline uint32_t AsUInt32() const { return (uint32_t)data.basic.u; }
|
||||
@@ -554,6 +582,7 @@ struct SDObject
|
||||
return this;
|
||||
}
|
||||
|
||||
void AddAndOwnChild(SDObject *child) { data.children.push_back(child); }
|
||||
#endif
|
||||
|
||||
// these are common to both python and C++
|
||||
@@ -780,11 +809,11 @@ inline SDObject *makeSDBool(const char *name, bool val)
|
||||
}
|
||||
|
||||
DOCUMENT("Make a structured object out of a string");
|
||||
inline SDObject *makeSDString(const char *name, const char *val)
|
||||
inline SDObject *makeSDString(const char *name, const rdcstr &val)
|
||||
{
|
||||
SDObject *ret = new SDObject(name, "string"_lit);
|
||||
ret->type.basetype = SDBasic::String;
|
||||
ret->type.byteSize = strlen(val);
|
||||
ret->type.byteSize = val.size();
|
||||
ret->data.str = val;
|
||||
return ret;
|
||||
}
|
||||
@@ -848,6 +877,7 @@ SDOBJECT_MAKER(uint32_t, makeSDUInt32);
|
||||
SDOBJECT_MAKER(float, makeSDFloat);
|
||||
SDOBJECT_MAKER(bool, makeSDBool);
|
||||
SDOBJECT_MAKER(const char *, makeSDString);
|
||||
SDOBJECT_MAKER(const rdcstr &, makeSDString);
|
||||
SDOBJECT_MAKER(ResourceId, makeSDResourceId);
|
||||
|
||||
#undef SDOBJECT_MAKER
|
||||
@@ -887,7 +917,7 @@ struct SDChunk : public SDObject
|
||||
SDChunkMetaData metadata;
|
||||
|
||||
DOCUMENT("Create a deep copy of this chunk.");
|
||||
SDChunk *Duplicate()
|
||||
SDChunk *Duplicate() const
|
||||
{
|
||||
SDChunk *ret = new SDChunk();
|
||||
ret->name = name;
|
||||
|
||||
@@ -454,6 +454,8 @@ void RenderDoc::Initialise()
|
||||
// information to stdout/stderr and being piped around and processed!
|
||||
if(IsReplayApp())
|
||||
RDCLOGOUTPUT();
|
||||
|
||||
ProcessConfig();
|
||||
}
|
||||
|
||||
RenderDoc::~RenderDoc()
|
||||
@@ -494,6 +496,8 @@ RenderDoc::~RenderDoc()
|
||||
m_RemoteThread = 0;
|
||||
}
|
||||
|
||||
delete m_Config;
|
||||
|
||||
Process::Shutdown();
|
||||
|
||||
Network::Shutdown();
|
||||
|
||||
+13
-4
@@ -39,6 +39,7 @@
|
||||
class Chunk;
|
||||
struct RDCThumb;
|
||||
struct ReplayOptions;
|
||||
struct SDObject;
|
||||
|
||||
// not provided by tinyexr, just do by hand
|
||||
bool is_exr_file(FILE *f);
|
||||
@@ -418,11 +419,15 @@ public:
|
||||
void RegisterShutdownFunction(ShutdownFunction func);
|
||||
void SetReplayApp(bool replay) { m_Replay = replay; }
|
||||
bool IsReplayApp() const { return m_Replay; }
|
||||
const rdcstr &GetConfigSetting(rdcstr name) { return m_ConfigSettings[name]; }
|
||||
void SetConfigSetting(rdcstr name, rdcstr value) { m_ConfigSettings[name] = value; }
|
||||
void BecomeRemoteServer(const char *listenhost, uint16_t port, RENDERDOC_KillCallback killReplay,
|
||||
RENDERDOC_PreviewWindowCallback previewWindow);
|
||||
|
||||
const SDObject *GetConfigSetting(const rdcstr &name);
|
||||
SDObject *SetConfigSetting(const rdcstr &name);
|
||||
void SaveConfigSettings();
|
||||
|
||||
void RegisterSetting(const rdcstr &settingPath, SDObject *setting);
|
||||
|
||||
DriverInformation GetDriverInformation(GraphicsAPI api);
|
||||
|
||||
// can't be disabled, only enabled then latched
|
||||
@@ -621,8 +626,6 @@ private:
|
||||
Threading::CriticalSection m_ChildLock;
|
||||
rdcarray<rdcpair<uint32_t, uint32_t> > m_Children;
|
||||
|
||||
std::map<rdcstr, rdcstr> m_ConfigSettings;
|
||||
|
||||
std::map<RDCDriver, ReplayDriverProvider> m_ReplayDriverProviders;
|
||||
std::map<RDCDriver, RemoteDriverProvider> m_RemoteDriverProviders;
|
||||
|
||||
@@ -698,6 +701,12 @@ private:
|
||||
static void TargetControlClientThread(uint32_t version, Network::Socket *client);
|
||||
|
||||
ICrashHandler *m_ExHandler;
|
||||
|
||||
void ProcessConfig();
|
||||
|
||||
SDObject *FindConfigSetting(const rdcstr &name);
|
||||
|
||||
SDObject *m_Config = NULL;
|
||||
};
|
||||
|
||||
struct DriverRegistration
|
||||
|
||||
@@ -29,6 +29,7 @@
|
||||
#include "api/replay/renderdoc_replay.h"
|
||||
#include "api/replay/version.h"
|
||||
#include "core/core.h"
|
||||
#include "core/settings.h"
|
||||
#include "os/os_specific.h"
|
||||
#include "replay/replay_controller.h"
|
||||
#include "serialise/rdcfile.h"
|
||||
@@ -36,11 +37,12 @@
|
||||
#include "strings/string_utils.h"
|
||||
#include "replay_proxy.h"
|
||||
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
static const uint32_t RemoteServerTimeoutMS = 5000;
|
||||
#endif
|
||||
RDOC_CONFIG(uint32_t, RemoteServer_TimeoutMS, 5000,
|
||||
"Timeout in milliseconds for remote server operations.");
|
||||
|
||||
#define DEBUG_REMOTE_SERVER OPTION_OFF
|
||||
RDOC_DEBUG_CONFIG(bool, RemoteServer_DebugLogging, false,
|
||||
"Where possible (i.e. it is completely unambiguous) replace register names with "
|
||||
"high-level variable names.");
|
||||
|
||||
static const uint32_t RemoteServerProtocolVersion =
|
||||
uint32_t(RENDERDOC_VERSION_MAJOR * 1000) | RENDERDOC_VERSION_MINOR;
|
||||
@@ -215,9 +217,7 @@ static void ActiveRemoteClientThread(ClientThread *threadData,
|
||||
|
||||
Network::Socket *&client = threadData->socket;
|
||||
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
client->SetTimeout(RemoteServerTimeoutMS);
|
||||
#endif
|
||||
client->SetTimeout(RemoteServer_TimeoutMS);
|
||||
|
||||
uint32_t ip = client->GetRemoteIP();
|
||||
|
||||
@@ -1156,9 +1156,7 @@ RENDERDOC_CreateRemoteServerConnection(const char *URL, IRemoteServer **rend)
|
||||
|
||||
uint32_t version = RemoteServerProtocolVersion;
|
||||
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
sock->SetTimeout(RemoteServerTimeoutMS);
|
||||
#endif
|
||||
sock->SetTimeout(RemoteServer_TimeoutMS);
|
||||
|
||||
{
|
||||
WriteSerialiser ser(new StreamWriter(sock, Ownership::Nothing), Ownership::Stream);
|
||||
@@ -1218,22 +1216,25 @@ RemoteServer::RemoteServer(Network::Socket *sock, const rdcstr &deviceID)
|
||||
reader = new ReadSerialiser(new StreamReader(sock, Ownership::Nothing), Ownership::Stream);
|
||||
writer = new WriteSerialiser(new StreamWriter(sock, Ownership::Nothing), Ownership::Stream);
|
||||
|
||||
#if ENABLED(RDOC_DEVEL) && ENABLED(DEBUG_REMOTE_SERVER)
|
||||
reader->ConfigureStructuredExport(&GetRemoteServerChunkName, false);
|
||||
writer->ConfigureStructuredExport(&GetRemoteServerChunkName, false);
|
||||
if(RemoteServer_DebugLogging)
|
||||
{
|
||||
reader->ConfigureStructuredExport(&GetRemoteServerChunkName, false);
|
||||
writer->ConfigureStructuredExport(&GetRemoteServerChunkName, false);
|
||||
|
||||
rdcstr filename = FileIO::GetTempFolderFilename() + "/RenderDoc/RemoteServer.log";
|
||||
rdcstr filename = FileIO::GetTempFolderFilename() + "/RenderDoc/RemoteServer.log";
|
||||
|
||||
// truncate the log
|
||||
debugLog = FileIO::logfile_open(filename.c_str());
|
||||
FileIO::logfile_close(debugLog, filename.c_str());
|
||||
debugLog = FileIO::logfile_open(filename.c_str());
|
||||
// truncate the log
|
||||
debugLog = FileIO::logfile_open(filename.c_str());
|
||||
FileIO::logfile_close(debugLog, filename.c_str());
|
||||
debugLog = FileIO::logfile_open(filename.c_str());
|
||||
|
||||
reader->EnableDumping(debugLog);
|
||||
writer->EnableDumping(debugLog);
|
||||
#else
|
||||
debugLog = NULL;
|
||||
#endif
|
||||
reader->EnableDumping(debugLog);
|
||||
writer->EnableDumping(debugLog);
|
||||
}
|
||||
else
|
||||
{
|
||||
debugLog = NULL;
|
||||
}
|
||||
|
||||
writer->SetStreamingMode(true);
|
||||
reader->SetStreamingMode(true);
|
||||
|
||||
@@ -0,0 +1,595 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 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 "settings.h"
|
||||
#include "api/replay/structured_data.h"
|
||||
#include "common/formatting.h"
|
||||
#include "serialise/streamio.h"
|
||||
#include "core.h"
|
||||
|
||||
#include "3rdparty/pugixml/pugixml.hpp"
|
||||
|
||||
static const rdcliteral debugOnlyString = "DEBUG VARIABLE: Read-only in stable builds."_lit;
|
||||
|
||||
static rdcstr valueString(const SDObject *o)
|
||||
{
|
||||
if(o->type.basetype == SDBasic::String)
|
||||
return o->data.str;
|
||||
|
||||
if(o->type.basetype == SDBasic::UnsignedInteger)
|
||||
return StringFormat::Fmt("%llu", o->data.basic.u);
|
||||
|
||||
if(o->type.basetype == SDBasic::SignedInteger)
|
||||
return StringFormat::Fmt("%lld", o->data.basic.i);
|
||||
|
||||
if(o->type.basetype == SDBasic::Float)
|
||||
return StringFormat::Fmt("%lf", o->data.basic.d);
|
||||
|
||||
if(o->type.basetype == SDBasic::Boolean)
|
||||
return o->data.basic.b ? "True" : "False";
|
||||
|
||||
if(o->type.basetype == SDBasic::Array)
|
||||
return StringFormat::Fmt("[%zu]", o->NumChildren());
|
||||
|
||||
return "{}";
|
||||
}
|
||||
|
||||
struct xml_stream_writer : pugi::xml_writer
|
||||
{
|
||||
StreamWriter &stream;
|
||||
|
||||
xml_stream_writer(StreamWriter &writer) : stream(writer) {}
|
||||
void write(const void *data, size_t size) { stream.Write(data, size); }
|
||||
};
|
||||
|
||||
static SDObject *makeSDObject(const char *name, SDBasic type, pugi::xml_node &value)
|
||||
{
|
||||
switch(type)
|
||||
{
|
||||
case SDBasic::UnsignedInteger: return makeSDObject(name, (uint64_t)value.text().as_ullong());
|
||||
case SDBasic::SignedInteger: return makeSDObject(name, (int64_t)value.text().as_llong());
|
||||
case SDBasic::String: return makeSDObject(name, value.text().as_string());
|
||||
case SDBasic::Float: return makeSDObject(name, value.text().as_float());
|
||||
case SDBasic::Boolean: return makeSDObject(name, value.text().as_bool());
|
||||
case SDBasic::Character: return makeSDObject(name, value.text().as_string()[0]);
|
||||
default: break;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
static void saveSDObject(SDObject &value, pugi::xml_node obj)
|
||||
{
|
||||
switch(value.type.basetype)
|
||||
{
|
||||
case SDBasic::Resource:
|
||||
case SDBasic::Enum:
|
||||
case SDBasic::UnsignedInteger: obj.text() = value.data.basic.u; break;
|
||||
case SDBasic::SignedInteger: obj.text() = value.data.basic.i; break;
|
||||
case SDBasic::String: obj.text() = value.data.str.c_str(); break;
|
||||
case SDBasic::Float: obj.text() = value.data.basic.d; break;
|
||||
case SDBasic::Boolean: obj.text() = value.data.basic.b; break;
|
||||
case SDBasic::Character:
|
||||
{
|
||||
char str[2] = {value.data.basic.c, '\0'};
|
||||
obj.text().set(str);
|
||||
break;
|
||||
}
|
||||
default: RDCERR("Unexpected case");
|
||||
}
|
||||
}
|
||||
|
||||
static void Config2XML(pugi::xml_node &parent, SDObject &child)
|
||||
{
|
||||
pugi::xml_node obj = parent.append_child(child.name.c_str());
|
||||
|
||||
if(child.type.name == "category"_lit)
|
||||
{
|
||||
for(size_t i = 0; i < child.NumChildren(); i++)
|
||||
Config2XML(obj, *child.GetChild(i));
|
||||
}
|
||||
else
|
||||
{
|
||||
SDObject *value = child.FindChild("value");
|
||||
|
||||
parent.insert_child_before(pugi::node_comment, obj)
|
||||
.set_value((" " + child.FindChild("description")->data.str + " ").c_str());
|
||||
|
||||
obj.append_attribute("type") = ToStr(value->type.basetype).c_str();
|
||||
if(value->type.basetype == SDBasic::Array)
|
||||
{
|
||||
if(!value->data.children.empty())
|
||||
obj.append_attribute("elemtype") = ToStr(value->data.children[0]->type.basetype).c_str();
|
||||
else
|
||||
obj.append_attribute("elemtype") = "";
|
||||
|
||||
for(size_t o = 0; o < value->data.children.size(); o++)
|
||||
saveSDObject(*value->data.children[o], obj.append_child("item"));
|
||||
}
|
||||
else
|
||||
{
|
||||
saveSDObject(*value, obj);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static SDObject *XML2Config(pugi::xml_node &obj)
|
||||
{
|
||||
SDObject *ret = new SDObject(obj.name(), obj.attribute("type") ? "setting"_lit : "category"_lit);
|
||||
|
||||
if(ret->type.name == "category"_lit)
|
||||
{
|
||||
uint32_t i = 0;
|
||||
for(pugi::xml_node child = obj.first_child(); child; child = child.next_sibling())
|
||||
{
|
||||
if(child.type() == pugi::node_comment)
|
||||
continue;
|
||||
|
||||
SDObject *childObj = XML2Config(child);
|
||||
if(childObj)
|
||||
{
|
||||
ret->data.children.push_back(childObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("Error converting child %u config option '%s'", i, ret->name.c_str());
|
||||
delete ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pugi::xml_node value = obj.first_child();
|
||||
rdcstr description = obj.previous_sibling().value();
|
||||
description.trim();
|
||||
|
||||
ret->AddAndOwnChild(makeSDObject("description", description));
|
||||
|
||||
SDObject *valueObj = NULL;
|
||||
|
||||
const SDBasic types[] = {
|
||||
SDBasic::Array, SDBasic::String, SDBasic::UnsignedInteger,
|
||||
SDBasic::SignedInteger, SDBasic::Float, SDBasic::Boolean,
|
||||
};
|
||||
|
||||
static rdcarray<rdcstr> basicTypeStrings;
|
||||
for(SDBasic t : types)
|
||||
basicTypeStrings.push_back(ToStr(t));
|
||||
|
||||
SDBasic type = types[basicTypeStrings.indexOf(obj.attribute("type").as_string())];
|
||||
|
||||
if(type == SDBasic::Array)
|
||||
{
|
||||
type = types[basicTypeStrings.indexOf(obj.attribute("elemtype").as_string())];
|
||||
valueObj = makeSDArray("value");
|
||||
|
||||
uint32_t i = 0;
|
||||
for(pugi::xml_node el = value.first_child(); el; el = el.next_sibling())
|
||||
{
|
||||
SDObject *childObj = makeSDObject("$el", type, el);
|
||||
|
||||
if(childObj)
|
||||
{
|
||||
valueObj->data.children.push_back(childObj);
|
||||
}
|
||||
else
|
||||
{
|
||||
RDCERR("Error converting array value %u in config option '%s'", i, ret->name.c_str());
|
||||
delete valueObj;
|
||||
delete ret;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
i++;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
valueObj = makeSDObject("value", type, value);
|
||||
|
||||
if(!valueObj)
|
||||
{
|
||||
RDCERR("Unexpected type %u of attribute %s", type, ret->name.c_str());
|
||||
delete ret;
|
||||
return NULL;
|
||||
}
|
||||
}
|
||||
|
||||
ret->AddAndOwnChild(valueObj);
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static SDObject *importXMLConfig(StreamReader &stream)
|
||||
{
|
||||
rdcstr buf;
|
||||
buf.resize((size_t)stream.GetSize());
|
||||
stream.Read(buf.data(), buf.size());
|
||||
|
||||
pugi::xml_document doc;
|
||||
doc.load_string(buf.c_str(), pugi::parse_default | pugi::parse_comments);
|
||||
|
||||
pugi::xml_node root = doc.child("config");
|
||||
|
||||
SDObject *ret = new SDObject("config"_lit, "config"_lit);
|
||||
|
||||
if(root)
|
||||
{
|
||||
for(pugi::xml_node child = root.first_child(); child; child = child.next_sibling())
|
||||
{
|
||||
SDObject *childObj = XML2Config(child);
|
||||
if(childObj)
|
||||
ret->data.children.push_back(XML2Config(child));
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
static void exportXMLConfig(StreamWriter &stream, const SDObject *obj)
|
||||
{
|
||||
pugi::xml_document doc;
|
||||
|
||||
pugi::xml_node xRoot = doc.append_child("config");
|
||||
xRoot.append_attribute("version") = (uint32_t)1;
|
||||
|
||||
for(size_t o = 0; o < obj->data.children.size(); o++)
|
||||
Config2XML(xRoot, *obj->data.children[o]);
|
||||
|
||||
xml_stream_writer writer(stream);
|
||||
doc.save(writer, " ", pugi::format_default | pugi::format_no_empty_element_tags);
|
||||
}
|
||||
|
||||
static bool MergeConfigValues(const rdcstr &prefix, SDObject *dstConfig, const SDObject *srcConfig,
|
||||
bool updateDescs)
|
||||
{
|
||||
bool ret = false;
|
||||
|
||||
// for every child in the destination, see if it has a source node. If not, we're out of date
|
||||
for(size_t i = 0; i < dstConfig->NumChildren(); i++)
|
||||
ret |= (srcConfig->FindChild(dstConfig->GetChild(i)->name.c_str()) == NULL);
|
||||
|
||||
// for every child in the source
|
||||
for(size_t i = 0; i < srcConfig->NumChildren(); i++)
|
||||
{
|
||||
// see if it's present in the destination
|
||||
const SDObject *srcChild = srcConfig->GetChild(i);
|
||||
SDObject *dstChild = dstConfig->FindChild(srcChild->name.c_str());
|
||||
|
||||
if(dstChild)
|
||||
{
|
||||
// if present, merge the values
|
||||
rdcstr prefixedChild = prefix + dstChild->name;
|
||||
|
||||
if(dstChild->type.name == "category"_lit)
|
||||
{
|
||||
// recurse if this child is not a setting node
|
||||
ret |= MergeConfigValues(prefixedChild + ".", dstChild, srcChild, updateDescs);
|
||||
}
|
||||
else
|
||||
{
|
||||
SDObject *dstVal = dstChild->FindChild("value");
|
||||
const SDObject *srcVal = srcChild->FindChild("value");
|
||||
SDObject *dstDesc = dstChild->FindChild("description");
|
||||
const SDObject *srcDesc = srcChild->FindChild("description");
|
||||
|
||||
bool customised = !srcVal->HasEqualValue(dstVal);
|
||||
|
||||
// otherwise see if the value is customised, and if so log the change
|
||||
if(customised)
|
||||
{
|
||||
rdcstr oldVal = valueString(dstVal);
|
||||
rdcstr newVal = valueString(srcVal);
|
||||
|
||||
RDCLOG("%s has been customised from %s to %s", (prefix + dstChild->name).c_str(),
|
||||
oldVal.c_str(), newVal.c_str());
|
||||
|
||||
if(dstDesc->data.str.contains(debugOnlyString))
|
||||
{
|
||||
RDCWARN("%s customisation will not apply - read only in this build",
|
||||
(prefix + dstChild->name).c_str());
|
||||
}
|
||||
|
||||
// always set the value. For a debug-only setting this will do nothing but we want to
|
||||
// update our config value with the user's in case we're going to write out some new
|
||||
// values/descriptions
|
||||
dstVal->data.str = srcVal->data.str;
|
||||
memcpy(&dstVal->data.basic, &srcVal->data.basic, sizeof(dstVal->data.basic));
|
||||
|
||||
dstVal->DeleteChildren();
|
||||
|
||||
for(size_t c = 0; c < srcVal->data.children.size(); c++)
|
||||
dstVal->data.children.push_back(srcVal->data.children[c]->Duplicate());
|
||||
}
|
||||
|
||||
// if the description has changed from the loaded, need to write the new one
|
||||
if(dstDesc->data.str != srcDesc->data.str)
|
||||
{
|
||||
if(updateDescs)
|
||||
dstDesc->data.str = srcDesc->data.str;
|
||||
ret |= true;
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// child wasn't in the destination config, out of date
|
||||
ret |= true;
|
||||
|
||||
// if we're copying nodes, do that now
|
||||
dstConfig->AddChild(srcChild->Duplicate());
|
||||
}
|
||||
}
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
const bool &ConfigVarRegistration<bool>::value()
|
||||
{
|
||||
// avoid warnings on stupid compilers
|
||||
(void)tmp;
|
||||
return obj->data.basic.b;
|
||||
}
|
||||
|
||||
const uint64_t &ConfigVarRegistration<uint64_t>::value()
|
||||
{
|
||||
(void)tmp;
|
||||
return obj->data.basic.u;
|
||||
}
|
||||
|
||||
const uint32_t &ConfigVarRegistration<uint32_t>::value()
|
||||
{
|
||||
tmp = obj->data.basic.u & 0xFFFFFFFFU;
|
||||
return tmp;
|
||||
}
|
||||
|
||||
const rdcstr &ConfigVarRegistration<rdcstr>::value()
|
||||
{
|
||||
(void)tmp;
|
||||
return obj->data.str;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
rdcstr DefValString(const T &el)
|
||||
{
|
||||
return ToStr(el);
|
||||
}
|
||||
|
||||
// this one needs a special implementation unfortunately to convert
|
||||
const rdcarray<rdcstr> &ConfigVarRegistration<rdcarray<rdcstr>>::value()
|
||||
{
|
||||
tmp.resize(obj->data.children.size());
|
||||
for(size_t i = 0; i < tmp.size(); i++)
|
||||
tmp[i] = obj->data.children[i]->data.str;
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
rdcstr DefValString(const rdcarray<rdcstr> &el)
|
||||
{
|
||||
rdcstr ret = "[";
|
||||
for(size_t i = 0; i < el.size(); i++)
|
||||
{
|
||||
if(i != 0)
|
||||
ret += ", ";
|
||||
ret += el[i];
|
||||
}
|
||||
ret += "]";
|
||||
return ret;
|
||||
}
|
||||
|
||||
inline SDObject *makeSDObject(const char *name, const rdcarray<rdcstr> &vals)
|
||||
{
|
||||
SDObject *ret = new SDObject(name, "array"_lit);
|
||||
ret->type.basetype = SDBasic::Array;
|
||||
for(const rdcstr &s : vals)
|
||||
ret->data.children.push_back(makeSDObject("$el", s));
|
||||
return ret;
|
||||
}
|
||||
|
||||
#define CONFIG_SUPPORT_TYPE(T) \
|
||||
ConfigVarRegistration<T>::ConfigVarRegistration(rdcliteral name, const T &defaultValue, \
|
||||
bool debugOnly, rdcliteral description) \
|
||||
{ \
|
||||
rdcstr settingName = name; \
|
||||
settingName = settingName.substr(settingName.find_last_of("_") + 1); \
|
||||
\
|
||||
rdcstr desc = name; \
|
||||
desc += "\n\n"; \
|
||||
for(char &c : desc) \
|
||||
if(c == '_') \
|
||||
c = '.'; \
|
||||
desc += description; \
|
||||
\
|
||||
desc += "\n\nDefault value: '" + DefValString(defaultValue) + "'"; \
|
||||
if(debugOnly) \
|
||||
{ \
|
||||
desc += "\n"; \
|
||||
desc += debugOnlyString; \
|
||||
} \
|
||||
\
|
||||
SDObject *setting = new SDObject(settingName, "setting"_lit); \
|
||||
setting->AddAndOwnChild(makeSDObject("value", defaultValue)); \
|
||||
setting->AddAndOwnChild(makeSDObject("key", name)); \
|
||||
setting->AddAndOwnChild(makeSDObject("default", defaultValue)); \
|
||||
setting->AddAndOwnChild(makeSDObject("description", desc.c_str())); \
|
||||
\
|
||||
obj = setting->GetChild(0); \
|
||||
\
|
||||
RenderDoc::Inst().RegisterSetting(name, setting); \
|
||||
}
|
||||
|
||||
CONFIG_SUPPORT_TYPE(bool)
|
||||
CONFIG_SUPPORT_TYPE(uint64_t)
|
||||
CONFIG_SUPPORT_TYPE(uint32_t)
|
||||
CONFIG_SUPPORT_TYPE(rdcstr)
|
||||
CONFIG_SUPPORT_TYPE(rdcarray<rdcstr>)
|
||||
|
||||
void RenderDoc::ProcessConfig()
|
||||
{
|
||||
rdcstr confFile = FileIO::GetAppFolderFilename("renderdoc.conf");
|
||||
|
||||
SDObject *loadedConfig = NULL;
|
||||
{
|
||||
StreamReader reader(FileIO::fopen(confFile.c_str(), "rb"));
|
||||
|
||||
loadedConfig = importXMLConfig(reader);
|
||||
}
|
||||
|
||||
// iterate through the current config, and update any values that are found in the loaded config.
|
||||
// returns true if the loaded config is out of date (i.e. there's a value we have which isn't
|
||||
// present at all, or the descriptions in the loaded config are old).
|
||||
bool outofDate = ::MergeConfigValues(rdcstr(), m_Config, loadedConfig, false);
|
||||
|
||||
// in the replay application, write it back out again if it's out of date. This
|
||||
// refreshes the config without changing any customised values and means the user can always edit
|
||||
// the files on disk
|
||||
if(IsReplayApp() && outofDate)
|
||||
{
|
||||
bool success = false;
|
||||
|
||||
// merge the current config into the loaded config. Values that overlap will have been updated
|
||||
// with the user's values above, so all that's left is to add new values which aren't in the
|
||||
// config or update descriptions
|
||||
MergeConfigValues(rdcstr(), loadedConfig, m_Config, true);
|
||||
|
||||
{
|
||||
StreamWriter writer(FileIO::fopen((confFile + ".tmp").c_str(), "wb"), Ownership::Stream);
|
||||
|
||||
exportXMLConfig(writer, loadedConfig);
|
||||
|
||||
// only overwrite the config if there were no errors here
|
||||
success = !writer.IsErrored();
|
||||
}
|
||||
|
||||
// if we successfully wrote the file, move it over the original
|
||||
if(success)
|
||||
FileIO::Move((confFile + ".tmp").c_str(), confFile.c_str(), true);
|
||||
}
|
||||
|
||||
// delete the loaded config if we have it
|
||||
delete loadedConfig;
|
||||
}
|
||||
|
||||
void RenderDoc::SaveConfigSettings()
|
||||
{
|
||||
if(IsReplayApp())
|
||||
{
|
||||
rdcstr confFile = FileIO::GetAppFolderFilename("renderdoc.conf");
|
||||
|
||||
bool success = false;
|
||||
|
||||
{
|
||||
StreamWriter writer(FileIO::fopen((confFile + ".tmp").c_str(), "wb"), Ownership::Stream);
|
||||
|
||||
exportXMLConfig(writer, m_Config);
|
||||
|
||||
// only overwrite the config if there were no errors here
|
||||
success = !writer.IsErrored();
|
||||
}
|
||||
|
||||
// if we successfully wrote the file, move it over the original
|
||||
if(success)
|
||||
FileIO::Move((confFile + ".tmp").c_str(), confFile.c_str(), true);
|
||||
}
|
||||
}
|
||||
|
||||
const SDObject *RenderDoc::GetConfigSetting(const rdcstr &settingPath)
|
||||
{
|
||||
return FindConfigSetting(settingPath);
|
||||
}
|
||||
|
||||
SDObject *RenderDoc::SetConfigSetting(const rdcstr &settingPath)
|
||||
{
|
||||
return FindConfigSetting(settingPath);
|
||||
}
|
||||
|
||||
SDObject *RenderDoc::FindConfigSetting(const rdcstr &settingPath)
|
||||
{
|
||||
if(settingPath.empty())
|
||||
return m_Config;
|
||||
|
||||
SDObject *cur = m_Config;
|
||||
|
||||
rdcstr path = settingPath;
|
||||
int idx = path.find_first_of("_.");
|
||||
while(idx >= 0)
|
||||
{
|
||||
rdcstr node = path.substr(0, idx);
|
||||
path.erase(0, idx + 1);
|
||||
|
||||
SDObject *child = cur->FindChild(node.c_str());
|
||||
if(!child)
|
||||
return NULL;
|
||||
|
||||
cur = child;
|
||||
idx = path.find_first_of("_.");
|
||||
}
|
||||
|
||||
SDObject *obj = cur->FindChild(path.c_str());
|
||||
if(obj)
|
||||
return obj->FindChild("value");
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void RenderDoc::RegisterSetting(const rdcstr &settingPath, SDObject *setting)
|
||||
{
|
||||
SDObject *cur = m_Config;
|
||||
|
||||
if(cur == NULL)
|
||||
cur = m_Config = new SDObject("config"_lit, "config"_lit);
|
||||
|
||||
rdcstr path = settingPath;
|
||||
int idx = path.indexOf('_');
|
||||
while(idx >= 0)
|
||||
{
|
||||
rdcstr node = path.substr(0, idx);
|
||||
path.erase(0, idx + 1);
|
||||
|
||||
SDObject *child = cur->FindChild(node.c_str());
|
||||
if(!child)
|
||||
{
|
||||
child = new SDObject(node, "category"_lit);
|
||||
auto it =
|
||||
std::lower_bound(cur->data.children.begin(), cur->data.children.end(), child,
|
||||
[](const SDObject *a, const SDObject *b) { return a->name < b->name; });
|
||||
cur->data.children.insert(it - cur->data.children.begin(), child);
|
||||
}
|
||||
|
||||
cur = child;
|
||||
|
||||
idx = path.indexOf('_');
|
||||
}
|
||||
|
||||
SDObject *obj = cur->FindChild(path.c_str());
|
||||
if(obj != NULL)
|
||||
RDCFATAL("Duplicate setting %s", settingPath.c_str());
|
||||
|
||||
cur->AddAndOwnChild(setting);
|
||||
}
|
||||
@@ -0,0 +1,79 @@
|
||||
/******************************************************************************
|
||||
* The MIT License (MIT)
|
||||
*
|
||||
* Copyright (c) 2019 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 "api/replay/rdcarray.h"
|
||||
#include "api/replay/rdcstr.h"
|
||||
#include "api/replay/version.h"
|
||||
#include "common/common.h"
|
||||
|
||||
struct SDObject;
|
||||
|
||||
template <typename T>
|
||||
struct ConfigVarRegistration;
|
||||
|
||||
#define CONFIG_SUPPORT_TYPE(T) \
|
||||
template <> \
|
||||
struct ConfigVarRegistration<T> \
|
||||
{ \
|
||||
ConfigVarRegistration(rdcliteral name, const T &defaultValue, bool debugOnly, \
|
||||
rdcliteral description); \
|
||||
const T &value(); \
|
||||
\
|
||||
private: \
|
||||
SDObject *obj; \
|
||||
T tmp; \
|
||||
};
|
||||
|
||||
CONFIG_SUPPORT_TYPE(rdcstr);
|
||||
CONFIG_SUPPORT_TYPE(bool);
|
||||
CONFIG_SUPPORT_TYPE(uint64_t);
|
||||
CONFIG_SUPPORT_TYPE(uint32_t);
|
||||
CONFIG_SUPPORT_TYPE(rdcarray<rdcstr>);
|
||||
|
||||
#undef CONFIG_SUPPORT_TYPE
|
||||
|
||||
#define RDOC_CONFIG(type, name, defaultValue, description) \
|
||||
static ConfigVarRegistration<type> CONCAT(config, __LINE__)( \
|
||||
STRING_LITERAL(STRINGIZE(name)), defaultValue, false, STRING_LITERAL(description)); \
|
||||
static const type &name = CONCAT(config, __LINE__).value();
|
||||
|
||||
// debug configs get set to constants in official stable builds, they will remain configurable
|
||||
// in nightly builds and of course in development builds
|
||||
#if RENDERDOC_STABLE_BUILD
|
||||
|
||||
#define RDOC_DEBUG_CONFIG(type, name, defaultValue, description) \
|
||||
static ConfigVarRegistration<type> CONCAT(config, __LINE__)( \
|
||||
STRING_LITERAL(STRINGIZE(name)), defaultValue, true, STRING_LITERAL(description)); \
|
||||
static constexpr type name = defaultValue;
|
||||
|
||||
#else
|
||||
|
||||
#define RDOC_DEBUG_CONFIG(type, name, defaultValue, description) \
|
||||
ConfigVarRegistration<type> CONCAT(config, __LINE__)( \
|
||||
STRING_LITERAL(STRINGIZE(name)), defaultValue, true, STRING_LITERAL(description)); \
|
||||
static const type &name = CONCAT(config, __LINE__).value();
|
||||
|
||||
#endif
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
#include "d3d11_device.h"
|
||||
#include "core/core.h"
|
||||
#include "core/settings.h"
|
||||
#include "driver/dxgi/dxgi_wrapped.h"
|
||||
#include "jpeg-compressor/jpge.h"
|
||||
#include "maths/formatpacking.h"
|
||||
@@ -38,6 +39,9 @@
|
||||
#include "d3d11_resources.h"
|
||||
#include "d3d11_shader_cache.h"
|
||||
|
||||
RDOC_CONFIG(rdcarray<rdcstr>, DXBC_Debug_SearchDirPaths, {},
|
||||
"Paths to search for separated shader debug PDBs.");
|
||||
|
||||
WRAPPED_POOL_INST(WrappedID3D11Device);
|
||||
|
||||
WrappedID3D11Device *WrappedID3D11Device::m_pCurrentWrappedDevice = NULL;
|
||||
@@ -112,9 +116,6 @@ WrappedID3D11Device::WrappedID3D11Device(ID3D11Device *realDevice, D3D11InitPara
|
||||
|
||||
D3D11MarkerRegion::device = this;
|
||||
|
||||
rdcstr shaderSearchPathString = RenderDoc::Inst().GetConfigSetting("shader.debug.searchPaths");
|
||||
split(shaderSearchPathString, m_ShaderSearchPaths, ';');
|
||||
|
||||
ResourceIDGen::SetReplayResourceIDs();
|
||||
}
|
||||
else
|
||||
@@ -789,6 +790,11 @@ rdcstr WrappedID3D11Device::GetChunkName(uint32_t idx)
|
||||
return ToStr((D3D11Chunk)idx);
|
||||
}
|
||||
|
||||
const rdcarray<rdcstr> *WrappedID3D11Device::GetShaderDebugInfoSearchPaths()
|
||||
{
|
||||
return &DXBC_Debug_SearchDirPaths;
|
||||
}
|
||||
|
||||
void WrappedID3D11Device::AddDebugMessage(MessageCategory c, MessageSeverity sv, MessageSource src,
|
||||
rdcstr d)
|
||||
{
|
||||
|
||||
@@ -314,8 +314,6 @@ private:
|
||||
D3D11ShaderCache *m_ShaderCache = NULL;
|
||||
D3D11ResourceManager *m_ResourceManager = NULL;
|
||||
|
||||
rdcarray<rdcstr> m_ShaderSearchPaths;
|
||||
|
||||
D3D11InitParams m_InitParams;
|
||||
uint64_t m_SectionVersion;
|
||||
ReplayOptions m_ReplayOptions;
|
||||
@@ -456,7 +454,7 @@ public:
|
||||
return m_LayoutDescs[layout];
|
||||
}
|
||||
|
||||
rdcarray<rdcstr> *GetShaderDebugInfoSearchPaths() { return &m_ShaderSearchPaths; }
|
||||
const rdcarray<rdcstr> *GetShaderDebugInfoSearchPaths();
|
||||
template <typename SerialiserType>
|
||||
bool Serialise_CaptureScope(SerialiserType &ser);
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "d3d11_replay.h"
|
||||
#include "core/settings.h"
|
||||
#include "driver/dx/official/d3dcompiler.h"
|
||||
#include "driver/ihv/amd/amd_counters.h"
|
||||
#include "driver/ihv/intel/intel_counters.h"
|
||||
@@ -42,6 +43,9 @@
|
||||
|
||||
#include "data/hlsl/hlsl_cbuffers.h"
|
||||
|
||||
RDOC_CONFIG(bool, D3D11_HardwareCounters, true,
|
||||
"Enable support for IHV-specific hardware counters on D3D11.");
|
||||
|
||||
static const char *DXBCDisassemblyTarget = "DXBC";
|
||||
|
||||
D3D11Replay::D3D11Replay(WrappedID3D11Device *d)
|
||||
@@ -170,7 +174,7 @@ void D3D11Replay::CreateResources(IDXGIFactory *factory)
|
||||
|
||||
m_pDevice->GetShaderCache()->SetCaching(false);
|
||||
|
||||
if(!m_Proxy)
|
||||
if(!m_Proxy && D3D11_HardwareCounters)
|
||||
{
|
||||
AMDCounters *countersAMD = NULL;
|
||||
NVCounters *countersNV = NULL;
|
||||
|
||||
@@ -956,7 +956,7 @@ public:
|
||||
ResourceId m_ID;
|
||||
|
||||
rdcstr m_DebugInfoPath;
|
||||
rdcarray<rdcstr> *m_DebugInfoSearchPaths;
|
||||
const rdcarray<rdcstr> *m_DebugInfoSearchPaths;
|
||||
|
||||
rdcarray<byte> m_Bytecode;
|
||||
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "d3d12_replay.h"
|
||||
#include "core/plugins.h"
|
||||
#include "core/settings.h"
|
||||
#include "driver/dx/official/d3dcompiler.h"
|
||||
#include "driver/dxgi/dxgi_common.h"
|
||||
#include "driver/ihv/amd/amd_counters.h"
|
||||
@@ -41,6 +42,12 @@
|
||||
|
||||
#include "data/hlsl/hlsl_cbuffers.h"
|
||||
|
||||
RDOC_CONFIG(bool, D3D12_ShaderDebugging, false,
|
||||
"BETA: Enable experimental shader debugging support.");
|
||||
|
||||
RDOC_CONFIG(bool, D3D12_HardwareCounters, true,
|
||||
"Enable support for IHV-specific hardware counters on D3D12.");
|
||||
|
||||
static const char *LiveDriverDisassemblyTarget = "Live driver disassembly";
|
||||
|
||||
ID3DDevice *GetD3D12DeviceIfAlloc(IUnknown *dev);
|
||||
@@ -151,7 +158,7 @@ void D3D12Replay::CreateResources()
|
||||
m_PixelPick.Init(m_pDevice, m_DebugManager);
|
||||
m_Histogram.Init(m_pDevice, m_DebugManager);
|
||||
|
||||
if(!m_Proxy)
|
||||
if(!m_Proxy && D3D12_HardwareCounters)
|
||||
{
|
||||
AMDCounters *counters = NULL;
|
||||
|
||||
@@ -271,11 +278,7 @@ APIProperties D3D12Replay::GetAPIProperties()
|
||||
ret.shadersMutable = false;
|
||||
ret.rgpCapture =
|
||||
m_DriverInfo.vendor == GPUVendor::AMD && m_RGP != NULL && m_RGP->DriverSupportsInterop();
|
||||
|
||||
// Enable shader debugging if specified in the config
|
||||
rdcstr setting = strlower(RenderDoc::Inst().GetConfigSetting("d3d12ShaderDebugging"));
|
||||
if(!strcmp(setting.c_str(), "true") || setting == "1")
|
||||
ret.shaderDebugging = true;
|
||||
ret.shaderDebugging = D3D12_ShaderDebugging;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include "gl_replay.h"
|
||||
#include "core/settings.h"
|
||||
#include "driver/ihv/amd/amd_counters.h"
|
||||
#include "driver/ihv/intel/intel_gl_counters.h"
|
||||
#include "maths/matrix.h"
|
||||
@@ -35,6 +36,9 @@
|
||||
#define OPENGL 1
|
||||
#include "data/glsl/glsl_ubos_cpp.h"
|
||||
|
||||
RDOC_CONFIG(bool, OpenGL_HardwareCounters, true,
|
||||
"Enable support for IHV-specific hardware counters on OpenGL.");
|
||||
|
||||
static const char *SPIRVDisassemblyTarget = "SPIR-V (RenderDoc)";
|
||||
|
||||
GLReplay::GLReplay(WrappedOpenGL *d)
|
||||
@@ -227,7 +231,7 @@ void GLReplay::SetReplayData(GLWindowingData data)
|
||||
if(!HasDebugContext())
|
||||
return;
|
||||
|
||||
if(!m_Proxy)
|
||||
if(!m_Proxy && OpenGL_HardwareCounters)
|
||||
{
|
||||
AMDCounters *countersAMD = NULL;
|
||||
IntelGlCounters *countersIntel = NULL;
|
||||
|
||||
@@ -26,8 +26,11 @@
|
||||
#include "common/common.h"
|
||||
#include "core/core.h"
|
||||
#include "core/plugins.h"
|
||||
#include "core/settings.h"
|
||||
#include "official/RGP/DevDriverAPI.h"
|
||||
|
||||
RDOC_CONFIG(bool, AMD_RGP_Enable, false, "Enable integration with AMD's RGP tool.");
|
||||
|
||||
uint64_t MakeTagFromMarker(const char *marker)
|
||||
{
|
||||
if(!marker)
|
||||
@@ -68,9 +71,7 @@ AMDRGPControl::AMDRGPControl()
|
||||
m_RGPDispatchTable->minorVersion = DEV_DRIVER_API_MINOR_VERSION;
|
||||
m_RGPContext = NULL;
|
||||
|
||||
const bool enabled = RenderDoc::Inst().GetConfigSetting("ExternalTool_RGPIntegration") == "1";
|
||||
|
||||
if(!enabled)
|
||||
if(!AMD_RGP_Enable)
|
||||
{
|
||||
RDCLOG("AMD RGP Interop is not enabled");
|
||||
return;
|
||||
|
||||
@@ -26,12 +26,17 @@
|
||||
#include <math.h>
|
||||
#include "common/common.h"
|
||||
#include "core/core.h"
|
||||
#include "core/settings.h"
|
||||
#include "serialise/serialiser.h"
|
||||
#include "strings/string_utils.h"
|
||||
#include "dxbc_bytecode.h"
|
||||
|
||||
#include "dxbc_container.h"
|
||||
|
||||
RDOC_CONFIG(bool, DXBC_Disassembly_FriendlyNaming, true,
|
||||
"Where possible (i.e. it is completely unambiguous) replace register names with "
|
||||
"high-level variable names.");
|
||||
|
||||
namespace DXBCBytecode
|
||||
{
|
||||
// little utility function to both document and easily extract an arbitrary mask
|
||||
@@ -437,7 +442,7 @@ void Program::DisassembleHexDump()
|
||||
|
||||
m_Declarations.reserve(numDecls);
|
||||
|
||||
const bool friendly = RenderDoc::Inst().GetConfigSetting("Disassembly_FriendlyNaming") != "0";
|
||||
const bool friendly = DXBC_Disassembly_FriendlyNaming;
|
||||
|
||||
while(cur < end)
|
||||
{
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
******************************************************************************/
|
||||
|
||||
#include <float.h>
|
||||
#include "core/settings.h"
|
||||
#include "driver/shaders/spirv/spirv_editor.h"
|
||||
#include "driver/shaders/spirv/spirv_op_helpers.h"
|
||||
#include "vk_core.h"
|
||||
@@ -30,6 +31,10 @@
|
||||
#include "vk_replay.h"
|
||||
#include "vk_shader_cache.h"
|
||||
|
||||
RDOC_CONFIG(
|
||||
bool, Vulkan_BindlessFeedback, true,
|
||||
"Enable fetching from GPU which descriptors were dynamically used in descriptor arrays.");
|
||||
|
||||
struct feedbackData
|
||||
{
|
||||
uint64_t offset;
|
||||
@@ -524,6 +529,9 @@ void VulkanReplay::FetchShaderFeedback(uint32_t eventId)
|
||||
if(m_BindlessFeedback.Usage.find(eventId) != m_BindlessFeedback.Usage.end())
|
||||
return;
|
||||
|
||||
if(!Vulkan_BindlessFeedback)
|
||||
return;
|
||||
|
||||
// create it here so we won't re-run any code if the event is re-selected. We'll mark it as valid
|
||||
// if it actually has any data in it later.
|
||||
DynamicUsedBinds &result = m_BindlessFeedback.Usage[eventId];
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
|
||||
#include "vk_debug.h"
|
||||
#include <float.h>
|
||||
#include "core/settings.h"
|
||||
#include "data/glsl_shaders.h"
|
||||
#include "driver/ihv/amd/amd_counters.h"
|
||||
#include "driver/ihv/amd/official/GPUPerfAPI/Include/GPUPerfAPI-VK.h"
|
||||
@@ -38,6 +39,9 @@
|
||||
#define VULKAN 1
|
||||
#include "data/glsl/glsl_ubos_cpp.h"
|
||||
|
||||
RDOC_CONFIG(bool, Vulkan_HardwareCounters, true,
|
||||
"Enable support for IHV-specific hardware counters on Vulkan.");
|
||||
|
||||
const VkDeviceSize STAGE_BUFFER_BYTE_SIZE = 16 * 1024 * 1024ULL;
|
||||
|
||||
static void create(WrappedVulkan *driver, const char *objName, const int line, VkSampler *sampler,
|
||||
@@ -1712,7 +1716,7 @@ void VulkanReplay::CreateResources()
|
||||
GPA_vkContextOpenInfo context = {Unwrap(m_pDriver->GetInstance()),
|
||||
Unwrap(m_pDriver->GetPhysDev()), Unwrap(m_pDriver->GetDev())};
|
||||
|
||||
if(!m_pDriver->GetReplay()->IsRemoteProxy())
|
||||
if(!m_pDriver->GetReplay()->IsRemoteProxy() && Vulkan_HardwareCounters)
|
||||
{
|
||||
AMDCounters *counters = NULL;
|
||||
|
||||
|
||||
@@ -27,6 +27,7 @@
|
||||
#include <float.h>
|
||||
#include <math.h>
|
||||
#include <algorithm>
|
||||
#include "core/settings.h"
|
||||
#include "driver/ihv/amd/amd_rgp.h"
|
||||
#include "driver/shaders/spirv/spirv_compile.h"
|
||||
#include "maths/formatpacking.h"
|
||||
@@ -41,6 +42,9 @@
|
||||
#define VULKAN 1
|
||||
#include "data/glsl/glsl_ubos_cpp.h"
|
||||
|
||||
RDOC_CONFIG(bool, Vulkan_ShaderDebugging, false,
|
||||
"BETA: Enable experimental shader debugging support.");
|
||||
|
||||
static const char *SPIRVDisassemblyTarget = "SPIR-V (RenderDoc)";
|
||||
static const char *AMDShaderInfoTarget = "AMD_shader_info";
|
||||
static const char *KHRExecutablePropertiesTarget = "KHR_pipeline_executable_properties";
|
||||
@@ -186,11 +190,7 @@ APIProperties VulkanReplay::GetAPIProperties()
|
||||
ret.shadersMutable = false;
|
||||
ret.rgpCapture =
|
||||
m_DriverInfo.vendor == GPUVendor::AMD && m_RGP != NULL && m_RGP->DriverSupportsInterop();
|
||||
|
||||
// Enable shader debugging if specified in the config
|
||||
rdcstr setting = strlower(RenderDoc::Inst().GetConfigSetting("vulkanShaderDebugging"));
|
||||
if(!strcmp(setting.c_str(), "true") || setting == "1")
|
||||
ret.shaderDebugging = true;
|
||||
ret.shaderDebugging = Vulkan_ShaderDebugging;
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@@ -189,6 +189,7 @@
|
||||
<ClInclude Include="common\timing.h" />
|
||||
<ClInclude Include="common\wrapped_pool.h" />
|
||||
<ClInclude Include="core\bit_flag_iterator.h" />
|
||||
<ClInclude Include="core\settings.h" />
|
||||
<ClInclude Include="core\core.h" />
|
||||
<ClInclude Include="core\crash_handler.h" />
|
||||
<ClInclude Include="core\intervals.h" />
|
||||
@@ -421,6 +422,7 @@
|
||||
<ClCompile Include="common\dds_readwrite.cpp" />
|
||||
<ClCompile Include="common\threading_tests.cpp" />
|
||||
<ClCompile Include="core\bit_flag_iterator_tests.cpp" />
|
||||
<ClCompile Include="core\settings.cpp" />
|
||||
<ClCompile Include="core\core.cpp" />
|
||||
<ClCompile Include="core\image_viewer.cpp" />
|
||||
<ClCompile Include="core\intervals_tests.cpp" />
|
||||
|
||||
@@ -504,6 +504,9 @@
|
||||
<ClInclude Include="common\formatting.h">
|
||||
<Filter>Common</Filter>
|
||||
</ClInclude>
|
||||
<ClInclude Include="core\settings.h">
|
||||
<Filter>Core</Filter>
|
||||
</ClInclude>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<ClCompile Include="maths\camera.cpp">
|
||||
@@ -887,6 +890,9 @@
|
||||
<ClCompile Include="maths\vec.cpp">
|
||||
<Filter>Common\Maths</Filter>
|
||||
</ClCompile>
|
||||
<ClCompile Include="core\settings.cpp">
|
||||
<Filter>Core</Filter>
|
||||
</ClCompile>
|
||||
</ItemGroup>
|
||||
<ItemGroup>
|
||||
<None Include="os\win32\comexport.def">
|
||||
|
||||
@@ -192,15 +192,19 @@ extern "C" RENDERDOC_API uint64_t RENDERDOC_CC RENDERDOC_GetCurrentProcessMemory
|
||||
return Process::GetMemoryUsage();
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API const char *RENDERDOC_CC RENDERDOC_GetConfigSetting(const char *name)
|
||||
extern "C" RENDERDOC_API const SDObject *RENDERDOC_CC RENDERDOC_GetConfigSetting(const char *name)
|
||||
{
|
||||
return RenderDoc::Inst().GetConfigSetting(name).c_str();
|
||||
return RenderDoc::Inst().GetConfigSetting(name);
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetConfigSetting(const char *name,
|
||||
const char *value)
|
||||
extern "C" RENDERDOC_API SDObject *RENDERDOC_CC RENDERDOC_SetConfigSetting(const char *name)
|
||||
{
|
||||
RenderDoc::Inst().SetConfigSetting(name, value);
|
||||
return RenderDoc::Inst().SetConfigSetting(name);
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SaveConfigSettings()
|
||||
{
|
||||
return RenderDoc::Inst().SaveConfigSettings();
|
||||
}
|
||||
|
||||
extern "C" RENDERDOC_API void RENDERDOC_CC RENDERDOC_SetColors(FloatVector darkChecker,
|
||||
|
||||
@@ -34,6 +34,8 @@
|
||||
int64_t Chunk::m_LiveChunks = 0;
|
||||
int64_t Chunk::m_TotalMem = 0;
|
||||
|
||||
#endif
|
||||
|
||||
void DumpObject(FileIO::LogFileHandle *log, const rdcstr &indent, SDObject *obj)
|
||||
{
|
||||
if(obj->NumChildren() > 0)
|
||||
@@ -81,8 +83,6 @@ void DumpChunk(bool reading, FileIO::LogFileHandle *log, SDChunk *chunk)
|
||||
DumpObject(log, " ", chunk);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
// Read Serialiser functions
|
||||
|
||||
@@ -265,12 +265,10 @@ void Serialiser<SerialiserMode::Reading>::EndChunk()
|
||||
m_StructureStack.pop_back();
|
||||
}
|
||||
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
if(m_DebugDumpLog && !m_StructuredFile->chunks.empty())
|
||||
{
|
||||
DumpChunk(true, m_DebugDumpLog, m_StructuredFile->chunks.back());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// only skip remaining bytes if we have a valid length - if we have a length of 0 we wrote this
|
||||
@@ -526,12 +524,10 @@ void Serialiser<SerialiserMode::Writing>::EndChunk()
|
||||
m_StructureStack.pop_back();
|
||||
}
|
||||
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
if(m_DebugDumpLog && !m_StructuredFile->chunks.empty())
|
||||
{
|
||||
DumpChunk(false, m_DebugDumpLog, m_StructuredFile->chunks.back());
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// align to the natural chunk alignment
|
||||
@@ -621,27 +617,6 @@ void Serialiser<SerialiserMode::Writing>::WriteStructuredFile(const SDFile &file
|
||||
scratchWriter.m_StructuredFile = &scratchWriter.m_StructData;
|
||||
}
|
||||
|
||||
template <>
|
||||
rdcstr DoStringise(const SDBasic &el)
|
||||
{
|
||||
BEGIN_ENUM_STRINGISE(SDBasic);
|
||||
{
|
||||
STRINGISE_ENUM_CLASS(Chunk);
|
||||
STRINGISE_ENUM_CLASS(Struct);
|
||||
STRINGISE_ENUM_CLASS(Array);
|
||||
STRINGISE_ENUM_CLASS(Null);
|
||||
STRINGISE_ENUM_CLASS(Buffer);
|
||||
STRINGISE_ENUM_CLASS(String);
|
||||
STRINGISE_ENUM_CLASS(Enum);
|
||||
STRINGISE_ENUM_CLASS(UnsignedInteger);
|
||||
STRINGISE_ENUM_CLASS(SignedInteger);
|
||||
STRINGISE_ENUM_CLASS(Float);
|
||||
STRINGISE_ENUM_CLASS(Boolean);
|
||||
STRINGISE_ENUM_CLASS(Character);
|
||||
}
|
||||
END_ENUM_STRINGISE();
|
||||
}
|
||||
|
||||
template <>
|
||||
rdcstr DoStringise(const SDTypeFlags &el)
|
||||
{
|
||||
|
||||
@@ -121,11 +121,8 @@ public:
|
||||
uint32_t GetChunkMetadataRecording() { return m_ChunkFlags; }
|
||||
void SetChunkMetadataRecording(uint32_t flags);
|
||||
|
||||
// debug-only option to dump out (roughly) the data going through the serialiser as it happens
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
// debug-only option to dump out (roughly) the data going through the serialiser as it happens
|
||||
void EnableDumping(FileIO::LogFileHandle *debugLog) { m_DebugDumpLog = debugLog; }
|
||||
#endif
|
||||
|
||||
SDChunkMetaData &ChunkMetadata() { return m_ChunkMetadata; }
|
||||
//////////////////////////////////////////
|
||||
// Utility functions
|
||||
@@ -1340,9 +1337,7 @@ private:
|
||||
}
|
||||
|
||||
ChunkLookup m_ChunkLookup = NULL;
|
||||
#if ENABLED(RDOC_DEVEL)
|
||||
FileIO::LogFileHandle *m_DebugDumpLog = NULL;
|
||||
#endif
|
||||
};
|
||||
|
||||
#ifndef SERIALISER_IMPL
|
||||
|
||||
@@ -18,7 +18,9 @@ class D3D12_RGP_Capture(rdtest.TestCase):
|
||||
|
||||
# Need to enable RGP mode before opening the capture
|
||||
def run(self):
|
||||
rd.SetConfigSetting("ExternalTool_RGPIntegration", "1")
|
||||
obj: rd.SDObject = rd.SetConfigSetting("AMD.RGP.Enable")
|
||||
if obj is not None:
|
||||
obj.data.basic.b = True
|
||||
super().run()
|
||||
|
||||
def check_capture(self):
|
||||
|
||||
@@ -8,7 +8,9 @@ class VK_RGP_Capture(rdtest.TestCase):
|
||||
|
||||
# Need to enable RGP mode before opening the capture
|
||||
def run(self):
|
||||
rd.SetConfigSetting("ExternalTool_RGPIntegration", "1")
|
||||
obj: rd.SDObject = rd.SetConfigSetting("AMD.RGP.Enable")
|
||||
if obj is not None:
|
||||
obj.data.basic.b = True
|
||||
super().run()
|
||||
|
||||
def check_capture(self):
|
||||
|
||||
Reference in New Issue
Block a user