From 902fa4da52737d43e04c2a028658ad9840811a89 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sat, 4 Apr 2015 12:57:31 +0200 Subject: Add CiTrace recording support. This is exposed in the GUI as a new "CiTrace Recording" widget. Playback is implemented by a standalone 3DS homebrew application (which only runs reliably within Citra currently; on an actual 3DS it will often crash still). --- src/citra_qt/debugger/graphics_tracing.cpp | 123 +++++++++++++++++++++++++++++ 1 file changed, 123 insertions(+) create mode 100644 src/citra_qt/debugger/graphics_tracing.cpp (limited to 'src/citra_qt/debugger/graphics_tracing.cpp') diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp new file mode 100644 index 000000000..2e74193f5 --- /dev/null +++ b/src/citra_qt/debugger/graphics_tracing.cpp @@ -0,0 +1,123 @@ +// Copyright 2015 Citra Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include + +#include +#include +#include +#include +#include +#include + +#include "core/hw/gpu.h" +#include "video_core/pica.h" + +#include "nihstro/float24.h" + +#include "graphics_tracing.h" + +GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr debug_context, + QWidget* parent) + : BreakPointObserverDock(debug_context, tr("CiTrace Recorder"), parent) { + + setObjectName("CiTracing"); + + QPushButton* start_recording = new QPushButton(tr("Start Recording")); + QPushButton* stop_recording = new QPushButton(QIcon::fromTheme("document-save"), tr("Stop and Save")); + QPushButton* abort_recording = new QPushButton(tr("Abort Recording")); + + connect(this, SIGNAL(SetStartTracingButtonEnabled(bool)), start_recording, SLOT(setVisible(bool))); + connect(this, SIGNAL(SetStopTracingButtonEnabled(bool)), stop_recording, SLOT(setVisible(bool))); + connect(this, SIGNAL(SetAbortTracingButtonEnabled(bool)), abort_recording, SLOT(setVisible(bool))); + connect(start_recording, SIGNAL(clicked()), this, SLOT(StartRecording())); + connect(stop_recording, SIGNAL(clicked()), this, SLOT(StopRecording())); + connect(abort_recording, SIGNAL(clicked()), this, SLOT(AbortRecording())); + + stop_recording->setVisible(false); + abort_recording->setVisible(false); + + auto main_widget = new QWidget; + auto main_layout = new QVBoxLayout; + { + auto sub_layout = new QHBoxLayout; + sub_layout->addWidget(start_recording); + sub_layout->addWidget(stop_recording); + sub_layout->addWidget(abort_recording); + main_layout->addLayout(sub_layout); + } + main_widget->setLayout(main_layout); + setWidget(main_widget); + + // TODO: Make sure to have this widget disabled as soon as emulation is started! +} + +void GraphicsTracingWidget::StartRecording() { + auto context = context_weak.lock(); + if (!context) + return; + + auto shader_binary = Pica::g_state.vs.program_code; + auto swizzle_data = Pica::g_state.vs.swizzle_data; + + // Encode floating point numbers to 24-bit values + // TODO: Drop this explicit conversion once we store float24 values bit-correctly internally. + std::array, 96> vs_float_uniforms; + for (unsigned i = 0; i < 96; ++i) + for (unsigned comp = 0; comp < 3; ++comp) + vs_float_uniforms[i][comp] = nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32()); + + auto recorder = new CiTrace::Recorder((u32*)&GPU::g_regs, 0x700, nullptr, 0, (u32*)&Pica::g_state.regs, 0x300, + shader_binary.data(), shader_binary.size(), + swizzle_data.data(), swizzle_data.size(), + (u32*)vs_float_uniforms.data(), vs_float_uniforms.size() * 4, + nullptr, 0, nullptr, 0, nullptr, 0 // Geometry shader is not implemented yet, so submit dummy data for now + ); + context->recorder = std::shared_ptr(recorder); + + emit SetStartTracingButtonEnabled(false); + emit SetStopTracingButtonEnabled(true); + emit SetAbortTracingButtonEnabled(true); +} + +void GraphicsTracingWidget::StopRecording() { + auto context = context_weak.lock(); + if (!context) + return; + + QString filename = QFileDialog::getSaveFileName(this, tr("Save CiTrace"), "citrace.ctf", + tr("CiTrace File (*.ctf)")); + + if (filename.isEmpty()) { + // If the user canceled the dialog, keep recording + return; + } + + context->recorder->Finish(filename.toStdString()); + context->recorder = nullptr; + + emit SetStopTracingButtonEnabled(false); + emit SetAbortTracingButtonEnabled(false); + emit SetStartTracingButtonEnabled(true); +} + +void GraphicsTracingWidget::AbortRecording() { + auto context = context_weak.lock(); + if (!context) + return; + + context->recorder = nullptr; + + emit SetStopTracingButtonEnabled(false); + emit SetAbortTracingButtonEnabled(false); + emit SetStartTracingButtonEnabled(true); +} + +void GraphicsTracingWidget::OnBreakPointHit(Pica::DebugContext::Event event, void* data) { + widget()->setEnabled(true); +} + +void GraphicsTracingWidget::OnResumed() { + widget()->setEnabled(false); +} -- cgit v1.2.3 From 01a526e1c449f86bbb626dd83f3f6cf94c2d86d4 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Thu, 21 May 2015 02:12:59 +0200 Subject: citra-qt: Properly disable the CiTrace widget upon starting/stopping emulation. --- src/citra_qt/debugger/graphics_tracing.cpp | 33 ++++++++++++++++++++++++++++-- 1 file changed, 31 insertions(+), 2 deletions(-) (limited to 'src/citra_qt/debugger/graphics_tracing.cpp') diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp index 2e74193f5..eac405820 100644 --- a/src/citra_qt/debugger/graphics_tracing.cpp +++ b/src/citra_qt/debugger/graphics_tracing.cpp @@ -8,6 +8,7 @@ #include #include #include +#include #include #include @@ -49,8 +50,6 @@ GraphicsTracingWidget::GraphicsTracingWidget(std::shared_ptr } main_widget->setLayout(main_layout); setWidget(main_widget); - - // TODO: Make sure to have this widget disabled as soon as emulation is started! } void GraphicsTracingWidget::StartRecording() { @@ -121,3 +120,33 @@ void GraphicsTracingWidget::OnBreakPointHit(Pica::DebugContext::Event event, voi void GraphicsTracingWidget::OnResumed() { widget()->setEnabled(false); } + +void GraphicsTracingWidget::OnEmulationStarting(EmuThread* emu_thread) { + // Disable tracing starting/stopping until a GPU breakpoint is reached + widget()->setEnabled(false); +} + +void GraphicsTracingWidget::OnEmulationStopping() { + // TODO: Is it safe to access the context here? + + auto context = context_weak.lock(); + if (!context) + return; + + + if (context->recorder) { + auto reply = QMessageBox::question(this, tr("CiTracing still active"), + tr("A CiTrace is still being recorded. Do you want to save it? If not, all recorded data will be discarded."), + QMessageBox::Yes | QMessageBox::No, QMessageBox::Yes); + + if (reply == QMessageBox::Yes) { + StopRecording(); + } else { + AbortRecording(); + } + } + + // If the widget was disabled before, enable it now to allow starting + // tracing before starting the next emulation session + widget()->setEnabled(true); +} -- cgit v1.2.3 From fd62580985b2f2d8f65b940148211bedc8d08404 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Thu, 21 May 2015 02:51:28 +0200 Subject: CiTrace: Record default vertex attributes. --- src/citra_qt/debugger/graphics_tracing.cpp | 8 ++++++++ 1 file changed, 8 insertions(+) (limited to 'src/citra_qt/debugger/graphics_tracing.cpp') diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp index eac405820..3e88346c0 100644 --- a/src/citra_qt/debugger/graphics_tracing.cpp +++ b/src/citra_qt/debugger/graphics_tracing.cpp @@ -62,12 +62,20 @@ void GraphicsTracingWidget::StartRecording() { // Encode floating point numbers to 24-bit values // TODO: Drop this explicit conversion once we store float24 values bit-correctly internally. + std::array, 16> default_attributes; + for (unsigned i = 0; i < 16; ++i) { + for (unsigned comp = 0; comp < 3; ++comp) { + default_attributes[i][comp] = nihstro::to_float24(Pica::g_state.vs.default_attributes[i][comp].ToFloat32()); + } + } + std::array, 96> vs_float_uniforms; for (unsigned i = 0; i < 96; ++i) for (unsigned comp = 0; comp < 3; ++comp) vs_float_uniforms[i][comp] = nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32()); auto recorder = new CiTrace::Recorder((u32*)&GPU::g_regs, 0x700, nullptr, 0, (u32*)&Pica::g_state.regs, 0x300, + (u32*)default_attributes.data(), default_attributes.size() * 4, shader_binary.data(), shader_binary.size(), swizzle_data.data(), swizzle_data.size(), (u32*)vs_float_uniforms.data(), vs_float_uniforms.size() * 4, -- cgit v1.2.3 From dc8295298e414868f2733d4d87ac5cab11c387cb Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Wed, 27 May 2015 19:03:45 +0200 Subject: CiTrace: Record LCD registers. Cleanup recording code. --- src/citra_qt/debugger/graphics_tracing.cpp | 18 +++++++++++------- 1 file changed, 11 insertions(+), 7 deletions(-) (limited to 'src/citra_qt/debugger/graphics_tracing.cpp') diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp index 3e88346c0..654df12af 100644 --- a/src/citra_qt/debugger/graphics_tracing.cpp +++ b/src/citra_qt/debugger/graphics_tracing.cpp @@ -13,6 +13,8 @@ #include #include "core/hw/gpu.h" +#include "core/hw/lcd.h" + #include "video_core/pica.h" #include "nihstro/float24.h" @@ -62,23 +64,25 @@ void GraphicsTracingWidget::StartRecording() { // Encode floating point numbers to 24-bit values // TODO: Drop this explicit conversion once we store float24 values bit-correctly internally. - std::array, 16> default_attributes; + std::array default_attributes; for (unsigned i = 0; i < 16; ++i) { for (unsigned comp = 0; comp < 3; ++comp) { - default_attributes[i][comp] = nihstro::to_float24(Pica::g_state.vs.default_attributes[i][comp].ToFloat32()); + default_attributes[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.default_attributes[i][comp].ToFloat32()); } } - std::array, 96> vs_float_uniforms; + std::array vs_float_uniforms; for (unsigned i = 0; i < 96; ++i) for (unsigned comp = 0; comp < 3; ++comp) - vs_float_uniforms[i][comp] = nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32()); + vs_float_uniforms[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32()); - auto recorder = new CiTrace::Recorder((u32*)&GPU::g_regs, 0x700, nullptr, 0, (u32*)&Pica::g_state.regs, 0x300, - (u32*)default_attributes.data(), default_attributes.size() * 4, + auto recorder = new CiTrace::Recorder((u32*)&GPU::g_regs, sizeof(GPU::g_regs) / sizeof(u32), + (u32*)&LCD::g_regs, sizeof(LCD::g_regs) / sizeof(u32), + (u32*)&Pica::g_state.regs, sizeof(Pica::g_state.regs) / sizeof(u32), + default_attributes.data(), default_attributes.size(), shader_binary.data(), shader_binary.size(), swizzle_data.data(), swizzle_data.size(), - (u32*)vs_float_uniforms.data(), vs_float_uniforms.size() * 4, + vs_float_uniforms.data(), vs_float_uniforms.size(), nullptr, 0, nullptr, 0, nullptr, 0 // Geometry shader is not implemented yet, so submit dummy data for now ); context->recorder = std::shared_ptr(recorder); -- cgit v1.2.3 From 29abb11e8fbb6a78edf84496979ef946bf4e45a7 Mon Sep 17 00:00:00 2001 From: Tony Wasserka Date: Sun, 12 Jul 2015 03:20:19 +0200 Subject: CiTrace: Clean up initialization method. --- src/citra_qt/debugger/graphics_tracing.cpp | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) (limited to 'src/citra_qt/debugger/graphics_tracing.cpp') diff --git a/src/citra_qt/debugger/graphics_tracing.cpp b/src/citra_qt/debugger/graphics_tracing.cpp index 654df12af..3f20f149d 100644 --- a/src/citra_qt/debugger/graphics_tracing.cpp +++ b/src/citra_qt/debugger/graphics_tracing.cpp @@ -12,6 +12,8 @@ #include #include +#include + #include "core/hw/gpu.h" #include "core/hw/lcd.h" @@ -76,15 +78,19 @@ void GraphicsTracingWidget::StartRecording() { for (unsigned comp = 0; comp < 3; ++comp) vs_float_uniforms[4 * i + comp] = nihstro::to_float24(Pica::g_state.vs.uniforms.f[i][comp].ToFloat32()); - auto recorder = new CiTrace::Recorder((u32*)&GPU::g_regs, sizeof(GPU::g_regs) / sizeof(u32), - (u32*)&LCD::g_regs, sizeof(LCD::g_regs) / sizeof(u32), - (u32*)&Pica::g_state.regs, sizeof(Pica::g_state.regs) / sizeof(u32), - default_attributes.data(), default_attributes.size(), - shader_binary.data(), shader_binary.size(), - swizzle_data.data(), swizzle_data.size(), - vs_float_uniforms.data(), vs_float_uniforms.size(), - nullptr, 0, nullptr, 0, nullptr, 0 // Geometry shader is not implemented yet, so submit dummy data for now - ); + CiTrace::Recorder::InitialState state; + std::copy_n((u32*)&GPU::g_regs, sizeof(GPU::g_regs) / sizeof(u32), std::back_inserter(state.gpu_registers)); + std::copy_n((u32*)&LCD::g_regs, sizeof(LCD::g_regs) / sizeof(u32), std::back_inserter(state.lcd_registers)); + std::copy_n((u32*)&Pica::g_state.regs, sizeof(Pica::g_state.regs) / sizeof(u32), std::back_inserter(state.pica_registers)); + boost::copy(default_attributes, std::back_inserter(state.default_attributes)); + boost::copy(shader_binary, std::back_inserter(state.vs_program_binary)); + boost::copy(swizzle_data, std::back_inserter(state.vs_swizzle_data)); + boost::copy(vs_float_uniforms, std::back_inserter(state.vs_float_uniforms)); + //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_program_binary)); + //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_swizzle_data)); + //boost::copy(TODO: Not implemented, std::back_inserter(state.gs_float_uniforms)); + + auto recorder = new CiTrace::Recorder(state); context->recorder = std::shared_ptr(recorder); emit SetStartTracingButtonEnabled(false); -- cgit v1.2.3