From d2b2a3daefc14fd39d775f2ebe192823b24bd590 Mon Sep 17 00:00:00 2001 From: Grant Date: Thu, 19 Dec 2024 00:05:34 +0000 Subject: [PATCH] Adds gfxr capture to dive ui --- ui/main_window.cpp | 25 ++- ui/main_window.h | 5 +- ui/trace_window.cpp | 378 ++++++++++++++++++++++++++++++++++++++++++-- ui/trace_window.h | 39 +++++ 4 files changed, 432 insertions(+), 15 deletions(-) diff --git a/ui/main_window.cpp b/ui/main_window.cpp index 348b86a29..6cae8a5c8 100644 --- a/ui/main_window.cpp +++ b/ui/main_window.cpp @@ -645,6 +645,12 @@ void MainWindow::OnOpenFile() } } +//-------------------------------------------------------------------------------------------------- +void MainWindow::OnGFXRCapture() +{ + emit OnCapture(false, true); +} + // ================================================================================================= // OnNormalCapture is triggered for captures without counters. // ================================================================================================= @@ -689,8 +695,9 @@ void MainWindow::OnCaptureTrigger() } //-------------------------------------------------------------------------------------------------- -void MainWindow::OnCapture(bool is_capture_delayed) +void MainWindow::OnCapture(bool is_capture_delayed, bool is_gfxr_capture) { + m_trace_dig->useGfxrCapture(is_gfxr_capture); m_trace_dig->UpdateDeviceList(true); m_trace_dig->exec(); } @@ -927,6 +934,17 @@ void MainWindow::CreateActions() m_capture_action->setShortcut(QKeySequence("f5")); connect(m_capture_action, &QAction::triggered, this, &MainWindow::OnNormalCapture); + // PM4 Capture action + m_pm4_capture_action = new QAction(tr("PM4 Capture"), this); + m_pm4_capture_action->setStatusTip(tr("Capture a Dive trace (PM4)")); + m_pm4_capture_action->setShortcut(QKeySequence("f5")); + connect(m_pm4_capture_action, &QAction::triggered, this, &MainWindow::OnNormalCapture); + // GFXR Capture action + m_gfxr_capture_action = new QAction(tr("GFXR Capture"), this); + m_gfxr_capture_action->setStatusTip(tr("Capture a Dive trace (GFXR)")); + m_gfxr_capture_action->setShortcut(QKeySequence("f6")); + connect(m_gfxr_capture_action, &QAction::triggered, this, &MainWindow::OnGFXRCapture); + // Capture with delay action m_capture_delay_action = new QAction(tr("Capture with delay"), this); m_capture_delay_action->setStatusTip(tr("Capture a Dive trace after a delay")); @@ -960,7 +978,8 @@ void MainWindow::CreateMenus() m_file_menu->addAction(m_exit_action); m_capture_menu = menuBar()->addMenu(tr("&Capture")); - m_capture_menu->addAction(m_capture_action); + m_capture_menu->addAction(m_pm4_capture_action); + m_capture_menu->addAction(m_gfxr_capture_action); m_help_menu = menuBar()->addMenu(tr("&Help")); m_help_menu->addAction(m_shortcuts_action); @@ -984,7 +1003,7 @@ void MainWindow::CreateToolBars() QToolButton *m_capture_button = new QToolButton(); m_capture_button->setPopupMode(QToolButton::MenuButtonPopup); m_capture_button->setMenu(m_capture_menu); - m_capture_button->setDefaultAction(m_capture_action); + m_capture_button->setDefaultAction(m_pm4_capture_action); m_capture_button->setIcon(QIcon(":/images/capture.png")); m_file_tool_bar->addWidget(m_capture_button); diff --git a/ui/main_window.h b/ui/main_window.h index f2a2f80a4..6f4791426 100644 --- a/ui/main_window.h +++ b/ui/main_window.h @@ -71,7 +71,7 @@ class MainWindow : public QMainWindow void FileLoaded(); public slots: - void OnCapture(bool is_capture_delayed = false); + void OnCapture(bool is_capture_delayed = false, bool is_gfxr_capture = false); void OnSwitchToShaderTab(); private slots: @@ -79,6 +79,7 @@ private slots: void OnCommandViewModeComboBoxHover(const QString &); void OnSelectionChanged(const QModelIndex &index); void OnOpenFile(); + void OnGFXRCapture(); void OnNormalCapture(); void OnCaptureTrigger(); void OnExpandToLevel(); @@ -119,6 +120,8 @@ private slots: QAction *m_save_as_action; QAction *m_exit_action; QMenu *m_capture_menu; + QAction *m_gfxr_capture_action; + QAction *m_pm4_capture_action; QAction *m_capture_action; QAction *m_capture_delay_action; QAction *m_capture_setting_action; diff --git a/ui/trace_window.cpp b/ui/trace_window.cpp index f97432e66..eb71e4049 100644 --- a/ui/trace_window.cpp +++ b/ui/trace_window.cpp @@ -17,9 +17,13 @@ #include "trace_window.h" #include +#include +#include #include #include +#include #include +#include #include #include #include @@ -42,6 +46,7 @@ #include "absl/strings/str_split.h" #include "capture_service/android_application.h" #include "capture_service/client.h" +#include "capture_service/constants.h" #include "capture_service/device_mgr.h" namespace @@ -59,6 +64,10 @@ TraceDialog::TraceDialog(QWidget *parent) m_dev_label = new QLabel(tr("Devices:")); m_pkg_label = new QLabel(tr("Packages:")); m_app_type_label = new QLabel(tr("Application Type:")); + m_gfxr_capture_file_directory_label = new QLabel(tr("GFXR Capture File Directory Name:")); + m_gfxr_capture_file_local_directory_label = new QLabel(tr("Local GFXR Capture Save Location:")); + m_frame_num_label = new QLabel(tr("Frame number:")); + m_frame_range_label = new QLabel(tr("Frame range:")); m_dev_model = new QStandardItemModel(); m_pkg_model = new QStandardItemModel(); @@ -68,11 +77,36 @@ TraceDialog::TraceDialog(QWidget *parent) m_pkg_box = new QComboBox(); m_app_type_box = new QComboBox(); + m_frame_num_spin_box = new QSpinBox(); + m_frame_num_spin_box->setMinimum(1); + m_frame_num_spin_box->setMaximum(std::numeric_limits::max()); + m_frame_num_spin_box->setValue(1); + + m_frame_range_min_spin_box = new QSpinBox(); + m_frame_range_min_spin_box->setMinimum(1); + m_frame_range_min_spin_box->setMaximum(std::numeric_limits::max()); + m_frame_range_min_spin_box->setValue(1); + + m_frame_range_max_spin_box = new QSpinBox(); + m_frame_range_max_spin_box->setMinimum(2); + m_frame_range_max_spin_box->setMaximum(std::numeric_limits::max()); + m_frame_range_max_spin_box->setValue(2); + + m_single_frame_checkbox = new QCheckBox("Capture Single Frame"); + m_frame_range_checkbox = new QCheckBox("Capture Frame Range"); + m_run_time_checkbox = new QCheckBox("Capture During Runtime"); + m_button_layout = new QHBoxLayout(); - m_run_button = new QPushButton("&Start Application", this); + m_run_button = new QPushButton(kStart_Application, this); m_run_button->setEnabled(false); m_capture_button = new QPushButton("&Trace", this); m_capture_button->setEnabled(false); + m_gfxr_capture_button = new QPushButton(kStart_Gfxr_Runtime_Capture, this); + m_gfxr_capture_button->setEnabled(false); + m_gfxr_capture_button->hide(); + m_gfxr_retrieve_button = new QPushButton(kRetrieve_Gfxr_Capture, this); + m_gfxr_retrieve_button->setEnabled(false); + m_gfxr_retrieve_button->hide(); m_dev_refresh_button = new QPushButton("&Refresh", this); m_pkg_refresh_button = new QPushButton("&Refresh", this); @@ -148,14 +182,63 @@ TraceDialog::TraceDialog(QWidget *parent) m_type_layout->addWidget(m_app_type_label); m_type_layout->addWidget(m_app_type_box); + m_gfxr_capture_file_directory_layout = new QHBoxLayout(); + m_gfxr_capture_file_directory_input_box = new QLineEdit(); + m_gfxr_capture_file_directory_input_box->setPlaceholderText( + "Input a name for the capture directory"); + m_gfxr_capture_file_directory_layout->addWidget(m_gfxr_capture_file_directory_label); + m_gfxr_capture_file_directory_layout->addWidget(m_gfxr_capture_file_directory_input_box); + m_gfxr_capture_file_directory_label->hide(); + m_gfxr_capture_file_directory_input_box->hide(); + + m_gfxr_capture_file_local_directory_layout = new QHBoxLayout(); + m_gfxr_capture_file_local_directory_input_box = new QLineEdit(); + m_gfxr_capture_file_local_directory_input_box->setPlaceholderText( + "Input the location to save the directory to"); + m_gfxr_capture_file_local_directory_layout->addWidget( + m_gfxr_capture_file_local_directory_label); + m_gfxr_capture_file_local_directory_layout->addWidget( + m_gfxr_capture_file_local_directory_input_box); + m_gfxr_capture_file_local_directory_label->hide(); + m_gfxr_capture_file_local_directory_input_box->hide(); + + m_frame_type_layout = new QHBoxLayout(); + m_frame_type_layout->addWidget(m_single_frame_checkbox); + m_single_frame_checkbox->setCheckState(Qt::Unchecked); + m_single_frame_checkbox->hide(); + m_frame_type_layout->addWidget(m_frame_range_checkbox); + m_frame_range_checkbox->setCheckState(Qt::Unchecked); + m_frame_range_checkbox->hide(); + m_frame_type_layout->addWidget(m_run_time_checkbox); + m_run_time_checkbox->setCheckState(Qt::Checked); + m_run_time_checkbox->hide(); + + m_frames_layout = new QHBoxLayout(); + m_frames_layout->addWidget(m_frame_num_label); + m_frames_layout->addWidget(m_frame_num_spin_box); + m_frame_num_label->hide(); + m_frame_num_spin_box->hide(); + m_frames_layout->addWidget(m_frame_range_label); + m_frames_layout->addWidget(m_frame_range_min_spin_box); + m_frames_layout->addWidget(m_frame_range_max_spin_box); + m_frame_range_label->hide(); + m_frame_range_min_spin_box->hide(); + m_frame_range_max_spin_box->hide(); + m_button_layout->addWidget(m_run_button); m_button_layout->addWidget(m_capture_button); + m_button_layout->addWidget(m_gfxr_capture_button); + m_button_layout->addWidget(m_gfxr_retrieve_button); m_main_layout->addLayout(m_capture_layout); m_main_layout->addLayout(m_cmd_layout); m_main_layout->addLayout(m_pkg_filter_layout); m_main_layout->addLayout(m_pkg_layout); + m_main_layout->addLayout(m_gfxr_capture_file_directory_layout); + m_main_layout->addLayout(m_gfxr_capture_file_local_directory_layout); m_main_layout->addLayout(m_args_layout); + m_main_layout->addLayout(m_frame_type_layout); + m_main_layout->addLayout(m_frames_layout); m_main_layout->addLayout(m_type_layout); @@ -176,6 +259,14 @@ TraceDialog::TraceDialog(QWidget *parent) &QSortFilterProxyModel::setFilterFixedString); QObject::connect(m_run_button, &QPushButton::clicked, this, &TraceDialog::OnStartClicked); QObject::connect(m_capture_button, &QPushButton::clicked, this, &TraceDialog::OnTraceClicked); + QObject::connect(m_gfxr_capture_button, + &QPushButton::clicked, + this, + &TraceDialog::OnGfxrCaptureClicked); + QObject::connect(m_gfxr_retrieve_button, + &QPushButton::clicked, + this, + &TraceDialog::OnGfxrRetrieveClicked); QObject::connect(m_dev_refresh_button, &QPushButton::clicked, @@ -195,6 +286,18 @@ TraceDialog::TraceDialog(QWidget *parent) &PackageFilter::filtersApplied, this, &TraceDialog::OnPackageListFilterApplied); + QObject::connect(m_single_frame_checkbox, + &QCheckBox::stateChanged, + this, + &TraceDialog::OnGfxrCaptureFrameTypeSelection); + QObject::connect(m_frame_range_checkbox, + &QCheckBox::stateChanged, + this, + &TraceDialog::OnGfxrCaptureFrameTypeSelection); + QObject::connect(m_run_time_checkbox, + &QCheckBox::stateChanged, + this, + &TraceDialog::OnGfxrCaptureFrameTypeSelection); } TraceDialog::~TraceDialog() @@ -333,15 +436,57 @@ bool TraceDialog::StartPackage(Dive::AndroidDevice *device, const std::string &a absl::Status ret; qDebug() << "Start app on dev: " << m_cur_dev.c_str() << ", package: " << m_cur_pkg.c_str() << ", type: " << app_type.c_str() << ", args: " << m_command_args.c_str(); + + std::string gfxr_capture_frames = ""; + std::string device_architecture = ""; + if (m_gfxr_capture) + { + auto retrieve_device_architecture = device->Adb() + .RunAndGetResult("shell getprop ro.product.cpu.abi", + true); + device_architecture = retrieve_device_architecture.value_or(""); + + if (m_single_frame_checkbox->isChecked()) + { + gfxr_capture_frames = std::to_string(m_frame_num_spin_box->value()); + m_run_button->setText(kStart_Application); + } + else if (m_frame_range_checkbox->isChecked()) + { + gfxr_capture_frames = std::to_string(m_frame_range_min_spin_box->value()) + "-" + + std::to_string(m_frame_range_max_spin_box->value()); + m_run_button->setText(kStart_Application); + } + else + { + gfxr_capture_frames = Dive::kGfxrRuntimeCapture; + m_gfxr_capture_button->setText(kStart_Gfxr_Runtime_Capture); + m_gfxr_capture_button->setEnabled(true); + } + + if (m_gfxr_capture_file_directory_input_box->text() == "") + { + m_gfxr_capture_file_directory_input_box->setText("gfxr_capture"); + } + } + if (app_type == "OpenXR APK") { - ret = device - ->SetupApp(m_cur_pkg, Dive::ApplicationType::OPENXR_APK, m_command_args, "", "", ""); + ret = device->SetupApp(m_cur_pkg, + Dive::ApplicationType::OPENXR_APK, + m_command_args, + device_architecture, + m_gfxr_capture_file_directory_input_box->text().toStdString(), + gfxr_capture_frames); } else if (app_type == "Vulkan APK") { - ret = device - ->SetupApp(m_cur_pkg, Dive::ApplicationType::VULKAN_APK, m_command_args, "", "", ""); + ret = device->SetupApp(m_cur_pkg, + Dive::ApplicationType::VULKAN_APK, + m_command_args, + device_architecture, + m_gfxr_capture_file_directory_input_box->text().toStdString(), + gfxr_capture_frames); } else if (app_type == "Command Line Application") { @@ -392,8 +537,19 @@ bool TraceDialog::StartPackage(Dive::AndroidDevice *device, const std::string &a if (cur_app) { m_run_button->setDisabled(false); - m_run_button->setText("&Stop"); - m_capture_button->setEnabled(true); + if (m_gfxr_capture) + { + if (gfxr_capture_frames == Dive::kGfxrRuntimeCapture) + { + m_run_button->setText("&Stop Application"); + m_gfxr_capture_button->setEnabled(true); + } + } + else + { + m_run_button->setText("&Stop"); + m_capture_button->setEnabled(true); + } } return true; } @@ -410,6 +566,7 @@ void TraceDialog::OnStartClicked() ShowErrorMessage(err_msg); return; } + device->EnableGfxr(m_gfxr_capture); absl::Status ret = device->SetupDevice(); if (!ret.ok()) { @@ -426,20 +583,54 @@ void TraceDialog::OnStartClicked() } std::string ty_str = kAppTypes[ty]; - if (m_run_button->text() == QString("&Start Application")) + if (m_run_button->text() == QString(kStart_Application)) { + if (m_gfxr_capture) + { + if (m_single_frame_checkbox->isChecked() || m_frame_range_checkbox->isChecked()) + { + m_gfxr_retrieve_button->setEnabled(true); + } + + std::string + err_msg = "Do not stop the application for single frame or frame range captures. The " + "application will quit once the capture is complete. Premature termination " + "may affect the resulting capture file."; + qDebug() << err_msg.c_str(); + ShowErrorMessage(err_msg); + } + if (!StartPackage(device, ty_str)) { m_run_button->setDisabled(false); - m_run_button->setText("&Start Application"); + m_run_button->setText(kStart_Application); } } else { qDebug() << "Stop package " << m_cur_pkg.c_str(); + + if (m_gfxr_capture) + { + if (m_gfxr_capture_button->text() == kStop_Gfxr_Runtime_Capture && + m_gfxr_capture_button->isEnabled()) + { + std::string err_msg = "Failed to stop application. Gfxr capture in process. Please " + "stop the capture before stopping the application."; + qDebug() << err_msg.c_str(); + ShowErrorMessage(err_msg); + return; + } + + m_gfxr_capture_button->setEnabled(false); + } + else + { + m_capture_button->setEnabled(false); + } + device->StopApp().IgnoreError(); - m_run_button->setText("&Start Application"); - m_capture_button->setEnabled(false); + m_run_button->setText(kStart_Application); } } @@ -680,3 +871,168 @@ void TraceDialog::OnPackageListFilterApplied(QSet filters) m_pkg_filter_label->hide(); m_pkg_filter->hide(); } + +void TraceDialog::OnGfxrCaptureFrameTypeSelection(int state) +{ + QCheckBox *senderCheckbox = qobject_cast(sender()); + if (state == Qt::Checked) + { + if (senderCheckbox == m_single_frame_checkbox) + { + m_frame_range_checkbox->setCheckState(Qt::Unchecked); + m_run_time_checkbox->setCheckState(Qt::Unchecked); + m_frame_num_label->show(); + m_frame_num_spin_box->show(); + m_frame_range_label->hide(); + m_frame_range_min_spin_box->hide(); + m_frame_range_max_spin_box->hide(); + } + else if (senderCheckbox == m_frame_range_checkbox) + { + m_single_frame_checkbox->setCheckState(Qt::Unchecked); + m_run_time_checkbox->setCheckState(Qt::Unchecked); + m_frame_range_label->show(); + m_frame_range_min_spin_box->show(); + m_frame_range_max_spin_box->show(); + m_frame_num_label->hide(); + m_frame_num_spin_box->hide(); + } + else + { + m_single_frame_checkbox->setCheckState(Qt::Unchecked); + m_frame_range_checkbox->setCheckState(Qt::Unchecked); + m_frame_range_label->hide(); + m_frame_range_min_spin_box->hide(); + m_frame_range_max_spin_box->hide(); + m_frame_num_label->hide(); + m_frame_num_spin_box->hide(); + } + } + else + { + if (!m_single_frame_checkbox->isChecked() && !m_frame_range_checkbox->isChecked() && + !m_run_time_checkbox->isChecked()) + { + senderCheckbox->setChecked(true); + } + } +} + +void TraceDialog::showGfxrFields() +{ + m_single_frame_checkbox->show(); + m_frame_range_checkbox->show(); + m_run_time_checkbox->show(); + m_args_label->hide(); + m_args_input_box->hide(); + m_capture_button->hide(); + m_gfxr_capture_button->show(); + m_gfxr_retrieve_button->show(); + m_gfxr_capture_file_directory_label->show(); + m_gfxr_capture_file_directory_input_box->show(); + m_gfxr_capture_file_local_directory_label->show(); + m_gfxr_capture_file_local_directory_input_box->show(); +} + +void TraceDialog::hideGfxrFields() +{ + m_args_label->show(); + m_args_input_box->show(); + m_capture_button->show(); + m_gfxr_capture_button->hide(); + m_gfxr_retrieve_button->hide(); + m_gfxr_capture_file_directory_label->hide(); + m_gfxr_capture_file_directory_input_box->hide(); + m_gfxr_capture_file_local_directory_label->hide(); + m_gfxr_capture_file_local_directory_input_box->hide(); + m_single_frame_checkbox->hide(); + m_frame_range_checkbox->hide(); + m_run_time_checkbox->hide(); + m_frame_num_label->hide(); + m_frame_num_spin_box->hide(); + m_frame_range_label->hide(); + m_frame_range_min_spin_box->hide(); + m_frame_range_max_spin_box->hide(); +} + +void TraceDialog::useGfxrCapture(bool enable) +{ + if (enable) + { + showGfxrFields(); + } + else + { + hideGfxrFields(); + } + + m_gfxr_capture = enable; +} + +void TraceDialog::RetrieveGfxrCapture(Dive::AndroidDevice *device) +{ + std::string message = "Retrieving GFXR capture from device and saving locally..."; + qDebug() << message.c_str(); + ShowErrorMessage(message); + + if (m_gfxr_capture_file_local_directory_input_box->text() == "") + { + m_gfxr_capture_file_local_directory_input_box->setText("."); + } + + std::string capture_directory = Dive::kGfxrCaptureDirectory + + m_gfxr_capture_file_directory_input_box->text().toStdString(); + auto r = device + ->RetrieveTrace(capture_directory, + m_gfxr_capture_file_local_directory_input_box->text().toStdString()); + + message = "GFXR capture retrieved from device and saved locally!"; + qDebug() << message.c_str(); + ShowErrorMessage(message); +} + +void TraceDialog::OnGfxrCaptureClicked() +{ + auto device = Dive::GetDeviceManager().GetDevice(); + absl::Status ret; + if (m_gfxr_capture_button->text() == kStop_Gfxr_Runtime_Capture) + { + ret = device->Adb().Run("shell setprop debug.gfxrecon.capture_android_trigger false"); + if (!ret.ok()) + { + std::string err_msg = absl::StrCat("Failed to stop runtime gfxr capture ", + m_cur_pkg, + " error: ", + ret.message()); + qDebug() << err_msg.c_str(); + ShowErrorMessage(err_msg); + return; + } + + m_gfxr_capture_button->setText(kStart_Gfxr_Runtime_Capture); + m_gfxr_retrieve_button->setEnabled(true); + } + else if (m_gfxr_capture_button->text() == kStart_Gfxr_Runtime_Capture) + { + ret = device->Adb().Run("shell setprop debug.gfxrecon.capture_android_trigger true"); + if (!ret.ok()) + { + std::string err_msg = absl::StrCat("Failed to start runtime gfxr capture ", + m_cur_pkg, + " error: ", + ret.message()); + qDebug() << err_msg.c_str(); + ShowErrorMessage(err_msg); + return; + } + m_gfxr_capture_button->setText(kStop_Gfxr_Runtime_Capture); + } +} + +void TraceDialog::OnGfxrRetrieveClicked() +{ + auto device = Dive::GetDeviceManager().GetDevice(); + RetrieveGfxrCapture(device); + m_gfxr_retrieve_button->setEnabled(false); + m_gfxr_capture_button->setEnabled(false); +} diff --git a/ui/trace_window.h b/ui/trace_window.h index 94cee0441..9778ce99e 100644 --- a/ui/trace_window.h +++ b/ui/trace_window.h @@ -1,3 +1,4 @@ + /* Copyright 2023 Google LLC @@ -14,6 +15,7 @@ limitations under the License. */ +#include #include #include #include @@ -33,6 +35,8 @@ class QComboBox; class QStandardItemModel; class QProgressDialog; class QLineEdit; +class QSpinBox; +class QCheckBox; class TraceWorker : public QThread { @@ -80,6 +84,9 @@ class TraceDialog : public QDialog void UpdateDeviceList(bool isInitialized); void UpdatePackageList(); void Cleanup() { Dive::GetDeviceManager().RemoveDevice(); } + void showGfxrFields(); + void hideGfxrFields(); + void useGfxrCapture(bool enable); private slots: void OnDeviceSelected(const QString &); @@ -93,12 +100,21 @@ private slots: void OnInputArgs(const QString &); void OnPackageListFilter(); void OnPackageListFilterApplied(QSet filters); + void OnGfxrCaptureFrameTypeSelection(int state); + void OnGfxrCaptureClicked(); + void OnGfxrRetrieveClicked(); signals: void TraceAvailable(const QString &); private: bool StartPackage(Dive::AndroidDevice *device, const std::string &app_type); + void RetrieveGfxrCapture(Dive::AndroidDevice *device); + + const QString kStart_Application = "&Start Application"; + const QString kStart_Gfxr_Runtime_Capture = "&Start GFXR Capture"; + const QString kStop_Gfxr_Runtime_Capture = "&Stop GFXR Capture"; + const QString kRetrieve_Gfxr_Capture = "&Retrieve GFXR Capture"; QHBoxLayout *m_capture_layout; QLabel *m_dev_label; @@ -124,6 +140,8 @@ private slots: QPushButton *m_capture_button; QPushButton *m_run_button; + QPushButton *m_gfxr_capture_button; + QPushButton *m_gfxr_retrieve_button; QHBoxLayout *m_button_layout; QHBoxLayout *m_cmd_layout; @@ -135,6 +153,26 @@ private slots: QLabel *m_args_label; QLineEdit *m_args_input_box; + QHBoxLayout *m_gfxr_capture_file_directory_layout; + QLabel *m_gfxr_capture_file_directory_label; + QLineEdit *m_gfxr_capture_file_directory_input_box; + + QHBoxLayout *m_gfxr_capture_file_local_directory_layout; + QLabel *m_gfxr_capture_file_local_directory_label; + QLineEdit *m_gfxr_capture_file_local_directory_input_box; + + QHBoxLayout *m_frame_type_layout; + QCheckBox *m_single_frame_checkbox; + QCheckBox *m_frame_range_checkbox; + QCheckBox *m_run_time_checkbox; + + QHBoxLayout *m_frames_layout; + QLabel *m_frame_num_label; + QLabel *m_frame_range_label; + QSpinBox *m_frame_num_spin_box; + QSpinBox *m_frame_range_min_spin_box; + QSpinBox *m_frame_range_max_spin_box; + QVBoxLayout *m_main_layout; std::vector m_devices; std::string m_cur_dev; @@ -142,4 +180,5 @@ private slots: std::string m_cur_pkg; std::string m_executable; std::string m_command_args; + bool m_gfxr_capture; };