mirror of
https://github.com/cemu-project/Cemu.git
synced 2025-12-29 16:37:03 +00:00
Add Metal backend (#1287)
This commit is contained in:
parent
5520613dc3
commit
26e40a4bce
108 changed files with 14986 additions and 453 deletions
|
|
@ -116,6 +116,13 @@ add_library(CemuWxGui STATIC
|
|||
wxHelper.h
|
||||
)
|
||||
|
||||
if (ENABLE_METAL)
|
||||
target_sources(CemuWxGui PRIVATE
|
||||
canvas/MetalCanvas.cpp
|
||||
canvas/MetalCanvas.h
|
||||
)
|
||||
endif()
|
||||
|
||||
if (ENABLE_BLUEZ)
|
||||
target_sources(CemuWxGui PRIVATE
|
||||
input/PairingDialog.cpp
|
||||
|
|
|
|||
|
|
@ -595,5 +595,3 @@ void CemuApp::ActivateApp(wxActivateEvent& event)
|
|||
g_window_info.app_active = event.GetActive();
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -61,7 +61,7 @@ GameProfileWindow::GameProfileWindow(wxWindow* parent, uint64_t title_id)
|
|||
const sint32 m_cpu_modeNChoices = std::size(cpu_modes);
|
||||
m_cpu_mode = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, m_cpu_modeNChoices, cpu_modes, 0);
|
||||
m_cpu_mode->SetToolTip(_("Set the CPU emulation mode"));
|
||||
first_row->Add(m_cpu_mode, 0, wxALL, 5);
|
||||
first_row->Add(m_cpu_mode, 0, wxALL, 5);
|
||||
|
||||
first_row->Add(new wxStaticText(box, wxID_ANY, _("Thread quantum")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
|
|
@ -112,10 +112,14 @@ GameProfileWindow::GameProfileWindow(wxWindow* parent, uint64_t title_id)
|
|||
|
||||
first_row->Add(new wxStaticText(panel, wxID_ANY, _("Graphics API")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
wxString gapi_values[] = { "", "OpenGL", "Vulkan" };
|
||||
wxString gapi_values[] = { "", "OpenGL", "Vulkan",
|
||||
#if ENABLE_METAL
|
||||
"Metal"
|
||||
#endif
|
||||
};
|
||||
m_graphic_api = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(gapi_values), gapi_values);
|
||||
first_row->Add(m_graphic_api, 0, wxALL, 5);
|
||||
|
||||
|
||||
first_row->Add(new wxStaticText(panel, wxID_ANY, _("Shader multiplication accuracy")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
wxString mul_values[] = { _("false"), _("true")};
|
||||
|
|
@ -123,6 +127,27 @@ GameProfileWindow::GameProfileWindow(wxWindow* parent, uint64_t title_id)
|
|||
m_shader_mul_accuracy->SetToolTip(_("EXPERT OPTION\nControls the accuracy of floating point multiplication in shaders.\n\nRecommended: true"));
|
||||
first_row->Add(m_shader_mul_accuracy, 0, wxALL, 5);
|
||||
|
||||
first_row->Add(new wxStaticText(panel, wxID_ANY, _("Shader fast math")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
wxString math_values[] = { _("false"), _("true") };
|
||||
m_shader_fast_math = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(math_values), math_values);
|
||||
m_shader_fast_math->SetToolTip(_("EXPERT OPTION\nEnables fast math for all shaders. May (rarely) cause graphical bugs.\n\nMetal only\n\nRecommended: true"));
|
||||
first_row->Add(m_shader_fast_math, 0, wxALL, 5);
|
||||
|
||||
first_row->Add(new wxStaticText(panel, wxID_ANY, _("Metal buffer cache mode")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
wxString cache_values[] = { _("auto"), _("device private"), _("device shared"), _("host") };
|
||||
m_metal_buffer_cache_mode = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(cache_values), cache_values);
|
||||
m_metal_buffer_cache_mode->SetToolTip(_("EXPERT OPTION\nDecides how the buffer cache memory will be managed.\n\nMetal only\n\nRecommended: auto"));
|
||||
first_row->Add(m_metal_buffer_cache_mode, 0, wxALL, 5);
|
||||
|
||||
first_row->Add(new wxStaticText(panel, wxID_ANY, _("Position invariance")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
wxString pos_values[] = { _("auto"), _("false"), _("true") };
|
||||
m_position_invariance = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(pos_values), pos_values);
|
||||
m_position_invariance->SetToolTip(_("EXPERT OPTION\nDisables most optimizations for vertex positions. May fix polygon cutouts or flickering in some games.\n\nMetal only\n\nRecommended: auto"));
|
||||
first_row->Add(m_position_invariance, 0, wxALL, 5);
|
||||
|
||||
/*first_row->Add(new wxStaticText(panel, wxID_ANY, _("GPU buffer cache accuracy")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
wxString accuarcy_values[] = { _("high"), _("medium"), _("low") };
|
||||
m_cache_accuracy = new wxChoice(panel, wxID_ANY, wxDefaultPosition, wxDefaultSize, (int)std::size(accuarcy_values), accuarcy_values);
|
||||
|
|
@ -249,7 +274,7 @@ void GameProfileWindow::ApplyProfile()
|
|||
// general
|
||||
m_load_libs->SetValue(m_game_profile.m_loadSharedLibraries.value());
|
||||
m_start_with_padview->SetValue(m_game_profile.m_startWithPadView);
|
||||
|
||||
|
||||
// cpu
|
||||
// wxString cpu_modes[] = { _("Singlecore-Interpreter"), _("Singlecore-Recompiler"), _("Triplecore-Recompiler"), _("Auto (recommended)") };
|
||||
switch(m_game_profile.m_cpuMode.value())
|
||||
|
|
@ -258,24 +283,27 @@ void GameProfileWindow::ApplyProfile()
|
|||
case CPUMode::SinglecoreRecompiler: m_cpu_mode->SetSelection(1); break;
|
||||
case CPUMode::DualcoreRecompiler: m_cpu_mode->SetSelection(2); break;
|
||||
case CPUMode::MulticoreRecompiler: m_cpu_mode->SetSelection(2); break;
|
||||
default: m_cpu_mode->SetSelection(3);
|
||||
default: m_cpu_mode->SetSelection(3);
|
||||
}
|
||||
|
||||
|
||||
m_thread_quantum->SetStringSelection(fmt::format("{}", m_game_profile.m_threadQuantum));
|
||||
|
||||
// gpu
|
||||
if (!m_game_profile.m_graphics_api.has_value())
|
||||
m_graphic_api->SetSelection(0); // selecting ""
|
||||
else
|
||||
m_graphic_api->SetSelection(1 + m_game_profile.m_graphics_api.value()); // "", OpenGL, Vulkan
|
||||
m_graphic_api->SetSelection(1 + m_game_profile.m_graphics_api.value()); // "", OpenGL, Vulkan, Metal
|
||||
m_shader_mul_accuracy->SetSelection((int)m_game_profile.m_accurateShaderMul);
|
||||
m_shader_fast_math->SetSelection((int)m_game_profile.m_shaderFastMath);
|
||||
m_metal_buffer_cache_mode->SetSelection((int)m_game_profile.m_metalBufferCacheMode);
|
||||
m_position_invariance->SetSelection((int)m_game_profile.m_positionInvariance);
|
||||
|
||||
//// audio
|
||||
//m_disable_audio->Set3StateValue(GetCheckboxState(m_game_profile.disableAudio));
|
||||
|
||||
// controller
|
||||
auto profiles = InputManager::get_profiles();
|
||||
|
||||
|
||||
for (const auto& cb : m_controller_profile)
|
||||
{
|
||||
cb->Clear();
|
||||
|
|
@ -293,7 +321,7 @@ void GameProfileWindow::ApplyProfile()
|
|||
const auto& v = m_game_profile.m_controllerProfile[i].value();
|
||||
m_controller_profile[i]->SetStringSelection(wxString::FromUTF8(v));
|
||||
}
|
||||
|
||||
|
||||
else
|
||||
m_controller_profile[i]->SetSelection(wxNOT_FOUND);
|
||||
}
|
||||
|
|
@ -317,7 +345,7 @@ void GameProfileWindow::SaveProfile()
|
|||
m_game_profile.m_cpuMode = CPUMode::Auto;
|
||||
}
|
||||
|
||||
|
||||
|
||||
const wxString thread_quantum = m_thread_quantum->GetStringSelection();
|
||||
if (!thread_quantum.empty())
|
||||
{
|
||||
|
|
@ -330,11 +358,14 @@ void GameProfileWindow::SaveProfile()
|
|||
m_game_profile.m_accurateShaderMul = (AccurateShaderMulOption)m_shader_mul_accuracy->GetSelection();
|
||||
if (m_game_profile.m_accurateShaderMul != AccurateShaderMulOption::False && m_game_profile.m_accurateShaderMul != AccurateShaderMulOption::True)
|
||||
m_game_profile.m_accurateShaderMul = AccurateShaderMulOption::True; // force a legal value
|
||||
m_game_profile.m_shaderFastMath = (bool)m_shader_fast_math->GetSelection();
|
||||
m_game_profile.m_metalBufferCacheMode = (MetalBufferCacheMode)m_metal_buffer_cache_mode->GetSelection();
|
||||
m_game_profile.m_positionInvariance = (PositionInvariance)m_position_invariance->GetSelection();
|
||||
|
||||
if (m_graphic_api->GetSelection() == 0)
|
||||
m_game_profile.m_graphics_api = {};
|
||||
else
|
||||
m_game_profile.m_graphics_api = (GraphicAPI)(m_graphic_api->GetSelection() - 1); // "", OpenGL, Vulkan
|
||||
m_game_profile.m_graphics_api = (GraphicAPI)(m_graphic_api->GetSelection() - 1); // "", OpenGL, Vulkan, Metal
|
||||
|
||||
// controller
|
||||
for (int i = 0; i < 8; ++i)
|
||||
|
|
|
|||
|
|
@ -40,6 +40,9 @@ private:
|
|||
wxChoice* m_graphic_api;
|
||||
|
||||
wxChoice* m_shader_mul_accuracy;
|
||||
wxChoice* m_shader_fast_math;
|
||||
wxChoice* m_metal_buffer_cache_mode;
|
||||
wxChoice* m_position_invariance;
|
||||
//wxChoice* m_cache_accuracy;
|
||||
|
||||
// audio
|
||||
|
|
@ -47,4 +50,4 @@ private:
|
|||
|
||||
// controller
|
||||
wxComboBox* m_controller_profile[8];
|
||||
};
|
||||
};
|
||||
|
|
|
|||
|
|
@ -11,6 +11,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>
|
||||
|
||||
|
|
@ -28,6 +29,9 @@
|
|||
|
||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanAPI.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Vulkan/VulkanRenderer.h"
|
||||
#if ENABLE_METAL
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
|
||||
#endif
|
||||
#include "Cafe/Account/Account.h"
|
||||
|
||||
#include <boost/tokenizer.hpp>
|
||||
|
|
@ -94,6 +98,19 @@ private:
|
|||
VulkanRenderer::DeviceInfo m_device_info;
|
||||
};
|
||||
|
||||
#if ENABLE_METAL
|
||||
class wxMetalUUID : public wxClientData
|
||||
{
|
||||
public:
|
||||
wxMetalUUID(const MetalRenderer::DeviceInfo& info)
|
||||
: m_device_info(info) {}
|
||||
const MetalRenderer::DeviceInfo& GetDeviceInfo() const { return m_device_info; }
|
||||
|
||||
private:
|
||||
MetalRenderer::DeviceInfo m_device_info;
|
||||
};
|
||||
#endif
|
||||
|
||||
class wxAccountData : public wxClientData
|
||||
{
|
||||
public:
|
||||
|
|
@ -102,7 +119,7 @@ public:
|
|||
|
||||
Account& GetAccount() { return m_account; }
|
||||
const Account& GetAccount() const { return m_account; }
|
||||
|
||||
|
||||
private:
|
||||
Account m_account;
|
||||
};
|
||||
|
|
@ -336,12 +353,14 @@ wxPanel* GeneralSettings2::AddGraphicsPage(wxNotebook* notebook)
|
|||
row->Add(new wxStaticText(box, wxID_ANY, _("Graphics API")), 0, wxALIGN_CENTER_VERTICAL | wxALL, 5);
|
||||
|
||||
sint32 api_size = 1;
|
||||
wxString choices[2] = { "OpenGL" };
|
||||
wxString choices[3] = { "OpenGL" };
|
||||
if (g_vulkan_available)
|
||||
{
|
||||
choices[1] = "Vulkan";
|
||||
api_size = 2;
|
||||
choices[api_size++] = "Vulkan";
|
||||
}
|
||||
#if ENABLE_METAL
|
||||
choices[api_size++] = "Metal";
|
||||
#endif
|
||||
|
||||
m_graphic_api = new wxChoice(box, wxID_ANY, wxDefaultPosition, wxDefaultSize, api_size, choices);
|
||||
m_graphic_api->SetSelection(0);
|
||||
|
|
@ -373,6 +392,10 @@ wxPanel* GeneralSettings2::AddGraphicsPage(wxNotebook* notebook)
|
|||
m_gx2drawdone_sync->SetToolTip(_("If synchronization is requested by the game, the emulated CPU will wait for the GPU to finish all operations.\nThis is more accurate behavior, but may cause lower performance"));
|
||||
graphic_misc_row->Add(m_gx2drawdone_sync, 0, wxALL, 5);
|
||||
|
||||
m_force_mesh_shaders = new wxCheckBox(box, wxID_ANY, _("Force mesh shaders"));
|
||||
m_force_mesh_shaders->SetToolTip(_("Force mesh shaders on all GPUs that support them. Mesh shaders are disabled by default on Intel GPUs due to potential stability issues"));
|
||||
graphic_misc_row->Add(m_force_mesh_shaders, 0, wxALL, 5);
|
||||
|
||||
box_sizer->Add(graphic_misc_row, 1, wxEXPAND, 5);
|
||||
graphics_panel_sizer->Add(box_sizer, 0, wxEXPAND | wxALL, 5);
|
||||
}
|
||||
|
|
@ -867,7 +890,7 @@ wxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook)
|
|||
auto* row = new wxFlexGridSizer(0, 2, 0, 0);
|
||||
row->SetFlexibleDirection(wxBOTH);
|
||||
row->SetNonFlexibleGrowMode(wxFLEX_GROWMODE_SPECIFIED);
|
||||
|
||||
|
||||
const wxImage tmp = wxBITMAP_PNG_FROM_DATA(PNG_ERROR).ConvertToImage();
|
||||
m_validate_online = new wxBitmapButton(box, wxID_ANY, tmp.Scale(16, 16));
|
||||
m_validate_online->Bind(wxEVT_BUTTON, &GeneralSettings2::OnShowOnlineValidator, this);
|
||||
|
|
@ -877,7 +900,7 @@ wxPanel* GeneralSettings2::AddAccountPage(wxNotebook* notebook)
|
|||
row->Add(m_online_status, 1, wxALL | wxALIGN_CENTRE_VERTICAL, 5);
|
||||
|
||||
box_sizer->Add(row, 1, wxEXPAND, 5);
|
||||
|
||||
|
||||
auto* tutorial_link = new wxHyperlinkCtrl(box, wxID_ANY, _("Online play tutorial"), "https://cemu.info/online-guide");
|
||||
box_sizer->Add(tutorial_link, 0, wxALL, 5);
|
||||
|
||||
|
|
@ -977,6 +1000,33 @@ 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. If such debugger is not attached, METAL_CAPTURE_ENABLED must be set to 1 as an environment variable."));
|
||||
|
||||
debug_row->Add(m_gpu_capture_dir, 0, wxALL | wxEXPAND, 5);
|
||||
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);
|
||||
|
||||
m_framebuffer_fetch = new wxCheckBox(panel, wxID_ANY, _("Framebuffer fetch"));
|
||||
m_framebuffer_fetch->SetToolTip(_("Enable framebuffer fetch for eligible textures on supported devices."));
|
||||
|
||||
debug_row->Add(m_framebuffer_fetch, 0, wxALL | wxEXPAND, 5);
|
||||
debug_panel_sizer->Add(debug_row, 0, wxALL | wxEXPAND, 5);
|
||||
}
|
||||
|
||||
panel->SetSizerAndFit(debug_panel_sizer);
|
||||
|
||||
return panel;
|
||||
|
|
@ -992,14 +1042,14 @@ GeneralSettings2::GeneralSettings2(wxWindow* parent, bool game_launched)
|
|||
|
||||
notebook->AddPage(AddGeneralPage(notebook), _("General"));
|
||||
notebook->AddPage(AddGraphicsPage(notebook), _("Graphics"));
|
||||
notebook->AddPage(AddAudioPage(notebook), _("Audio"));
|
||||
notebook->AddPage(AddAudioPage(notebook), _("Audio"));
|
||||
notebook->AddPage(AddOverlayPage(notebook), _("Overlay"));
|
||||
notebook->AddPage(AddAccountPage(notebook), _("Account"));
|
||||
notebook->AddPage(AddDebugPage(notebook), _("Debug"));
|
||||
|
||||
Bind(wxEVT_CLOSE_WINDOW, &GeneralSettings2::OnClose, this);
|
||||
|
||||
//
|
||||
//
|
||||
|
||||
sizer->Add(notebook, 1, wxEXPAND | wxALL, 5);
|
||||
|
||||
|
|
@ -1014,7 +1064,7 @@ GeneralSettings2::GeneralSettings2(wxWindow* parent, bool game_launched)
|
|||
|
||||
ApplyConfig();
|
||||
HandleGraphicsApiSelection();
|
||||
|
||||
|
||||
DisableSettings(game_launched);
|
||||
}
|
||||
|
||||
|
|
@ -1026,7 +1076,7 @@ uint32 GeneralSettings2::GetSelectedAccountPersistentId()
|
|||
return dynamic_cast<wxAccountData*>(m_active_account->GetClientObject(active_account))->GetAccount().GetPersistentId();
|
||||
}
|
||||
|
||||
void GeneralSettings2::StoreConfig()
|
||||
void GeneralSettings2::StoreConfig()
|
||||
{
|
||||
auto* app = (CemuApp*)wxTheApp;
|
||||
auto& config = GetConfig();
|
||||
|
|
@ -1051,7 +1101,6 @@ void GeneralSettings2::StoreConfig()
|
|||
ScreenSaver::SetInhibit(config.disable_screensaver);
|
||||
}
|
||||
|
||||
|
||||
// -1 is default wx widget value -> set to dummy 0 so mainwindow and padwindow will update it
|
||||
wxGuiConfig.window_position = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
|
||||
wxGuiConfig.window_size = m_save_window_position_size->IsChecked() ? Vector2i{ 0,0 } : Vector2i{-1,-1};
|
||||
|
|
@ -1094,7 +1143,7 @@ void GeneralSettings2::StoreConfig()
|
|||
config.pad_channels = kStereo; // (AudioChannels)m_pad_channels->GetSelection();
|
||||
//config.input_channels = (AudioChannels)m_input_channels->GetSelection();
|
||||
config.input_channels = kMono; // (AudioChannels)m_input_channels->GetSelection();
|
||||
|
||||
|
||||
config.tv_volume = m_tv_volume->GetValue();
|
||||
config.pad_volume = m_pad_volume->GetValue();
|
||||
config.input_volume = m_input_volume->GetValue();
|
||||
|
|
@ -1140,29 +1189,48 @@ void GeneralSettings2::StoreConfig()
|
|||
config.graphic_api = (GraphicAPI)m_graphic_api->GetSelection();
|
||||
|
||||
selection = m_graphic_device->GetSelection();
|
||||
if(selection != wxNOT_FOUND)
|
||||
if (config.graphic_api == GraphicAPI::kVulkan)
|
||||
{
|
||||
const auto* info = (wxVulkanUUID*)m_graphic_device->GetClientObject(selection);
|
||||
if(info)
|
||||
config.graphic_device_uuid = info->GetDeviceInfo().uuid;
|
||||
else
|
||||
config.graphic_device_uuid = {};
|
||||
if (selection != wxNOT_FOUND)
|
||||
{
|
||||
const auto* info = (wxVulkanUUID*)m_graphic_device->GetClientObject(selection);
|
||||
if (info)
|
||||
config.vk_graphic_device_uuid = info->GetDeviceInfo().uuid;
|
||||
else
|
||||
config.vk_graphic_device_uuid = {};
|
||||
}
|
||||
else
|
||||
config.vk_graphic_device_uuid = {};
|
||||
}
|
||||
else
|
||||
config.graphic_device_uuid = {};
|
||||
|
||||
else if (config.graphic_api == GraphicAPI::kMetal)
|
||||
{
|
||||
if (selection != wxNOT_FOUND)
|
||||
{
|
||||
#if ENABLE_METAL
|
||||
const auto* info = (wxMetalUUID*)m_graphic_device->GetClientObject(selection);
|
||||
if (info)
|
||||
config.mtl_graphic_device_uuid = info->GetDeviceInfo().uuid;
|
||||
else
|
||||
config.mtl_graphic_device_uuid = {};
|
||||
#endif
|
||||
}
|
||||
else
|
||||
config.mtl_graphic_device_uuid = {};
|
||||
}
|
||||
|
||||
|
||||
config.vsync = m_vsync->GetSelection();
|
||||
config.overrideAppGammaPreference = m_overrideGamma->IsChecked();
|
||||
config.overrideGammaValue = m_overrideGammaValue->GetValue();
|
||||
config.userDisplayGamma = m_userDisplayGamma->GetValue() * !m_userDisplayisSRGB->GetValue();
|
||||
config.gx2drawdone_sync = m_gx2drawdone_sync->IsChecked();
|
||||
config.force_mesh_shaders = m_force_mesh_shaders->IsChecked();
|
||||
config.async_compile = m_async_compile->IsChecked();
|
||||
|
||||
|
||||
config.upscale_filter = m_upscale_filter->GetSelection();
|
||||
config.downscale_filter = m_downscale_filter->GetSelection();
|
||||
config.fullscreen_scaling = m_fullscreen_scaling->GetSelection();
|
||||
|
||||
|
||||
config.overlay.position = (ScreenPosition)m_overlay_position->GetSelection(); wxASSERT((int)config.overlay.position <= (int)ScreenPosition::kBottomRight);
|
||||
config.overlay.text_color = m_overlay_font_color->GetColour().GetRGBA();
|
||||
config.overlay.text_scale = m_overlay_scale->GetSelection() * 25 + 50;
|
||||
|
|
@ -1189,6 +1257,8 @@ 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();
|
||||
config.framebuffer_fetch = m_framebuffer_fetch->IsChecked();
|
||||
|
||||
GetConfigHandle().Save();
|
||||
}
|
||||
|
|
@ -1230,7 +1300,7 @@ void GeneralSettings2::OnAudioLatencyChanged(wxCommandEvent& event)
|
|||
|
||||
void GeneralSettings2::OnVolumeChanged(wxCommandEvent& event)
|
||||
{
|
||||
|
||||
|
||||
if(event.GetEventObject() == m_input_volume)
|
||||
{
|
||||
std::shared_lock lock(g_audioInputMutex);
|
||||
|
|
@ -1258,7 +1328,7 @@ void GeneralSettings2::OnVolumeChanged(wxCommandEvent& event)
|
|||
g_portalAudio->SetVolume(event.GetInt());
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
|
@ -1351,7 +1421,7 @@ void GeneralSettings2::UpdateAudioDeviceList()
|
|||
// todo reset global instance of audio device
|
||||
}
|
||||
|
||||
void GeneralSettings2::ResetAccountInformation()
|
||||
void GeneralSettings2::ResetAccountInformation()
|
||||
{
|
||||
m_account_grid->SetSplitterPosition(100);
|
||||
m_active_account->SetSelection(0);
|
||||
|
|
@ -1379,7 +1449,7 @@ void GeneralSettings2::OnAccountCreate(wxCommandEvent& event)
|
|||
Account account(dialog.GetPersistentId(), dialog.GetMiiName().ToStdWstring());
|
||||
account.Save();
|
||||
Account::RefreshAccounts();
|
||||
|
||||
|
||||
const int index = m_active_account->Append(account.ToString(), new wxAccountData(account));
|
||||
|
||||
// update ui
|
||||
|
|
@ -1388,7 +1458,7 @@ void GeneralSettings2::OnAccountCreate(wxCommandEvent& event)
|
|||
|
||||
m_create_account->Enable(m_active_account->GetCount() < 0xC);
|
||||
m_delete_account->Enable(m_active_account->GetCount() > 1);
|
||||
|
||||
|
||||
// send main window event
|
||||
wxASSERT(GetParent());
|
||||
wxCommandEvent refresh_event(wxEVT_ACCOUNTLIST_REFRESH);
|
||||
|
|
@ -1418,7 +1488,7 @@ void GeneralSettings2::OnAccountDelete(wxCommandEvent& event)
|
|||
return;
|
||||
|
||||
// todo: ask if saves should be deleted too?
|
||||
|
||||
|
||||
const fs::path path = account.GetFileName();
|
||||
try
|
||||
{
|
||||
|
|
@ -1436,7 +1506,7 @@ void GeneralSettings2::OnAccountDelete(wxCommandEvent& event)
|
|||
SystemException sys(ex);
|
||||
cemuLog_log(LogType::Force, sys.what());
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
void GeneralSettings2::OnAccountSettingsChanged(wxPropertyGridEvent& event)
|
||||
|
|
@ -1491,7 +1561,7 @@ void GeneralSettings2::OnAccountSettingsChanged(wxPropertyGridEvent& event)
|
|||
else if (property->GetName() == kPropertyEmail)
|
||||
{
|
||||
account.SetEmail(value.As<wxString>().ToStdString());
|
||||
|
||||
|
||||
}
|
||||
else if (property->GetName() == kPropertyCountry)
|
||||
{
|
||||
|
|
@ -1499,7 +1569,7 @@ void GeneralSettings2::OnAccountSettingsChanged(wxPropertyGridEvent& event)
|
|||
}
|
||||
else
|
||||
cemu_assert_debug(false);
|
||||
|
||||
|
||||
account.Save();
|
||||
Account::RefreshAccounts(); // refresh internal account list
|
||||
UpdateAccountInformation(); // refresh on invalid values
|
||||
|
|
@ -1539,7 +1609,7 @@ void GeneralSettings2::UpdateAccountInformation()
|
|||
gender_property->SetChoiceSelection(std::min(gender_property->GetChoices().GetCount() - 1, (uint32)account.GetGender()));
|
||||
|
||||
m_account_grid->GetProperty(kPropertyEmail)->SetValueFromString(std::string{ account.GetEmail() });
|
||||
|
||||
|
||||
auto* country_property = dynamic_cast<wxEnumProperty*>(m_account_grid->GetProperty(kPropertyCountry));
|
||||
wxASSERT(country_property);
|
||||
int index = (country_property)->GetIndexForValue(account.GetCountry());
|
||||
|
|
@ -1623,9 +1693,9 @@ void GeneralSettings2::HandleGraphicsApiSelection()
|
|||
int selection = m_vsync->GetSelection();
|
||||
if(selection == wxNOT_FOUND)
|
||||
selection = GetConfig().vsync;
|
||||
|
||||
|
||||
m_vsync->Clear();
|
||||
if(m_graphic_api->GetSelection() == 0)
|
||||
if (m_graphic_api->GetSelection() == 0)
|
||||
{
|
||||
// OpenGL
|
||||
m_vsync->AppendString(_("Off"));
|
||||
|
|
@ -1640,12 +1710,14 @@ void GeneralSettings2::HandleGraphicsApiSelection()
|
|||
|
||||
m_gx2drawdone_sync->Enable();
|
||||
m_async_compile->Disable();
|
||||
m_force_mesh_shaders->Disable();
|
||||
}
|
||||
else
|
||||
else if (m_graphic_api->GetSelection() == 1)
|
||||
{
|
||||
// Vulkan
|
||||
m_gx2drawdone_sync->Disable();
|
||||
m_async_compile->Enable();
|
||||
m_force_mesh_shaders->Disable();
|
||||
|
||||
m_vsync->AppendString(_("Off"));
|
||||
m_vsync->AppendString(_("Double buffering"));
|
||||
|
|
@ -1655,7 +1727,7 @@ void GeneralSettings2::HandleGraphicsApiSelection()
|
|||
#endif
|
||||
|
||||
m_vsync->Select(selection);
|
||||
|
||||
|
||||
m_graphic_device->Enable();
|
||||
auto devices = VulkanRenderer::GetDevices();
|
||||
m_graphic_device->Clear();
|
||||
|
|
@ -1670,7 +1742,7 @@ void GeneralSettings2::HandleGraphicsApiSelection()
|
|||
const auto& config = GetConfig();
|
||||
for(size_t i = 0; i < devices.size(); ++i)
|
||||
{
|
||||
if(config.graphic_device_uuid == devices[i].uuid)
|
||||
if(config.vk_graphic_device_uuid == devices[i].uuid)
|
||||
{
|
||||
m_graphic_device->SetSelection(i);
|
||||
break;
|
||||
|
|
@ -1678,6 +1750,42 @@ void GeneralSettings2::HandleGraphicsApiSelection()
|
|||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
// Metal
|
||||
m_gx2drawdone_sync->Disable();
|
||||
m_async_compile->Enable();
|
||||
m_force_mesh_shaders->Enable();
|
||||
|
||||
m_vsync->AppendString(_("Off"));
|
||||
m_vsync->AppendString(_("On"));
|
||||
|
||||
m_vsync->Select(selection);
|
||||
|
||||
m_graphic_device->Enable();
|
||||
m_graphic_device->Clear();
|
||||
#if ENABLE_METAL
|
||||
auto devices = MetalRenderer::GetDevices();
|
||||
if(!devices.empty())
|
||||
{
|
||||
for (const auto& device : devices)
|
||||
{
|
||||
m_graphic_device->Append(device.name, new wxMetalUUID(device));
|
||||
}
|
||||
m_graphic_device->SetSelection(0);
|
||||
|
||||
const auto& config = GetConfig();
|
||||
for (size_t i = 0; i < devices.size(); ++i)
|
||||
{
|
||||
if (config.mtl_graphic_device_uuid == devices[i].uuid)
|
||||
{
|
||||
m_graphic_device->SetSelection(i);
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void GeneralSettings2::ApplyConfig()
|
||||
|
|
@ -1744,6 +1852,7 @@ void GeneralSettings2::ApplyConfig()
|
|||
}
|
||||
m_async_compile->SetValue(config.async_compile);
|
||||
m_gx2drawdone_sync->SetValue(config.gx2drawdone_sync);
|
||||
m_force_mesh_shaders->SetValue(config.force_mesh_shaders);
|
||||
m_upscale_filter->SetSelection(config.upscale_filter);
|
||||
m_downscale_filter->SetSelection(config.downscale_filter);
|
||||
m_fullscreen_scaling->SetSelection(config.fullscreen_scaling);
|
||||
|
|
@ -1794,7 +1903,7 @@ void GeneralSettings2::ApplyConfig()
|
|||
m_pad_channels->SetSelection(0);
|
||||
//m_input_channels->SetSelection(config.pad_channels);
|
||||
m_input_channels->SetSelection(0);
|
||||
|
||||
|
||||
SendSliderEvent(m_tv_volume, config.tv_volume);
|
||||
|
||||
if (!config.tv_device.empty() && m_tv_device->HasClientObjectData())
|
||||
|
|
@ -1811,7 +1920,7 @@ void GeneralSettings2::ApplyConfig()
|
|||
}
|
||||
else
|
||||
m_tv_device->SetSelection(0);
|
||||
|
||||
|
||||
SendSliderEvent(m_pad_volume, config.pad_volume);
|
||||
if (!config.pad_device.empty() && m_pad_device->HasClientObjectData())
|
||||
{
|
||||
|
|
@ -1880,6 +1989,8 @@ 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()));
|
||||
m_framebuffer_fetch->SetValue(config.framebuffer_fetch);
|
||||
}
|
||||
|
||||
void GeneralSettings2::OnAudioAPISelected(wxCommandEvent& event)
|
||||
|
|
@ -1947,7 +2058,7 @@ void GeneralSettings2::UpdateAudioDevice()
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// pad audio device
|
||||
{
|
||||
const auto selection = m_pad_device->GetSelection();
|
||||
|
|
@ -2041,7 +2152,7 @@ void GeneralSettings2::UpdateAudioDevice()
|
|||
channels = g_portalAudio->GetChannels();
|
||||
else
|
||||
channels = 1;
|
||||
|
||||
|
||||
try
|
||||
{
|
||||
g_portalAudio = IAudioAPI::CreateDevice((IAudioAPI::AudioAPI)config.audio_api, description->GetDescription(), 8000, 1, 32, 16);
|
||||
|
|
@ -2074,14 +2185,14 @@ void GeneralSettings2::OnAudioChannelsSelected(wxCommandEvent& event)
|
|||
{
|
||||
if (config.tv_channels == (AudioChannels)obj->GetSelection())
|
||||
return;
|
||||
|
||||
|
||||
config.tv_channels = (AudioChannels)obj->GetSelection();
|
||||
}
|
||||
else if (obj == m_pad_channels)
|
||||
{
|
||||
if (config.pad_channels == (AudioChannels)obj->GetSelection())
|
||||
return;
|
||||
|
||||
|
||||
config.pad_channels = (AudioChannels)obj->GetSelection();
|
||||
}
|
||||
else
|
||||
|
|
@ -2233,23 +2344,23 @@ void GeneralSettings2::OnShowOnlineValidator(wxCommandEvent& event)
|
|||
const auto selection = m_active_account->GetSelection();
|
||||
if (selection == wxNOT_FOUND)
|
||||
return;
|
||||
|
||||
|
||||
const auto* obj = dynamic_cast<wxAccountData*>(m_active_account->GetClientObject(selection));
|
||||
wxASSERT(obj);
|
||||
const auto& account = obj->GetAccount();
|
||||
|
||||
|
||||
const auto validator = account.ValidateOnlineFiles();
|
||||
if (validator) // everything valid? shouldn't happen
|
||||
return;
|
||||
|
||||
|
||||
wxString err;
|
||||
err << _("The following error(s) have been found:") << '\n';
|
||||
|
||||
|
||||
if (validator.otp == OnlineValidator::FileState::Missing)
|
||||
err << _("otp.bin missing in Cemu directory") << '\n';
|
||||
else if(validator.otp == OnlineValidator::FileState::Corrupted)
|
||||
err << _("otp.bin is invalid") << '\n';
|
||||
|
||||
|
||||
if (validator.seeprom == OnlineValidator::FileState::Missing)
|
||||
err << _("seeprom.bin missing in Cemu directory") << '\n';
|
||||
else if(validator.seeprom == OnlineValidator::FileState::Corrupted)
|
||||
|
|
|
|||
|
|
@ -28,7 +28,7 @@ private:
|
|||
|
||||
bool m_has_account_change = false; // keep track of dirty state of accounts
|
||||
|
||||
|
||||
|
||||
wxPanel* AddGeneralPage(wxNotebook* notebook);
|
||||
wxPanel* AddGraphicsPage(wxNotebook* notebook);
|
||||
wxPanel* AddAudioPage(wxNotebook* notebook);
|
||||
|
|
@ -61,7 +61,7 @@ private:
|
|||
wxSpinCtrlDouble* m_userDisplayGamma;
|
||||
wxCheckBox* m_userDisplayisSRGB;
|
||||
|
||||
wxCheckBox *m_async_compile, *m_gx2drawdone_sync;
|
||||
wxCheckBox *m_async_compile, *m_gx2drawdone_sync, *m_force_mesh_shaders;
|
||||
wxRadioBox* m_upscale_filter, *m_downscale_filter, *m_fullscreen_scaling;
|
||||
wxChoice* m_overlay_position, *m_notification_position, *m_overlay_scale, *m_notification_scale;
|
||||
wxCheckBox* m_controller_profile_name, *m_controller_low_battery, *m_shader_compiling, *m_friends_data;
|
||||
|
|
@ -87,6 +87,8 @@ private:
|
|||
// Debug
|
||||
wxChoice* m_crash_dump;
|
||||
wxSpinCtrl* m_gdb_port;
|
||||
wxTextCtrl* m_gpu_capture_dir;
|
||||
wxCheckBox* m_framebuffer_fetch;
|
||||
|
||||
void OnAccountCreate(wxCommandEvent& event);
|
||||
void OnAccountDelete(wxCommandEvent& event);
|
||||
|
|
@ -116,11 +118,10 @@ private:
|
|||
void UpdateAudioDevice();
|
||||
// refreshes audio device list for dropdown
|
||||
void UpdateAudioDeviceList();
|
||||
|
||||
|
||||
void ResetAccountInformation();
|
||||
void UpdateAccountInformation();
|
||||
void UpdateOnlineAccounts();
|
||||
void HandleGraphicsApiSelection();
|
||||
void ApplyConfig();
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -18,7 +18,7 @@ LoggingWindow::LoggingWindow(wxFrame* parent)
|
|||
|
||||
filter_row->Add(new wxStaticText( this, wxID_ANY, _("Filter")), 0, wxALIGN_CENTER_VERTICAL|wxALL, 5 );
|
||||
|
||||
wxString choices[] = {"Unsupported APIs calls", "Coreinit Logging", "Coreinit File-Access", "Coreinit Thread-Synchronization", "Coreinit Memory", "Coreinit MP", "Coreinit Thread", "nn::nfp", "GX2", "Audio", "Input", "Socket", "Save", "H264", "Graphic pack patches", "Texture cache", "Texture readback", "OpenGL debug output", "Vulkan validation layer"};
|
||||
wxString choices[] = {"Unsupported APIs calls", "Coreinit Logging", "Coreinit File-Access", "Coreinit Thread-Synchronization", "Coreinit Memory", "Coreinit MP", "Coreinit Thread", "nn::nfp", "GX2", "Audio", "Input", "Socket", "Save", "H264", "Graphic pack patches", "Texture cache", "Texture readback", "OpenGL debug output", "Vulkan validation layer", "Metal debug output"};
|
||||
m_filter = new wxComboBox( this, wxID_ANY, wxEmptyString, wxDefaultPosition, wxDefaultSize, std::size(choices), choices, 0 );
|
||||
m_filter->Bind(wxEVT_COMBOBOX, &LoggingWindow::OnFilterChange, this);
|
||||
m_filter->Bind(wxEVT_TEXT, &LoggingWindow::OnFilterChange, this);
|
||||
|
|
@ -69,7 +69,7 @@ void LoggingWindow::Log(std::string_view filter, std::wstring_view message)
|
|||
|
||||
void LoggingWindow::OnLogMessage(wxLogEvent& event)
|
||||
{
|
||||
m_log_list->PushEntry(event.GetFilter(), event.GetMessage());
|
||||
m_log_list->PushEntry(event.GetFilter(), event.GetMessage());
|
||||
}
|
||||
|
||||
void LoggingWindow::OnFilterChange(wxCommandEvent& event)
|
||||
|
|
@ -83,4 +83,3 @@ void LoggingWindow::OnFilterMessageChange(wxCommandEvent& event)
|
|||
m_log_list->SetFilterMessage(m_filter_message->GetValue());
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -14,6 +14,7 @@
|
|||
#include "AudioDebuggerWindow.h"
|
||||
#include "wxgui/canvas/OpenGLCanvas.h"
|
||||
#include "wxgui/canvas/VulkanCanvas.h"
|
||||
#include "wxgui/canvas/MetalCanvas.h"
|
||||
#include "Cafe/OS/libs/nfc/nfc.h"
|
||||
#include "Cafe/OS/libs/swkbd/swkbd.h"
|
||||
#include "wxgui/debugger/DebuggerWindow2.h"
|
||||
|
|
@ -64,6 +65,10 @@
|
|||
#include "gamemode_client.h"
|
||||
#endif
|
||||
|
||||
#if ENABLE_METAL
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
|
||||
#endif
|
||||
|
||||
#include "Cafe/TitleList/TitleInfo.h"
|
||||
#include "Cafe/TitleList/TitleList.h"
|
||||
#include "wxHelper.h"
|
||||
|
|
@ -100,7 +105,7 @@ enum
|
|||
// options -> account
|
||||
MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_1 = 20350,
|
||||
MAINFRAME_MENU_ID_OPTIONS_ACCOUNT_12 = 20350 + 11,
|
||||
|
||||
|
||||
// options -> system language
|
||||
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_JAPANESE = 20500,
|
||||
MAINFRAME_MENU_ID_OPTIONS_LANGUAGE_ENGLISH,
|
||||
|
|
@ -143,6 +148,7 @@ enum
|
|||
MAINFRAME_MENU_ID_DEBUG_VIEW_TEXTURE_RELATIONS,
|
||||
MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY,
|
||||
MAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS,
|
||||
MAINFRAME_MENU_ID_DEBUG_GPU_CAPTURE,
|
||||
|
||||
// debug->logging
|
||||
MAINFRAME_MENU_ID_DEBUG_LOGGING_MESSAGE = 21499,
|
||||
|
|
@ -225,6 +231,7 @@ EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_CURL_REQUESTS, MainWindow::OnDebugSetting)
|
|||
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN, MainWindow::OnDebugSetting)
|
||||
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY, MainWindow::OnDebugSetting)
|
||||
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS, MainWindow::OnDebugSetting)
|
||||
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_GPU_CAPTURE, MainWindow::OnDebugSetting)
|
||||
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_RAM, MainWindow::OnDebugSetting)
|
||||
EVT_MENU(MAINFRAME_MENU_ID_DEBUG_DUMP_FST, MainWindow::OnDebugSetting)
|
||||
// debug -> View ...
|
||||
|
|
@ -257,7 +264,7 @@ public:
|
|||
{
|
||||
if(!m_window->IsGameLaunched() && filenames.GetCount() == 1)
|
||||
return m_window->FileLoad(_utf8ToPath(filenames[0].utf8_string()), wxLaunchGameEvent::INITIATED_BY::DRAG_AND_DROP);
|
||||
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
|
@ -473,7 +480,7 @@ bool MainWindow::InstallUpdate(const fs::path& metaFilePath)
|
|||
{
|
||||
throw std::runtime_error(frame.GetExceptionMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
catch(const AbortException&)
|
||||
{
|
||||
|
|
@ -657,13 +664,13 @@ void MainWindow::OnFileMenu(wxCommandEvent& event)
|
|||
_("Wii U executable (*.rpx, *.elf)"),
|
||||
_("All files (*.*)")
|
||||
);
|
||||
|
||||
|
||||
wxFileDialog openFileDialog(this, _("Open file to launch"), wxEmptyString, wxEmptyString, wildcard, wxFD_OPEN | wxFD_FILE_MUST_EXIST);
|
||||
|
||||
if (openFileDialog.ShowModal() == wxID_CANCEL || openFileDialog.GetPath().IsEmpty())
|
||||
return;
|
||||
|
||||
const wxString wxStrFilePath = openFileDialog.GetPath();
|
||||
const wxString wxStrFilePath = openFileDialog.GetPath();
|
||||
FileLoad(_utf8ToPath(wxStrFilePath.utf8_string()), wxLaunchGameEvent::INITIATED_BY::MENU);
|
||||
}
|
||||
else if (menuId >= MAINFRAME_MENU_ID_FILE_RECENT_0 && menuId <= MAINFRAME_MENU_ID_FILE_RECENT_LAST)
|
||||
|
|
@ -814,7 +821,7 @@ void MainWindow::TogglePadView()
|
|||
{
|
||||
if (m_padView)
|
||||
return;
|
||||
|
||||
|
||||
m_padView = new PadViewFrame(this);
|
||||
|
||||
m_padView->Bind(wxEVT_CLOSE_WINDOW, &MainWindow::OnPadClose, this);
|
||||
|
|
@ -1029,7 +1036,7 @@ void MainWindow::OnConsoleLanguage(wxCommandEvent& event)
|
|||
// GetConfig().cpu_mode = CPUMode::TriplecoreRecompiler;
|
||||
// else
|
||||
// cemu_assert_debug(false);
|
||||
//
|
||||
//
|
||||
// GetConfigHandle().Save();
|
||||
//}
|
||||
|
||||
|
|
@ -1043,6 +1050,14 @@ void MainWindow::OnDebugSetting(wxCommandEvent& event)
|
|||
if(!GetConfig().vk_accurate_barriers)
|
||||
wxMessageBox(_("Warning: Disabling the accurate barriers option will lead to flickering graphics but may improve performance. It is highly recommended to leave it turned on."), _("Accurate barriers are off"), wxOK);
|
||||
}
|
||||
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_GPU_CAPTURE)
|
||||
{
|
||||
cemu_assert_debug(g_renderer->GetType() == RendererAPI::Metal);
|
||||
|
||||
#if ENABLE_METAL
|
||||
static_cast<MetalRenderer*>(g_renderer.get())->CaptureFrame();
|
||||
#endif
|
||||
}
|
||||
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_AUDIO_AUX_ONLY)
|
||||
ActiveSettings::EnableAudioOnlyAux(event.IsChecked());
|
||||
else if (event.GetId() == MAINFRAME_MENU_ID_DEBUG_DUMP_RAM)
|
||||
|
|
@ -1093,7 +1108,7 @@ void MainWindow::OnDebugSetting(wxCommandEvent& event)
|
|||
ActiveSettings::SetTimerShiftFactor(6);
|
||||
else
|
||||
cemu_assert_debug(false);
|
||||
|
||||
|
||||
GetConfigHandle().Save();
|
||||
}
|
||||
|
||||
|
|
@ -1165,7 +1180,7 @@ void MainWindow::OnLoggingWindow(wxCommandEvent& event)
|
|||
return;
|
||||
|
||||
m_logging_window = new LoggingWindow(this);
|
||||
m_logging_window->Bind(wxEVT_CLOSE_WINDOW,
|
||||
m_logging_window->Bind(wxEVT_CLOSE_WINDOW,
|
||||
[this](wxCloseEvent& event) {
|
||||
m_logging_window = nullptr;
|
||||
event.Skip();
|
||||
|
|
@ -1340,7 +1355,7 @@ void MainWindow::SaveSettings()
|
|||
{
|
||||
auto lock = GetConfigHandle().Lock();
|
||||
auto& config = GetWxGUIConfig();
|
||||
|
||||
|
||||
if (config.window_position != Vector2i{ -1,-1 })
|
||||
{
|
||||
config.window_position.x = m_restored_position.x;
|
||||
|
|
@ -1377,7 +1392,7 @@ void MainWindow::SaveSettings()
|
|||
|
||||
if(m_game_list)
|
||||
m_game_list->SaveConfig();
|
||||
|
||||
|
||||
g_wxConfig.Save();
|
||||
}
|
||||
|
||||
|
|
@ -1407,14 +1422,14 @@ void MainWindow::OnMouseMove(wxMouseEvent& event)
|
|||
void MainWindow::OnMouseLeft(wxMouseEvent& event)
|
||||
{
|
||||
auto& instance = InputManager::instance();
|
||||
|
||||
|
||||
std::scoped_lock lock(instance.m_main_mouse.m_mutex);
|
||||
instance.m_main_mouse.left_down = event.ButtonDown(wxMOUSE_BTN_LEFT);
|
||||
auto physPos = ToPhys(event.GetPosition());
|
||||
instance.m_main_mouse.position = { physPos.x, physPos.y };
|
||||
if (event.ButtonDown(wxMOUSE_BTN_LEFT))
|
||||
instance.m_main_mouse.left_down_toggle = true;
|
||||
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
|
@ -1428,7 +1443,7 @@ void MainWindow::OnMouseRight(wxMouseEvent& event)
|
|||
instance.m_main_mouse.position = { physPos.x, physPos.y };
|
||||
if(event.ButtonDown(wxMOUSE_BTN_RIGHT))
|
||||
instance.m_main_mouse.right_down_toggle = true;
|
||||
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
|
@ -1485,7 +1500,7 @@ void MainWindow::OnKeyDown(wxKeyEvent& event)
|
|||
#endif
|
||||
else
|
||||
{
|
||||
event.Skip();
|
||||
event.Skip();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1493,7 +1508,7 @@ void MainWindow::OnChar(wxKeyEvent& event)
|
|||
{
|
||||
if (swkbd_hasKeyboardInputHook())
|
||||
swkbd_keyInput(event.GetUnicodeKey());
|
||||
|
||||
|
||||
// event.Skip();
|
||||
}
|
||||
|
||||
|
|
@ -1518,7 +1533,7 @@ void MainWindow::OnToolsInput(wxCommandEvent& event)
|
|||
case MAINFRAME_MENU_ID_TOOLS_DOWNLOAD_MANAGER:
|
||||
{
|
||||
const auto default_tab = id == MAINFRAME_MENU_ID_TOOLS_TITLE_MANAGER ? TitleManagerPage::TitleManager : TitleManagerPage::DownloadManager;
|
||||
|
||||
|
||||
if (m_title_manager)
|
||||
m_title_manager->SetFocusAndTab(default_tab);
|
||||
else
|
||||
|
|
@ -1568,7 +1583,7 @@ void MainWindow::OnGesturePan(wxPanGestureEvent& event)
|
|||
instance.m_main_touch.left_down = event.IsGestureStart() || !event.IsGestureEnd();
|
||||
if (event.IsGestureStart() || !event.IsGestureEnd())
|
||||
instance.m_main_touch.left_down_toggle = true;
|
||||
|
||||
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
|
@ -1602,8 +1617,12 @@ void MainWindow::CreateCanvas()
|
|||
// create canvas
|
||||
if (ActiveSettings::GetGraphicsAPI() == kVulkan)
|
||||
m_render_canvas = new VulkanCanvas(m_game_panel, wxSize(1280, 720), true);
|
||||
else
|
||||
else if (ActiveSettings::GetGraphicsAPI() == kOpenGL)
|
||||
m_render_canvas = GLCanvas_Create(m_game_panel, wxSize(1280, 720), true);
|
||||
#if ENABLE_METAL
|
||||
else
|
||||
m_render_canvas = new MetalCanvas(m_game_panel, wxSize(1280, 720), true);
|
||||
#endif
|
||||
|
||||
// mouse events
|
||||
m_render_canvas->Bind(wxEVT_MOTION, &MainWindow::OnMouseMove, this);
|
||||
|
|
@ -1783,10 +1802,10 @@ void MainWindow::UpdateNFCMenu()
|
|||
const auto& entry = config.recent_nfc_files[i];
|
||||
if (entry.empty())
|
||||
continue;
|
||||
|
||||
|
||||
if (!fs::exists(_utf8ToPath(entry)))
|
||||
continue;
|
||||
|
||||
|
||||
if (recentFileIndex == 0)
|
||||
m_nfcMenuSeparator0 = m_nfcMenu->AppendSeparator();
|
||||
|
||||
|
|
@ -1837,7 +1856,7 @@ void MainWindow::OnTimer(wxTimerEvent& event)
|
|||
{
|
||||
ShowCursor(false);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
#define BUILD_DATE __DATE__ " " __TIME__
|
||||
|
|
@ -2106,9 +2125,9 @@ void MainWindow::RecreateMenu()
|
|||
m_menuBar->Destroy();
|
||||
m_menuBar = nullptr;
|
||||
}
|
||||
|
||||
|
||||
auto& guiConfig = GetWxGUIConfig();
|
||||
|
||||
|
||||
m_menuBar = new wxMenuBar();
|
||||
// file submenu
|
||||
m_fileMenu = new wxMenu();
|
||||
|
|
@ -2171,7 +2190,7 @@ void MainWindow::RecreateMenu()
|
|||
item->Check(account_id == account.GetPersistentId());
|
||||
if (m_game_launched || LaunchSettings::GetPersistentId().has_value())
|
||||
item->Enable(false);
|
||||
|
||||
|
||||
++index;
|
||||
}
|
||||
|
||||
|
|
@ -2203,8 +2222,8 @@ void MainWindow::RecreateMenu()
|
|||
// options submenu
|
||||
wxMenu* optionsMenu = new wxMenu();
|
||||
m_fullscreenMenuItem = optionsMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_FULLSCREEN, _("&Fullscreen"), wxEmptyString);
|
||||
m_fullscreenMenuItem->Check(FullscreenEnabled());
|
||||
|
||||
m_fullscreenMenuItem->Check(FullscreenEnabled());
|
||||
|
||||
optionsMenu->Append(MAINFRAME_MENU_ID_OPTIONS_GRAPHIC_PACKS2, _("&Graphic packs"));
|
||||
m_padViewMenuItem = optionsMenu->AppendCheckItem(MAINFRAME_MENU_ID_OPTIONS_SECOND_WINDOW_PADVIEW, _("&Separate GamePad view"), wxEmptyString);
|
||||
m_padViewMenuItem->Check(wxConfig.pad_open);
|
||||
|
|
@ -2303,7 +2322,7 @@ void MainWindow::RecreateMenu()
|
|||
debugMenu->AppendSubMenu(debugLoggingMenu, _("&Logging"));
|
||||
debugMenu->AppendSubMenu(debugDumpMenu, _("&Dump"));
|
||||
debugMenu->AppendSeparator();
|
||||
|
||||
|
||||
auto upsidedownItem = debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_RENDER_UPSIDE_DOWN, _("&Render upside-down"), wxEmptyString);
|
||||
upsidedownItem->Check(ActiveSettings::RenderUpsideDownEnabled());
|
||||
if(LaunchSettings::RenderUpsideDownEnabled().has_value())
|
||||
|
|
@ -2312,6 +2331,9 @@ void MainWindow::RecreateMenu()
|
|||
auto accurateBarriers = debugMenu->AppendCheckItem(MAINFRAME_MENU_ID_DEBUG_VK_ACCURATE_BARRIERS, _("&Accurate barriers (Vulkan)"), wxEmptyString);
|
||||
accurateBarriers->Check(GetConfig().vk_accurate_barriers);
|
||||
|
||||
auto gpuCapture = debugMenu->Append(MAINFRAME_MENU_ID_DEBUG_GPU_CAPTURE, _("&GPU capture (Metal)"));
|
||||
gpuCapture->Enable(m_game_launched && g_renderer->GetType() == RendererAPI::Metal);
|
||||
|
||||
debugMenu->AppendSeparator();
|
||||
|
||||
#ifdef CEMU_DEBUG_ASSERT
|
||||
|
|
|
|||
|
|
@ -8,6 +8,7 @@
|
|||
#include "Cafe/OS/libs/swkbd/swkbd.h"
|
||||
#include "wxgui/canvas/OpenGLCanvas.h"
|
||||
#include "wxgui/canvas/VulkanCanvas.h"
|
||||
#include "wxgui/canvas/MetalCanvas.h"
|
||||
#include "config/CemuConfig.h"
|
||||
#include "wxgui/MainWindow.h"
|
||||
#include "wxgui/helpers/wxHelpers.h"
|
||||
|
|
@ -74,8 +75,12 @@ void PadViewFrame::InitializeRenderCanvas()
|
|||
{
|
||||
if (ActiveSettings::GetGraphicsAPI() == kVulkan)
|
||||
m_render_canvas = new VulkanCanvas(this, wxSize(854, 480), false);
|
||||
else
|
||||
else if (ActiveSettings::GetGraphicsAPI() == kOpenGL)
|
||||
m_render_canvas = GLCanvas_Create(this, wxSize(854, 480), false);
|
||||
#if ENABLE_METAL
|
||||
else
|
||||
m_render_canvas = new MetalCanvas(this, wxSize(854, 480), false);
|
||||
#endif
|
||||
sizer->Add(m_render_canvas, 1, wxEXPAND, 0, nullptr);
|
||||
}
|
||||
SetSizer(sizer);
|
||||
|
|
@ -173,7 +178,7 @@ void PadViewFrame::OnChar(wxKeyEvent& event)
|
|||
{
|
||||
if (swkbd_hasKeyboardInputHook())
|
||||
swkbd_keyInput(event.GetUnicodeKey());
|
||||
|
||||
|
||||
event.Skip();
|
||||
}
|
||||
|
||||
|
|
@ -198,7 +203,7 @@ void PadViewFrame::OnMouseLeft(wxMouseEvent& event)
|
|||
instance.m_pad_mouse.position = { physPos.x, physPos.y };
|
||||
if (event.ButtonDown(wxMOUSE_BTN_LEFT))
|
||||
instance.m_pad_mouse.left_down_toggle = true;
|
||||
|
||||
|
||||
}
|
||||
|
||||
void PadViewFrame::OnMouseRight(wxMouseEvent& event)
|
||||
|
|
|
|||
61
src/gui/wxgui/canvas/MetalCanvas.cpp
Normal file
61
src/gui/wxgui/canvas/MetalCanvas.cpp
Normal file
|
|
@ -0,0 +1,61 @@
|
|||
#include "wxgui/canvas/MetalCanvas.h"
|
||||
#include "Cafe/HW/Latte/Renderer/Metal/MetalRenderer.h"
|
||||
|
||||
#include <wx/msgdlg.h>
|
||||
#include <helpers/wxHelpers.h>
|
||||
|
||||
MetalCanvas::MetalCanvas(wxWindow* parent, const wxSize& size, bool is_main_window)
|
||||
: IRenderCanvas(is_main_window), wxWindow(parent, wxID_ANY, wxDefaultPosition, size, wxNO_FULL_REPAINT_ON_RESIZE | wxWANTS_CHARS)
|
||||
{
|
||||
Bind(wxEVT_PAINT, &MetalCanvas::OnPaint, this);
|
||||
Bind(wxEVT_SIZE, &MetalCanvas::OnResize, this);
|
||||
|
||||
auto& canvas = is_main_window ? WindowSystem::GetWindowInfo().canvas_main : WindowSystem::GetWindowInfo().canvas_pad;
|
||||
canvas = initHandleContextFromWxWidgetsWindow(this);
|
||||
|
||||
try
|
||||
{
|
||||
if (is_main_window)
|
||||
g_renderer = std::make_unique<MetalRenderer>();
|
||||
|
||||
auto metal_renderer = MetalRenderer::GetInstance();
|
||||
metal_renderer->InitializeLayer({size.x, size.y}, is_main_window);
|
||||
}
|
||||
catch(const std::exception& ex)
|
||||
{
|
||||
cemuLog_log(LogType::Force, "Error when initializing Metal renderer: {}", ex.what());
|
||||
auto msg = formatWxString(_("Error when initializing Metal renderer:\n{}"), ex.what());
|
||||
wxMessageDialog dialog(this, msg, _("Error"), wxOK | wxCENTRE | wxICON_ERROR);
|
||||
dialog.ShowModal();
|
||||
exit(0);
|
||||
}
|
||||
|
||||
wxWindow::EnableTouchEvents(wxTOUCH_PAN_GESTURES);
|
||||
}
|
||||
|
||||
MetalCanvas::~MetalCanvas()
|
||||
{
|
||||
Unbind(wxEVT_PAINT, &MetalCanvas::OnPaint, this);
|
||||
Unbind(wxEVT_SIZE, &MetalCanvas::OnResize, this);
|
||||
|
||||
MetalRenderer* mtlr = (MetalRenderer*)g_renderer.get();
|
||||
if (mtlr)
|
||||
mtlr->ShutdownLayer(m_is_main_window);
|
||||
}
|
||||
|
||||
void MetalCanvas::OnPaint(wxPaintEvent& event)
|
||||
{
|
||||
}
|
||||
|
||||
void MetalCanvas::OnResize(wxSizeEvent& event)
|
||||
{
|
||||
const wxSize size = GetSize();
|
||||
if (size.GetWidth() == 0 || size.GetHeight() == 0)
|
||||
return;
|
||||
|
||||
const wxRect refreshRect(size);
|
||||
RefreshRect(refreshRect, false);
|
||||
|
||||
auto metal_renderer = MetalRenderer::GetInstance();
|
||||
metal_renderer->ResizeLayer({size.x, size.y}, m_is_main_window);
|
||||
}
|
||||
19
src/gui/wxgui/canvas/MetalCanvas.h
Normal file
19
src/gui/wxgui/canvas/MetalCanvas.h
Normal file
|
|
@ -0,0 +1,19 @@
|
|||
#pragma once
|
||||
|
||||
#include "wxgui/canvas/IRenderCanvas.h"
|
||||
|
||||
#include <wx/frame.h>
|
||||
|
||||
#include <set>
|
||||
|
||||
class MetalCanvas : public IRenderCanvas, public wxWindow
|
||||
{
|
||||
public:
|
||||
MetalCanvas(wxWindow* parent, const wxSize& size, bool is_main_window);
|
||||
~MetalCanvas();
|
||||
|
||||
private:
|
||||
|
||||
void OnPaint(wxPaintEvent& event);
|
||||
void OnResize(wxSizeEvent& event);
|
||||
};
|
||||
|
|
@ -72,8 +72,11 @@ std::vector<fs::path> _getCachesPaths(const TitleId& titleId)
|
|||
ActiveSettings::GetCachePath(L"shaderCache/driver/vk/{:016x}.bin", titleId),
|
||||
ActiveSettings::GetCachePath(L"shaderCache/precompiled/{:016x}_spirv.bin", titleId),
|
||||
ActiveSettings::GetCachePath(L"shaderCache/precompiled/{:016x}_gl.bin", titleId),
|
||||
ActiveSettings::GetCachePath(L"shaderCache/precompiled/{:016x}_air.bin", titleId),
|
||||
ActiveSettings::GetCachePath(L"shaderCache/transferable/{:016x}_shaders.bin", titleId),
|
||||
ActiveSettings::GetCachePath(L"shaderCache/transferable/{:016x}_vkpipeline.bin", titleId)};
|
||||
ActiveSettings::GetCachePath(L"shaderCache/transferable/{:016x}_mtlshaders.bin", titleId),
|
||||
ActiveSettings::GetCachePath(L"shaderCache/transferable/{:016x}_vkpipeline.bin", titleId),
|
||||
ActiveSettings::GetCachePath(L"shaderCache/transferable/{:016x}_mtlpipeline.bin", titleId)};
|
||||
|
||||
cachePaths.erase(std::remove_if(cachePaths.begin(), cachePaths.end(),
|
||||
[](const fs::path& cachePath) {
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue