Add option to make shader search paths non-recursive

* For very large shader symbol stores especially those on network drives, the
  bad behaviour that PIX has to recursively search all possible subdirectories
  and enumerate all files can be really slow. Most of the time a file is
  identified by its hash filename and looked up directly - if that isn't a hit,
  in many cases users would rather a fast exit to having no symbols.
This commit is contained in:
baldurk
2025-04-16 15:48:21 +01:00
parent 67960c740c
commit 0f019eafb9
7 changed files with 243 additions and 98 deletions
@@ -303,18 +303,6 @@ void PersistantConfig::applyValues(const QVariantMap &values)
debug->AddAndOwnChild(makeSDString("$el"_lit, 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;
}
+151 -68
View File
@@ -23,18 +23,20 @@
******************************************************************************/
#include "OrderedListEditor.h"
#include <QHBoxLayout>
#include <QHeaderView>
#include <QKeyEvent>
#include <QToolButton>
#include "Code/QRDUtils.h"
#include "Code/Resources.h"
OrderedListEditor::OrderedListEditor(const QString &itemName, ItemButton mode, QWidget *parent)
OrderedListEditor::OrderedListEditor(const QString &itemName, OrderedItemExtras extras,
const CustomProp &prop, QWidget *parent)
: RDTableWidget(parent)
{
setFont(Formatter::PreferredFont());
m_ButtonMode = mode;
m_Prop = prop;
setDragEnabled(true);
setDragDropOverwriteMode(false);
@@ -49,30 +51,45 @@ OrderedListEditor::OrderedListEditor(const QString &itemName, ItemButton mode, Q
horizontalHeader()->setMinimumSectionSize(50);
verticalHeader()->setHighlightSections(false);
if(m_ButtonMode == ItemButton::None)
{
setColumnCount(1);
setHorizontalHeaderLabels({itemName});
horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
}
else
{
QStringList labels;
labels << itemName;
switch(m_ButtonMode)
{
case ItemButton::None: labels << lit("????"); break;
case ItemButton::BrowseFile:
case ItemButton::BrowseFolder: labels << tr("Browse"); break;
case ItemButton::Delete: labels << tr("Delete"); break;
}
setColumnCount(2);
setHorizontalHeaderLabels(labels);
QStringList labels;
int columnCount = 1;
labels << itemName;
horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
horizontalHeader()->setSectionResizeMode(1, QHeaderView::ResizeToContents);
if(!prop.name.isEmpty())
{
columnCount++;
labels << prop.name;
}
if(extras & OrderedItemExtras::BrowseFile)
{
columnCount++;
labels << tr("Browse");
m_Extras.push_back(OrderedItemExtras::BrowseFile);
}
else if(extras & OrderedItemExtras::BrowseFolder)
{
columnCount++;
labels << tr("Browse");
m_Extras.push_back(OrderedItemExtras::BrowseFolder);
}
if(extras & OrderedItemExtras::Delete)
{
columnCount++;
labels << tr("Delete");
m_Extras.push_back(OrderedItemExtras::Delete);
}
setColumnCount(columnCount);
setHorizontalHeaderLabels(labels);
horizontalHeader()->setSectionResizeMode(0, QHeaderView::Stretch);
for(int i = 1; i < columnCount; i++)
horizontalHeader()->setSectionResizeMode(i, QHeaderView::ResizeToContents);
if(!prop.name.isEmpty())
horizontalHeaderItem(1)->setToolTip(prop.tooltip);
QObject::connect(this, &RDTableWidget::cellChanged, this, &OrderedListEditor::cellChanged);
}
@@ -80,22 +97,40 @@ OrderedListEditor::~OrderedListEditor()
{
}
QToolButton *OrderedListEditor::makeButton()
QWidget *OrderedListEditor::makeCellWidget(int row, OrderedItemExtras extra)
{
QToolButton *ret = new QToolButton(this);
if(m_ButtonMode == ItemButton::Delete)
if(extra == OrderedItemExtras::Delete)
{
QToolButton *ret = new QToolButton(this);
ret->setAutoRaise(true);
ret->setIcon(Icons::del());
else
QObject::connect(ret, &QToolButton::clicked, [this, row, extra]() { extraClicked(row, extra); });
return ret;
}
else if(extra == OrderedItemExtras::BrowseFile || extra == OrderedItemExtras::BrowseFolder)
{
QToolButton *ret = new QToolButton(this);
ret->setAutoRaise(true);
ret->setIcon(Icons::folder_page_white());
ret->setAutoRaise(true);
QObject::connect(ret, &QToolButton::clicked, [this, row, extra]() { extraClicked(row, extra); });
QObject::connect(ret, &QToolButton::clicked, this, &OrderedListEditor::buttonActivate);
return ret;
return ret;
}
else if(extra == OrderedItemExtras::CustomProp)
{
QCheckBox *ret = new QCheckBox(this);
if(m_Prop.defaultValue)
ret->setChecked(true);
return ret;
}
else
{
return NULL;
}
}
void OrderedListEditor::setItems(const QStringList &strings)
void OrderedListEditor::setItemsAndProp(const QStringList &strings, const QList<bool> &prop)
{
setUpdatesEnabled(false);
clearContents();
@@ -106,8 +141,28 @@ void OrderedListEditor::setItems(const QStringList &strings)
{
setItem(i, 0, new QTableWidgetItem(strings[i]));
if(m_ButtonMode != ItemButton::None)
setCellWidget(i, 1, makeButton());
if(m_Prop.valid())
{
QWidget *w = makeCellWidget(i, OrderedItemExtras::CustomProp);
if(i < prop.count())
{
QCheckBox *c = qobject_cast<QCheckBox *>(w);
if(c)
c->setChecked(prop[i]);
}
w->setToolTip(m_Prop.tooltip);
QWidget *wrapperWidget = new QWidget();
QHBoxLayout *l = new QHBoxLayout();
l->setAlignment(Qt::AlignCenter);
l->addWidget(w);
l->setContentsMargins(QMargins(0, 0, 0, 0));
wrapperWidget->setLayout(l);
setCellWidget(i, 1, wrapperWidget);
}
for(int c = 0; c < m_Extras.size(); c++)
setCellWidget(i, c + firstExtraColumn(), makeCellWidget(i, m_Extras[c]));
}
// if we added any strings above the new item row was automatically
@@ -116,8 +171,8 @@ void OrderedListEditor::setItems(const QStringList &strings)
addNewItemRow();
resizeColumnToContents(0);
if(m_ButtonMode != ItemButton::None)
resizeColumnToContents(1);
for(int c = 0; c < m_Extras.size(); c++)
resizeColumnToContents(c + firstExtraColumn());
setUpdatesEnabled(true);
}
@@ -133,13 +188,30 @@ void OrderedListEditor::addNewItemRow()
item->setFlags(item->flags() & ~(Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled));
setItem(rowCount() - 1, 0, item);
if(m_ButtonMode != ItemButton::None)
{
QWidget *w = makeCellWidget(rowCount() - 1, OrderedItemExtras::CustomProp);
QCheckBox *c = qobject_cast<QCheckBox *>(w);
if(c)
c->setChecked(m_Prop.defaultValue);
w->setToolTip(m_Prop.tooltip);
QWidget *wrapperWidget = new QWidget();
QHBoxLayout *l = new QHBoxLayout();
l->setAlignment(Qt::AlignCenter);
l->addWidget(w);
l->setContentsMargins(QMargins(0, 0, 0, 0));
wrapperWidget->setLayout(l);
setCellWidget(rowCount() - 1, 1, wrapperWidget);
}
for(int c = 0; c < m_Extras.size(); c++)
{
item = new QTableWidgetItem(QString());
item->setFlags(item->flags() & ~(Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled));
setItem(rowCount() - 1, 1, item);
setItem(rowCount() - 1, c + firstExtraColumn(), item);
setCellWidget(rowCount() - 1, 1, makeButton());
setCellWidget(rowCount() - 1, c + firstExtraColumn(),
makeCellWidget(rowCount() - 1, m_Extras[c]));
}
}
@@ -157,6 +229,23 @@ QStringList OrderedListEditor::getItems()
return ret;
}
QList<bool> OrderedListEditor::getItemProps()
{
QList<bool> ret;
int count = rowCount();
// don't include the last 'new item' entry
if(allowAddition())
count--;
for(int i = 0; i < count; i++)
{
QCheckBox *c = cellWidget(i, 1)->findChild<QCheckBox *>();
ret << (c && c->isChecked());
}
return ret;
}
void OrderedListEditor::cellChanged(int row, int column)
{
// hack :(. Assume this will only be hit on single UI thread.
@@ -174,8 +263,8 @@ void OrderedListEditor::cellChanged(int row, int column)
{
// enable dragging
item(row, 0)->setFlags(item(row, 0)->flags() | (Qt::ItemIsDragEnabled | Qt::ItemIsDropEnabled));
if(m_ButtonMode != ItemButton::None)
delete takeItem(row, 1);
for(int c = 0; c < m_Extras.size(); c++)
delete takeItem(row, c + firstExtraColumn());
addNewItemRow();
}
@@ -189,34 +278,24 @@ void OrderedListEditor::cellChanged(int row, int column)
recurse = false;
}
void OrderedListEditor::buttonActivate()
void OrderedListEditor::extraClicked(int row, OrderedItemExtras extra)
{
QWidget *tool = qobject_cast<QWidget *>(QObject::sender());
if(tool)
if(extra == OrderedItemExtras::Delete)
{
for(int i = 0; i < rowCount(); i++)
{
QWidget *rowButton = cellWidget(i, 1);
if(rowButton == tool)
{
if(m_ButtonMode == ItemButton::Delete)
{
this->removeRow(i);
return;
}
QString sel;
if(m_ButtonMode == ItemButton::BrowseFolder)
sel = RDDialog::getExistingDirectory(this, tr("Browse for a folder"));
else if(m_ButtonMode == ItemButton::BrowseFile)
sel = RDDialog::getOpenFileName(this, tr("Browse for a file"));
if(!sel.isEmpty())
item(i, 0)->setText(sel);
}
}
// don't delete the last 'new item' entry
if(!allowAddition() || row != rowCount() - 1)
removeRow(row);
return;
}
QString sel;
if(extra == OrderedItemExtras::BrowseFolder)
sel = RDDialog::getExistingDirectory(this, tr("Browse for a folder"));
else if(extra == OrderedItemExtras::BrowseFile)
sel = RDDialog::getOpenFileName(this, tr("Browse for a file"));
if(!sel.isEmpty())
item(row, 0)->setText(sel);
}
void OrderedListEditor::keyPressEvent(QKeyEvent *event)
@@ -228,7 +307,11 @@ void OrderedListEditor::keyPressEvent(QKeyEvent *event)
row = selectionModel()->selectedIndexes()[0].row();
if(row >= 0)
removeRow(row);
{
// don't delete the last 'new item' entry
if(!allowAddition() || row != rowCount() - 1)
removeRow(row);
}
}
RDTableWidget::keyPress(event);
+35 -10
View File
@@ -28,24 +28,46 @@
class QToolButton;
enum class ItemButton
enum class OrderedItemExtras
{
None,
BrowseFolder,
BrowseFile,
Delete,
None = 0x0,
BrowseFolder = 0x1,
BrowseFile = 0x2,
Delete = 0x4,
CustomProp = 0x8,
};
constexpr inline OrderedItemExtras operator|(OrderedItemExtras a, OrderedItemExtras b)
{
return OrderedItemExtras(int(a) | int(b));
}
constexpr inline bool operator&(OrderedItemExtras a, OrderedItemExtras b)
{
return int(a) & int(b);
}
class OrderedListEditor : public RDTableWidget
{
Q_OBJECT
public:
explicit OrderedListEditor(const QString &itemName, ItemButton button, QWidget *parent = 0);
struct CustomProp
{
QString name, tooltip;
bool defaultValue;
bool valid() const { return !name.isEmpty(); }
};
explicit OrderedListEditor(const QString &itemName, OrderedItemExtras extras,
const CustomProp &prop = {}, QWidget *parent = 0);
~OrderedListEditor();
void setItems(const QStringList &strings);
void setItemsAndProp(const QStringList &strings, const QList<bool> &props);
void setItems(const QStringList &strings) { setItemsAndProp(strings, {}); }
QStringList getItems();
QList<bool> getItemProps();
bool allowAddition() { return m_allowAddition; }
void setAllowAddition(bool allow) { m_allowAddition = allow; }
@@ -53,15 +75,18 @@ public:
private slots:
// manual slots
void cellChanged(int row, int column);
void buttonActivate();
void extraClicked(int row, OrderedItemExtras extra);
private:
void keyPressEvent(QKeyEvent *e) override;
ItemButton m_ButtonMode;
int firstExtraColumn() { return m_Prop.valid() ? 2 : 1; }
QList<OrderedItemExtras> m_Extras;
CustomProp m_Prop;
bool m_allowAddition = true;
void addNewItemRow();
QToolButton *makeButton();
QWidget *makeCellWidget(int row, OrderedItemExtras extra);
};
+3 -3
View File
@@ -565,12 +565,12 @@ QWidget *SettingDelegate::createEditor(QWidget *parent, const QStyleOptionViewIt
listEditor.setWindowTitle(tr("Edit values of %1").arg(QString(settingName)));
listEditor.setWindowFlags(listEditor.windowFlags() & ~Qt::WindowContextHelpButtonHint);
ItemButton mode = ItemButton::None;
OrderedItemExtras mode = OrderedItemExtras::None;
if(QString(o->name).contains(lit("DirPath"), Qt::CaseSensitive))
mode = ItemButton::BrowseFolder;
mode = OrderedItemExtras::BrowseFolder;
else if(QString(o->name).contains(lit("Path"), Qt::CaseSensitive))
mode = ItemButton::BrowseFile;
mode = OrderedItemExtras::BrowseFile;
OrderedListEditor list(tr("Entry"), mode);
+42 -4
View File
@@ -618,7 +618,15 @@ void SettingsDialog::on_chooseSearchPaths_clicked()
listEditor.setWindowTitle(tr("Shader debug info search paths"));
listEditor.setWindowFlags(listEditor.windowFlags() & ~Qt::WindowContextHelpButtonHint);
OrderedListEditor list(tr("Search Path"), ItemButton::BrowseFolder);
OrderedListEditor::CustomProp customProp = {
tr("Recursive"),
tr("Recursively search through all subdirectories"
"under this path to find matching debug files"),
true,
};
OrderedListEditor list(tr("Search Path"),
OrderedItemExtras::BrowseFolder | OrderedItemExtras::Delete, customProp);
QVBoxLayout layout;
QDialogButtonBox okCancel;
@@ -630,21 +638,37 @@ void SettingsDialog::on_chooseSearchPaths_clicked()
QObject::connect(&okCancel, &QDialogButtonBox::rejected, &listEditor, &QDialog::reject);
listEditor.setLayout(&layout);
listEditor.resize(750, 500);
const SDObject *getPaths = RENDERDOC_GetConfigSetting("DXBC.Debug.SearchDirPaths");
QStringList items;
QList<bool> recursive;
for(const SDObject *c : *getPaths)
{
items << c->data.str;
recursive << true;
}
list.setItems(items);
const SDObject *getLimitedPaths =
RENDERDOC_GetConfigSetting("Replay.Shader.LimitedSearchDirPaths");
for(const SDObject *c : *getLimitedPaths)
{
int idx = items.indexOf(c->data.str);
if(idx >= 0)
recursive[idx] = false;
}
list.setItemsAndProp(items, recursive);
int res = RDDialog::show(&listEditor);
if(res)
{
items = list.getItems();
recursive = list.getItemProps();
SDObject *setPaths = RENDERDOC_SetConfigSetting("DXBC.Debug.SearchDirPaths");
@@ -654,6 +678,20 @@ void SettingsDialog::on_chooseSearchPaths_clicked()
for(int i = 0; i < items.size(); i++)
setPaths->AddAndOwnChild(makeSDString("$el"_lit, items[i]));
SDObject *setLimitedPaths = RENDERDOC_SetConfigSetting("Replay.Shader.LimitedSearchDirPaths");
QStringList limited;
for(int i = 0; i < recursive.count() && i < items.count(); i++)
if(recursive[i] == false)
limited << items[i];
setLimitedPaths->DeleteChildren();
setLimitedPaths->ReserveChildren(limited.size());
for(int i = 0; i < limited.size(); i++)
setLimitedPaths->AddAndOwnChild(makeSDString("$el"_lit, limited[i]));
RENDERDOC_SaveConfigSettings();
}
}
@@ -665,7 +703,7 @@ void SettingsDialog::on_chooseIgnores_clicked()
listEditor.setWindowTitle(tr("Ignored DLLs for callstack symbol resolution"));
listEditor.setWindowFlags(listEditor.windowFlags() & ~Qt::WindowContextHelpButtonHint);
OrderedListEditor list(tr("Ignored DLL"), ItemButton::Delete);
OrderedListEditor list(tr("Ignored DLL"), OrderedItemExtras::Delete);
list.setAllowAddition(false);
@@ -761,7 +799,7 @@ void SettingsDialog::on_TextureViewer_ChooseShaderDirectories_clicked()
listEditor.setWindowTitle(tr("Custom shaders search directories"));
listEditor.setWindowFlags(listEditor.windowFlags() & ~Qt::WindowContextHelpButtonHint);
OrderedListEditor list(tr("Shaders Directory"), ItemButton::BrowseFolder);
OrderedListEditor list(tr("Shaders Directory"), OrderedItemExtras::BrowseFolder);
QVBoxLayout layout;
QDialogButtonBox okCancel;
+4 -1
View File
@@ -63,7 +63,10 @@ RDOC_CONFIG(bool, Replay_Debug_SingleThreadedCompilation, false,
// this is declared centrally so it can be shared with any backend - the name is a misnomer but kept
// for backwards compatibility reasons.
RDOC_CONFIG(rdcarray<rdcstr>, DXBC_Debug_SearchDirPaths, {},
"Paths to search for separated shader debug PDBs.");
"Paths to search for separated shader debug PDBs, including all types of paths.");
RDOC_CONFIG(rdcarray<rdcstr>, Replay_Shader_LimitedSearchDirPaths, {},
"Companion array to DXBC.Debug.SearchDirPaths - listing paths which should not be "
"searched exhaustively but only used for simple lookups.");
void LogReplayOptions(const ReplayOptions &opts)
{
@@ -41,6 +41,7 @@
// this is extern so that it can be shared with vulkan
RDOC_EXTERN_CONFIG(rdcarray<rdcstr>, DXBC_Debug_SearchDirPaths);
RDOC_EXTERN_CONFIG(rdcarray<rdcstr>, Replay_Shader_LimitedSearchDirPaths);
namespace
{
@@ -93,9 +94,16 @@ void CacheSearchDirDebugPaths()
return;
rdcarray<rdcstr> searchPaths = DXBC_Debug_SearchDirPaths();
rdcarray<rdcstr> limitedSearchPaths = Replay_Shader_LimitedSearchDirPaths();
for(const rdcstr &base : searchPaths)
{
if(limitedSearchPaths.contains(base))
{
RDCLOG("Not recursing to enumerate files under %s", base.c_str());
continue;
}
size_t sz = cachedDebugFilesLookup.size();
CacheSearchDirDebugPaths(base);
RDCLOG("Recursively enumerated all files under %s, found %zu files", base.c_str(),