diff --git a/src/xenia/app/emulator_window.cc b/src/xenia/app/emulator_window.cc index 075497bee..f2238d41e 100644 --- a/src/xenia/app/emulator_window.cc +++ b/src/xenia/app/emulator_window.cc @@ -31,7 +31,6 @@ #include "xenia/cpu/processor.h" #include "xenia/emulator.h" #include "xenia/gpu/command_processor.h" -#include "xenia/gpu/d3d12/d3d12_command_processor.h" #include "xenia/gpu/graphics_system.h" #include "xenia/hid/input_system.h" #include "xenia/kernel/xam/profile_manager.h" @@ -58,7 +57,9 @@ DECLARE_bool(guide_button); DECLARE_bool(clear_memory_page_state); -DECLARE_bool(d3d12_readback_resolve); +DECLARE_bool(readback_resolve); + +DECLARE_bool(readback_memexport); DEFINE_bool(fullscreen, false, "Whether to launch the emulator in fullscreen.", "Display"); @@ -1674,7 +1675,7 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey( } } break; case ButtonFunctions::ClearMemoryPageState: - ToggleGPUSetting(gpu_cvar::ClearMemoryPageState); + ToggleGPUSetting(GPUSetting::ClearMemoryPageState); // Assume the user wants ClearCaches as well if (cvars::clear_memory_page_state) { @@ -1689,10 +1690,10 @@ EmulatorWindow::ControllerHotKey EmulatorWindow::ProcessControllerHotkey( xe::threading::Sleep(delay); break; case ButtonFunctions::ReadbackResolve: - ToggleGPUSetting(gpu_cvar::ReadbackResolve); + ToggleGPUSetting(GPUSetting::ReadbackResolve); notificationTitle = "Toggle Readback Resolve"; - notificationDesc = cvars::d3d12_readback_resolve ? "Enabled" : "Disabled"; + notificationDesc = cvars::readback_resolve ? "Enabled" : "Disabled"; // Extra Sleep xe::threading::Sleep(delay); @@ -1862,15 +1863,17 @@ void EmulatorWindow::GamepadHotKeys() { } } -void EmulatorWindow::ToggleGPUSetting(gpu_cvar value) { - switch (value) { - case gpu_cvar::ClearMemoryPageState: - CommonSaveGPUSetting(CommonGPUSetting::ClearMemoryPageState, - !cvars::clear_memory_page_state); +void EmulatorWindow::ToggleGPUSetting(gpu::GPUSetting setting) { + switch (setting) { + case GPUSetting::ClearMemoryPageState: + SaveGPUSetting(GPUSetting::ClearMemoryPageState, + !cvars::clear_memory_page_state); break; - case gpu_cvar::ReadbackResolve: - D3D12SaveGPUSetting(D3D12GPUSetting::ReadbackResolve, - !cvars::d3d12_readback_resolve); + case GPUSetting::ReadbackResolve: + SaveGPUSetting(GPUSetting::ReadbackResolve, !cvars::readback_resolve); + break; + case GPUSetting::ReadbackMemexport: + SaveGPUSetting(GPUSetting::ReadbackMemexport, !cvars::readback_memexport); break; } } @@ -1915,7 +1918,7 @@ void EmulatorWindow::DisplayHotKeysConfig() { msg += "\n"; msg += "Readback Resolve: " + - xe::string_util::BoolToString(cvars::d3d12_readback_resolve); + xe::string_util::BoolToString(cvars::readback_resolve); msg += "\n"; msg += "Clear Memory Page State: " + diff --git a/src/xenia/app/emulator_window.h b/src/xenia/app/emulator_window.h index 945991465..7e58a3372 100644 --- a/src/xenia/app/emulator_window.h +++ b/src/xenia/app/emulator_window.h @@ -112,11 +112,6 @@ class EmulatorWindow { Unknown }; - enum class gpu_cvar { - ClearMemoryPageState, - ReadbackResolve, - }; - class ControllerHotKey { public: // If true the hotkey can be activated while a title is running, otherwise @@ -235,7 +230,7 @@ class EmulatorWindow { void VibrateController(xe::hid::InputSystem* input_sys, uint32_t user_index, bool vibrate = true); void GamepadHotKeys(); - void ToggleGPUSetting(gpu_cvar index); + void ToggleGPUSetting(gpu::GPUSetting setting); void DisplayHotKeysConfig(); static std::string CanonicalizeFileExtension( diff --git a/src/xenia/gpu/command_processor.cc b/src/xenia/gpu/command_processor.cc index 8338d0dd2..6337b8c80 100644 --- a/src/xenia/gpu/command_processor.cc +++ b/src/xenia/gpu/command_processor.cc @@ -50,17 +50,52 @@ DEFINE_bool(clear_memory_page_state, false, "for 'Team Ninja' Games to fix missing character models)", "GPU"); +DEFINE_bool( + readback_resolve, false, + "[D3D12 Only] Read render-to-texture results on the CPU. This may be " + "needed in some games, for instance, for screenshots in saved games, but " + "causes mid-frame synchronization, so it has a huge performance impact.", + "GPU"); + +DEFINE_bool( + readback_memexport, false, + "[D3D12 Only] Read data written by memory export in shaders on the CPU. " + "This may be needed in some games (but many only access exported data on " + "the GPU, and this flag isn't needed to handle such behavior), but causes " + "mid-frame synchronization, so it has a huge performance impact.", + "GPU"); + namespace xe { namespace gpu { -void CommonSaveGPUSetting(CommonGPUSetting setting, uint64_t value) { +// This should be written completely differently with support for different +// types. +void SaveGPUSetting(GPUSetting setting, uint64_t value) { switch (setting) { - case CommonGPUSetting::ClearMemoryPageState: - OVERRIDE_bool(clear_memory_page_state, (bool)value); + case GPUSetting::ClearMemoryPageState: + OVERRIDE_bool(clear_memory_page_state, static_cast(value)); + break; + case GPUSetting::ReadbackResolve: + OVERRIDE_bool(readback_resolve, static_cast(value)); + break; + case GPUSetting::ReadbackMemexport: + OVERRIDE_bool(readback_memexport, static_cast(value)); break; } } +bool GetGPUSetting(GPUSetting setting) { + switch (setting) { + case GPUSetting::ClearMemoryPageState: + return cvars::clear_memory_page_state; + case GPUSetting::ReadbackResolve: + return cvars::readback_resolve; + case GPUSetting::ReadbackMemexport: + return cvars::readback_memexport; + } + return false; +} + using namespace xe::gpu::xenos; CommandProcessor::CommandProcessor(GraphicsSystem* graphics_system, diff --git a/src/xenia/gpu/command_processor.h b/src/xenia/gpu/command_processor.h index 90f5060a6..0a65b34f8 100644 --- a/src/xenia/gpu/command_processor.h +++ b/src/xenia/gpu/command_processor.h @@ -33,11 +33,14 @@ class ByteStream; namespace gpu { -enum class CommonGPUSetting { +enum class GPUSetting { ClearMemoryPageState, + ReadbackResolve, + ReadbackMemexport }; -void CommonSaveGPUSetting(CommonGPUSetting setting, uint64_t value); +void SaveGPUSetting(GPUSetting setting, uint64_t value); +bool GetGPUSetting(GPUSetting setting); class GraphicsSystem; class Shader; diff --git a/src/xenia/gpu/d3d12/d3d12_command_processor.cc b/src/xenia/gpu/d3d12/d3d12_command_processor.cc index c658a86ae..1c664ca18 100644 --- a/src/xenia/gpu/d3d12/d3d12_command_processor.cc +++ b/src/xenia/gpu/d3d12/d3d12_command_processor.cc @@ -32,19 +32,7 @@ DEFINE_bool(d3d12_bindless, true, "Use bindless resources where available - may improve performance, " "but may make debugging more complicated.", "D3D12"); -DEFINE_bool(d3d12_readback_memexport, false, - "Read data written by memory export in shaders on the CPU. This " - "may be needed in some games (but many only access exported data " - "on the GPU, and this flag isn't needed to handle such behavior), " - "but causes mid-frame synchronization, so it has a huge " - "performance impact.", - "D3D12"); -DEFINE_bool(d3d12_readback_resolve, false, - "Read render-to-texture results on the CPU. This may be needed in " - "some games, for instance, for screenshots in saved games, but " - "causes mid-frame synchronization, so it has a huge performance " - "impact.", - "D3D12"); + DEFINE_bool(d3d12_submit_on_primary_buffer_end, true, "Submit the command list when a PM4 primary buffer ends if it's " "possible to submit immediately to try to reduce frame latency.", @@ -54,15 +42,6 @@ DECLARE_bool(clear_memory_page_state); namespace xe { namespace gpu { - -void D3D12SaveGPUSetting(D3D12GPUSetting setting, uint64_t value) { - switch (setting) { - case D3D12GPUSetting::ReadbackResolve: - OVERRIDE_bool(d3d12_readback_resolve, (bool)value); - break; - } -} - namespace d3d12 { // Generated with `xb buildshaders`. @@ -3011,7 +2990,7 @@ bool D3D12CommandProcessor::IssueDraw(xenos::PrimitiveType primitive_type, memexport_range.base_address_dwords << 2, memexport_range.size_bytes, false); } - if (cvars::d3d12_readback_memexport) { + if (GetGPUSetting(GPUSetting::ReadbackResolve)) { // Read the exported data on the CPU. uint32_t memexport_total_size = 0; for (const draw_util::MemExportRange& memexport_range : @@ -3091,7 +3070,7 @@ bool D3D12CommandProcessor::IssueCopy() { if (!BeginSubmission(true)) { return false; } - if (!cvars::d3d12_readback_resolve) { + if (!GetGPUSetting(GPUSetting::ReadbackResolve)) { uint32_t written_address, written_length; return render_target_cache_->Resolve(*memory_, *shared_memory_, *texture_cache_, written_address,