/****************************************************************************** * The MIT License (MIT) * * Copyright (c) 2019-2026 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 "ReplayOptionsSelector.h" #include #include "Code/QRDUtils.h" #include "ui_ReplayOptionsSelector.h" ReplayOptionsSelector::ReplayOptionsSelector(ICaptureContext &ctx, bool actions, QWidget *parent) : m_Ctx(ctx), QWidget(parent), ui(new Ui::ReplayOptionsSelector) { ui->setupUi(this); if(!actions) { ui->captureFileFrame->hide(); ui->buttonsFrame->hide(); } QObject::connect(ui->open, &QPushButton::clicked, this, &ReplayOptionsSelector::opened); QObject::connect(ui->cancel, &QPushButton::clicked, this, &ReplayOptionsSelector::canceled); // try to use the remote capture access to enumerate remote GPUs, but if it's not available open a // local capture access ICaptureFile *dummy = RENDERDOC_OpenCaptureFile(); ICaptureAccess *capture = m_Ctx.Replay().GetCaptureAccess(); if(!capture) capture = dummy; // fetch available GPUs m_GPUs = capture->GetAvailableGPUs(); dummy->Shutdown(); // this is always available ui->gpuOverride->addItem(tr("Default GPU selection")); for(const GPUDevice &dev : m_GPUs) { QString apis; for(size_t i = 0; i < dev.apis.size(); i++) { apis += ToQStr(dev.apis[i]); if(i + 1 < dev.apis.size()) apis += lit(", "); } QString vendor = ToQStr(dev.vendor); QString name = dev.name; // if the name already contains the vendor, don't display it twice if(name.contains(vendor, Qt::CaseInsensitive)) ui->gpuOverride->addItem(QFormatStr("%1 [%2]").arg(name).arg(apis)); else ui->gpuOverride->addItem(QFormatStr("%1 %2 [%3]").arg(vendor).arg(name).arg(apis)); } for(ReplayOptimisationLevel level : values()) ui->replayOptimisation->addItem(ToQStr(level)); // set default options { const ReplayOptions &opts = m_Ctx.Config().DefaultReplayOptions; ui->replayAPIValidation->setChecked(opts.apiValidation); ui->replayOptimisation->setCurrentIndex((int)opts.optimisation); int bestIndex = -1; if(opts.forceGPUVendor == GPUVendor::Unknown && opts.forceGPUDeviceID == 0 && opts.forceGPUDriverName.empty()) { // no forcing active bestIndex = -1; } else { // if the options are trying to force a GPU, pick the closest one we can find and use it bestIndex = 0; for(int i = 0; i < m_GPUs.count(); i++) { // if this is a closer vendor match than the current best, use it if(opts.forceGPUVendor == m_GPUs[i].vendor && opts.forceGPUVendor != m_GPUs[bestIndex].vendor) { bestIndex = i; continue; } else if(m_GPUs[i].vendor != opts.forceGPUVendor) { continue; } // if this is a closer device match, use it if(opts.forceGPUDeviceID == m_GPUs[i].deviceID && opts.forceGPUDeviceID != m_GPUs[bestIndex].deviceID) { bestIndex = i; continue; } else if(m_GPUs[i].deviceID != opts.forceGPUDeviceID) { continue; } // if this is a closer driver match, use it if(opts.forceGPUDriverName == m_GPUs[i].driver && opts.forceGPUDriverName != m_GPUs[bestIndex].driver) { bestIndex = i; continue; } } } if(bestIndex >= 0 && bestIndex < m_GPUs.count()) ui->gpuOverride->setCurrentIndex(bestIndex + 1); else ui->gpuOverride->setCurrentIndex(0); } // add recent capture files as options in the dropdown for(rdcstr file : m_Ctx.Config().RecentCaptureFiles) ui->captureFile->insertItem(0, file); // default to the last opened file ui->captureFile->setCurrentIndex(0); } ReplayOptionsSelector::~ReplayOptionsSelector() { delete ui; } QString ReplayOptionsSelector::filename() { return ui->captureFile->currentText(); } ReplayOptions ReplayOptionsSelector::options() { ReplayOptions opts; opts.apiValidation = ui->replayAPIValidation->isChecked(); opts.optimisation = (ReplayOptimisationLevel)ui->replayOptimisation->currentIndex(); int gpuChoice = ui->gpuOverride->currentIndex(); if(gpuChoice > 0 && gpuChoice - 1 < m_GPUs.count()) { const GPUDevice &gpu = m_GPUs[gpuChoice - 1]; opts.forceGPUVendor = gpu.vendor; opts.forceGPUDeviceID = gpu.deviceID; opts.forceGPUDriverName = gpu.driver; } return opts; } void ReplayOptionsSelector::on_saveDefaults_clicked() { m_Ctx.Config().DefaultReplayOptions = options(); m_Ctx.Config().Save(); } void ReplayOptionsSelector::on_captureFileBrowse_clicked() { QString initDir; QFileInfo f(ui->captureFile->currentText()); QDir dir = f.dir(); if(f.isAbsolute() && dir.exists()) { initDir = dir.absolutePath(); } else if(!m_Ctx.Config().LastCaptureFilePath.isEmpty()) { initDir = m_Ctx.Config().LastCaptureFilePath; } QString filename = RDDialog::getOpenFileName(this, tr("Select capture to open"), initDir, tr("Capture Files (*.rdc);;All Files (*)")); if(!filename.isEmpty()) ui->captureFile->setCurrentText(filename); } void ReplayOptionsSelector::keyPressEvent(QKeyEvent *e) { if(e->key() == Qt::Key_Return || e->key() == Qt::Key_Enter) { opened(); return; } QWidget::keyPressEvent(e); }