support saving GPU captures to a file

This commit is contained in:
Samuliak 2025-01-04 13:54:07 +01:00
parent 1d8806cf06
commit 9a61e81715
No known key found for this signature in database
6 changed files with 69 additions and 0 deletions

View File

@ -67,6 +67,18 @@ inline NS::String* ToNSString(const std::string& str)
return ToNSString(str.c_str());
}
// Cast from const char* to NS::URL*
inline NS::URL* ToNSURL(const char* str)
{
return NS::URL::fileURLWithPath(ToNSString(str));
}
// Cast from std::string to NS::URL*
inline NS::URL* ToNSURL(const std::string& str)
{
return ToNSURL(str.c_str());
}
inline NS::String* GetLabel(const std::string& label, const void* identifier)
{
return ToNSString(label + " (" + std::to_string(reinterpret_cast<uintptr_t>(identifier)) + ")");

View File

@ -20,6 +20,9 @@
#include "Cemu/Logging/CemuLogging.h"
#include "Cafe/HW/Latte/Core/FetchShader.h"
#include "Cafe/HW/Latte/Core/LatteConst.h"
#include "Common/precompiled.h"
#include "HW/Latte/Renderer/Metal/MetalCommon.h"
#include "Metal/MTLCaptureManager.hpp"
#include "config/CemuConfig.h"
#include "gui/guiWrapper.h"
@ -2179,6 +2182,38 @@ void MetalRenderer::StartCapture()
auto desc = MTL::CaptureDescriptor::alloc()->init();
desc->setCaptureObject(m_device);
// Check if a debugger with support for GPU capture is attached
if (captureManager->supportsDestination(MTL::CaptureDestinationDeveloperTools))
{
desc->setDestination(MTL::CaptureDestinationDeveloperTools);
}
else
{
if (GetConfig().gpu_capture_dir.GetValue().empty())
{
cemuLog_log(LogType::Force, "No GPU capture directory specified, cannot do a GPU capture");
return;
}
// Check if the GPU trace document destination is available
if (!captureManager->supportsDestination(MTL::CaptureDestinationGPUTraceDocument))
{
cemuLog_log(LogType::Force, "GPU trace document destination is not available, cannot do a GPU capture");
return;
}
// Get current date and time as a string
auto now = std::chrono::system_clock::now();
std::time_t now_time = std::chrono::system_clock::to_time_t(now);
std::ostringstream oss;
oss << std::put_time(std::localtime(&now_time), "%Y-%m-%d_%H-%M-%S");
std::string now_str = oss.str();
std::string capturePath = fmt::format("{}/cemu_{}.gputrace", GetConfig().gpu_capture_dir.GetValue(), now_str);
desc->setDestination(MTL::CaptureDestinationGPUTraceDocument);
desc->setOutputURL(ToNSURL(capturePath));
}
NS::Error* error = nullptr;
captureManager->startCapture(desc, &error);
if (error)

View File

@ -336,6 +336,7 @@ void CemuConfig::Load(XMLConfigParser& parser)
crash_dump = debug.get("CrashDumpUnix", crash_dump);
#endif
gdb_port = debug.get("GDBPort", 1337);
gpu_capture_dir = debug.get("GPUCaptureDir", "");
// input
auto input = parser.get("Input");
@ -537,6 +538,7 @@ void CemuConfig::Save(XMLConfigParser& parser)
debug.set("CrashDumpUnix", crash_dump.GetValue());
#endif
debug.set("GDBPort", gdb_port);
debug.set("GPUCaptureDir", gpu_capture_dir.GetValue());
// input
auto input = config.set("Input");

View File

@ -526,6 +526,7 @@ struct CemuConfig
// debug
ConfigValueBounds<CrashDump> crash_dump{ CrashDump::Disabled };
ConfigValue<uint16> gdb_port{ 1337 };
ConfigValue<std::string> gpu_capture_dir{};
void Load(XMLConfigParser& parser);
void Save(XMLConfigParser& parser);

View File

@ -10,6 +10,7 @@
#include <wx/collpane.h>
#include <wx/clrpicker.h>
#include <wx/cshelp.h>
#include <wx/textctrl.h>
#include <wx/textdlg.h>
#include <wx/hyperlink.h>
@ -892,6 +893,21 @@ wxPanel* GeneralSettings2::AddDebugPage(wxNotebook* notebook)
debug_panel_sizer->Add(debug_row, 0, wxALL | wxEXPAND, 5);
}
{
auto* debug_row = new wxFlexGridSizer(0, 2, 0, 0);
debug_row->SetFlexibleDirection(wxBOTH);
debug_row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
debug_row->Add(new wxStaticText(panel, wxID_ANY, _("GPU capture save directory"), wxDefaultPosition, wxDefaultSize, 0), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
m_gpu_capture_dir = new wxTextCtrl(panel, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, wxTE_DONTWRAP);
m_gpu_capture_dir->SetMinSize(wxSize(150, -1));
m_gpu_capture_dir->SetToolTip(_("Cemu will save the GPU captures done by selecting Debug -> GPU capture in the menu bar in this directory. If a debugger with support for GPU captures (like Xcode) is attached, the capture will be opened in that debugger instead."));
debug_row->Add(m_gpu_capture_dir, 0, wxALL | wxEXPAND, 5);
debug_panel_sizer->Add(debug_row, 0, wxALL | wxEXPAND, 5);
}
panel->SetSizerAndFit(debug_panel_sizer);
return panel;
@ -1101,6 +1117,7 @@ void GeneralSettings2::StoreConfig()
// debug
config.crash_dump = (CrashDump)m_crash_dump->GetSelection();
config.gdb_port = m_gdb_port->GetValue();
config.gpu_capture_dir = m_gpu_capture_dir->GetValue().utf8_string();
g_config.Save();
}
@ -1794,6 +1811,7 @@ void GeneralSettings2::ApplyConfig()
// debug
m_crash_dump->SetSelection((int)config.crash_dump.GetValue());
m_gdb_port->SetValue(config.gdb_port.GetValue());
m_gpu_capture_dir->SetValue(wxHelper::FromUtf8(config.gpu_capture_dir.GetValue()));
}
void GeneralSettings2::OnAudioAPISelected(wxCommandEvent& event)

View File

@ -78,6 +78,7 @@ private:
// Debug
wxChoice* m_crash_dump;
wxSpinCtrl* m_gdb_port;
wxTextCtrl* m_gpu_capture_dir;
void OnAccountCreate(wxCommandEvent& event);
void OnAccountDelete(wxCommandEvent& event);