diff options
36 files changed, 358 insertions, 355 deletions
diff --git a/externals/FidelityFX-FSR/ffx-fsr/ffx_fsr1.h b/externals/FidelityFX-FSR/ffx-fsr/ffx_fsr1.h index 15ecfde5c..4e0b3d548 100644 --- a/externals/FidelityFX-FSR/ffx-fsr/ffx_fsr1.h +++ b/externals/FidelityFX-FSR/ffx-fsr/ffx_fsr1.h @@ -747,12 +747,12 @@ AF1 sharpness){ // Immediate constants for peak range. AF2 peakC=AF2(1.0,-1.0*4.0); // Limiters, these need to be high precision RCPs. - AF1 hitMinR=mn4R*ARcpF1(AF1_(4.0)*mx4R); - AF1 hitMinG=mn4G*ARcpF1(AF1_(4.0)*mx4G); - AF1 hitMinB=mn4B*ARcpF1(AF1_(4.0)*mx4B); - AF1 hitMaxR=(peakC.x-mx4R)*ARcpF1(AF1_(4.0)*mn4R+peakC.y); - AF1 hitMaxG=(peakC.x-mx4G)*ARcpF1(AF1_(4.0)*mn4G+peakC.y); - AF1 hitMaxB=(peakC.x-mx4B)*ARcpF1(AF1_(4.0)*mn4B+peakC.y); + AF1 hitMinR=min(mn4R,eR)*ARcpF1(AF1_(4.0)*mx4R); + AF1 hitMinG=min(mn4G,eG)*ARcpF1(AF1_(4.0)*mx4G); + AF1 hitMinB=min(mn4B,eB)*ARcpF1(AF1_(4.0)*mx4B); + AF1 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpF1(AF1_(4.0)*mn4R+peakC.y); + AF1 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpF1(AF1_(4.0)*mn4G+peakC.y); + AF1 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpF1(AF1_(4.0)*mn4B+peakC.y); AF1 lobeR=max(-hitMinR,hitMaxR); AF1 lobeG=max(-hitMinG,hitMaxG); AF1 lobeB=max(-hitMinB,hitMaxB); @@ -845,12 +845,12 @@ AF1 sharpness){ // Immediate constants for peak range. AH2 peakC=AH2(1.0,-1.0*4.0); // Limiters, these need to be high precision RCPs. - AH1 hitMinR=mn4R*ARcpH1(AH1_(4.0)*mx4R); - AH1 hitMinG=mn4G*ARcpH1(AH1_(4.0)*mx4G); - AH1 hitMinB=mn4B*ARcpH1(AH1_(4.0)*mx4B); - AH1 hitMaxR=(peakC.x-mx4R)*ARcpH1(AH1_(4.0)*mn4R+peakC.y); - AH1 hitMaxG=(peakC.x-mx4G)*ARcpH1(AH1_(4.0)*mn4G+peakC.y); - AH1 hitMaxB=(peakC.x-mx4B)*ARcpH1(AH1_(4.0)*mn4B+peakC.y); + AH1 hitMinR=min(mn4R,eR)*ARcpH1(AH1_(4.0)*mx4R); + AH1 hitMinG=min(mn4G,eG)*ARcpH1(AH1_(4.0)*mx4G); + AH1 hitMinB=min(mn4B,eB)*ARcpH1(AH1_(4.0)*mx4B); + AH1 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpH1(AH1_(4.0)*mn4R+peakC.y); + AH1 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpH1(AH1_(4.0)*mn4G+peakC.y); + AH1 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpH1(AH1_(4.0)*mn4B+peakC.y); AH1 lobeR=max(-hitMinR,hitMaxR); AH1 lobeG=max(-hitMinG,hitMaxG); AH1 lobeB=max(-hitMinB,hitMaxB); @@ -963,12 +963,12 @@ AF1 sharpness){ // Immediate constants for peak range. AH2 peakC=AH2(1.0,-1.0*4.0); // Limiters, these need to be high precision RCPs. - AH2 hitMinR=mn4R*ARcpH2(AH2_(4.0)*mx4R); - AH2 hitMinG=mn4G*ARcpH2(AH2_(4.0)*mx4G); - AH2 hitMinB=mn4B*ARcpH2(AH2_(4.0)*mx4B); - AH2 hitMaxR=(peakC.x-mx4R)*ARcpH2(AH2_(4.0)*mn4R+peakC.y); - AH2 hitMaxG=(peakC.x-mx4G)*ARcpH2(AH2_(4.0)*mn4G+peakC.y); - AH2 hitMaxB=(peakC.x-mx4B)*ARcpH2(AH2_(4.0)*mn4B+peakC.y); + AH2 hitMinR=min(mn4R,eR)*ARcpH2(AH2_(4.0)*mx4R); + AH2 hitMinG=min(mn4G,eG)*ARcpH2(AH2_(4.0)*mx4G); + AH2 hitMinB=min(mn4B,eB)*ARcpH2(AH2_(4.0)*mx4B); + AH2 hitMaxR=(peakC.x-max(mx4R,eR))*ARcpH2(AH2_(4.0)*mn4R+peakC.y); + AH2 hitMaxG=(peakC.x-max(mx4G,eG))*ARcpH2(AH2_(4.0)*mn4G+peakC.y); + AH2 hitMaxB=(peakC.x-max(mx4B,eB))*ARcpH2(AH2_(4.0)*mn4B+peakC.y); AH2 lobeR=max(-hitMinR,hitMaxR); AH2 lobeG=max(-hitMinG,hitMaxG); AH2 lobeB=max(-hitMinB,hitMaxB); diff --git a/externals/ffmpeg/CMakeLists.txt b/externals/ffmpeg/CMakeLists.txt index c57b54f77..be8325b47 100644 --- a/externals/ffmpeg/CMakeLists.txt +++ b/externals/ffmpeg/CMakeLists.txt @@ -95,7 +95,8 @@ if (NOT WIN32) # ffnvenc could load CUDA libraries at the runtime using dlopen/dlsym or LoadLibrary/GetProcAddress # here we handle the hard-linking senario where CUDA is linked during compilation if (CUDA_FOUND) - list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS}) + # This line causes build error if CUDA_INCLUDE_DIRS is anything but a single non-empty value + #list(APPEND FFmpeg_HWACCEL_FLAGS --extra-cflags=-I${CUDA_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_LIBRARIES ${CUDA_LIBRARIES}) list(APPEND FFmpeg_HWACCEL_INCLUDE_DIRS ${CUDA_INCLUDE_DIRS}) list(APPEND FFmpeg_HWACCEL_LDFLAGS ${CUDA_LDFLAGS}) @@ -119,6 +120,8 @@ if (NOT WIN32) # `configure` parameters builds only exactly what yuzu needs from FFmpeg # `--disable-vdpau` is needed to avoid linking issues + set(FFmpeg_CC ${CMAKE_C_COMPILER_LAUNCHER} ${CMAKE_C_COMPILER}) + set(FFmpeg_CXX ${CMAKE_CXX_COMPILER_LAUNCHER} ${CMAKE_CXX_COMPILER}) add_custom_command( OUTPUT ${FFmpeg_MAKEFILE} @@ -137,12 +140,14 @@ if (NOT WIN32) --enable-decoder=h264 --enable-decoder=vp8 --enable-decoder=vp9 - --cc="${CMAKE_C_COMPILER}" - --cxx="${CMAKE_CXX_COMPILER}" + --cc="${FFmpeg_CC}" + --cxx="${FFmpeg_CXX}" ${FFmpeg_HWACCEL_FLAGS} WORKING_DIRECTORY ${FFmpeg_BUILD_DIR} ) + unset(FFmpeg_CC) + unset(FFmpeg_CXX) unset(FFmpeg_HWACCEL_FLAGS) # Workaround for Ubuntu 18.04's older version of make not being able to call make as a child diff --git a/src/audio_core/stream.cpp b/src/audio_core/stream.cpp index 5a30f55a7..0abc989b2 100644 --- a/src/audio_core/stream.cpp +++ b/src/audio_core/stream.cpp @@ -79,8 +79,8 @@ static void VolumeAdjustSamples(std::vector<s16>& samples, float game_volume) { return; } - // Implementation of a volume slider with a dynamic range of 60 dB - const float volume_scale_factor = volume == 0 ? 0 : std::exp(6.90775f * volume) * 0.001f; + // Perceived volume is not the same as the volume level + const float volume_scale_factor = (0.85f * ((volume * volume) - volume)) + volume; for (auto& sample : samples) { sample = static_cast<s16>(sample * volume_scale_factor); } diff --git a/src/common/settings.h b/src/common/settings.h index d01c0448c..9bee6e10f 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -554,6 +554,7 @@ struct Values { Setting<bool> use_docked_mode{true, "use_docked_mode"}; BasicSetting<bool> enable_raw_input{false, "enable_raw_input"}; + BasicSetting<bool> controller_navigation{true, "controller_navigation"}; Setting<bool> vibration_enabled{true, "vibration_enabled"}; Setting<bool> enable_accurate_vibrations{false, "enable_accurate_vibrations"}; diff --git a/src/core/hle/kernel/k_affinity_mask.h b/src/core/hle/kernel/k_affinity_mask.h index b906895fc..cf704ce87 100644 --- a/src/core/hle/kernel/k_affinity_mask.h +++ b/src/core/hle/kernel/k_affinity_mask.h @@ -31,8 +31,6 @@ public: } constexpr void SetAffinity(s32 core, bool set) { - ASSERT(0 <= core && core < static_cast<s32>(Core::Hardware::NUM_CPU_CORES)); - if (set) { this->mask |= GetCoreBit(core); } else { diff --git a/src/core/hle/kernel/k_process.cpp b/src/core/hle/kernel/k_process.cpp index 265ac6fa1..85c506979 100644 --- a/src/core/hle/kernel/k_process.cpp +++ b/src/core/hle/kernel/k_process.cpp @@ -146,6 +146,13 @@ ResultCode KProcess::Initialize(KProcess* process, Core::System& system, std::st // Open a reference to the resource limit. process->resource_limit->Open(); + // Clear remaining fields. + process->num_running_threads = 0; + process->is_signaled = false; + process->exception_thread = nullptr; + process->is_suspended = false; + process->schedule_count = 0; + return ResultSuccess; } @@ -157,20 +164,17 @@ KResourceLimit* KProcess::GetResourceLimit() const { return resource_limit; } -void KProcess::IncrementThreadCount() { - ASSERT(num_threads >= 0); - num_created_threads++; - - if (const auto count = ++num_threads; count > peak_num_threads) { - peak_num_threads = count; - } +void KProcess::IncrementRunningThreadCount() { + ASSERT(num_running_threads.load() >= 0); + ++num_running_threads; } -void KProcess::DecrementThreadCount() { - ASSERT(num_threads > 0); +void KProcess::DecrementRunningThreadCount() { + ASSERT(num_running_threads.load() > 0); - if (const auto count = --num_threads; count == 0) { - LOG_WARNING(Kernel, "Process termination is not fully implemented."); + if (const auto prev = num_running_threads--; prev == 1) { + // TODO(bunnei): Process termination to be implemented when multiprocess is supported. + UNIMPLEMENTED_MSG("KProcess termination is not implemennted!"); } } diff --git a/src/core/hle/kernel/k_process.h b/src/core/hle/kernel/k_process.h index c2a672021..38b446350 100644 --- a/src/core/hle/kernel/k_process.h +++ b/src/core/hle/kernel/k_process.h @@ -235,8 +235,8 @@ public: ++schedule_count; } - void IncrementThreadCount(); - void DecrementThreadCount(); + void IncrementRunningThreadCount(); + void DecrementRunningThreadCount(); void SetRunningThread(s32 core, KThread* thread, u64 idle_count) { running_threads[core] = thread; @@ -473,9 +473,7 @@ private: bool is_suspended{}; bool is_initialized{}; - std::atomic<s32> num_created_threads{}; - std::atomic<u16> num_threads{}; - u16 peak_num_threads{}; + std::atomic<u16> num_running_threads{}; std::array<KThread*, Core::Hardware::NUM_CPU_CORES> running_threads{}; std::array<u64, Core::Hardware::NUM_CPU_CORES> running_thread_idle_counts{}; diff --git a/src/core/hle/kernel/k_thread.cpp b/src/core/hle/kernel/k_thread.cpp index f42abb8a1..de3ffe0c7 100644 --- a/src/core/hle/kernel/k_thread.cpp +++ b/src/core/hle/kernel/k_thread.cpp @@ -215,7 +215,6 @@ ResultCode KThread::Initialize(KThreadFunction func, uintptr_t arg, VAddr user_s parent = owner; parent->Open(); - parent->IncrementThreadCount(); } // Initialize thread context. @@ -327,11 +326,6 @@ void KThread::Finalize() { } } - // Decrement the parent process's thread count. - if (parent != nullptr) { - parent->DecrementThreadCount(); - } - // Perform inherited finalization. KSynchronizationObject::Finalize(); } @@ -1011,7 +1005,7 @@ ResultCode KThread::Run() { if (IsUserThread() && IsSuspended()) { this->UpdateState(); } - owner->IncrementThreadCount(); + owner->IncrementRunningThreadCount(); } // Set our state and finish. @@ -1026,10 +1020,11 @@ ResultCode KThread::Run() { void KThread::Exit() { ASSERT(this == GetCurrentThreadPointer(kernel)); - // Release the thread resource hint from parent. + // Release the thread resource hint, running thread count from parent. if (parent != nullptr) { parent->GetResourceLimit()->Release(Kernel::LimitableResource::Threads, 0, 1); resource_limit_release_hint = true; + parent->DecrementRunningThreadCount(); } // Perform termination. diff --git a/src/input_common/drivers/udp_client.cpp b/src/input_common/drivers/udp_client.cpp index 9aaeb91be..d1cdb1ab2 100644 --- a/src/input_common/drivers/udp_client.cpp +++ b/src/input_common/drivers/udp_client.cpp @@ -339,7 +339,7 @@ void UDPClient::StartCommunication(std::size_t client, const std::string& host, } } -const PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const { +PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const { const std::size_t client = pad_index / PADS_PER_CLIENT; return { .guid = clients[client].uuid, @@ -348,9 +348,9 @@ const PadIdentifier UDPClient::GetPadIdentifier(std::size_t pad_index) const { }; } -const Common::UUID UDPClient::GetHostUUID(const std::string host) const { - const auto ip = boost::asio::ip::address_v4::from_string(host); - const auto hex_host = fmt::format("{:06x}", ip.to_ulong()); +Common::UUID UDPClient::GetHostUUID(const std::string& host) const { + const auto ip = boost::asio::ip::make_address_v4(host); + const auto hex_host = fmt::format("{:06x}", ip.to_uint()); return Common::UUID{hex_host}; } diff --git a/src/input_common/drivers/udp_client.h b/src/input_common/drivers/udp_client.h index 61a1fff37..30d7c2682 100644 --- a/src/input_common/drivers/udp_client.h +++ b/src/input_common/drivers/udp_client.h @@ -145,8 +145,8 @@ private: void OnPortInfo(Response::PortInfo); void OnPadData(Response::PadData, std::size_t client); void StartCommunication(std::size_t client, const std::string& host, u16 port); - const PadIdentifier GetPadIdentifier(std::size_t pad_index) const; - const Common::UUID GetHostUUID(const std::string host) const; + PadIdentifier GetPadIdentifier(std::size_t pad_index) const; + Common::UUID GetHostUUID(const std::string& host) const; Common::Input::ButtonNames GetUIButtonName(const Common::ParamPackage& params) const; diff --git a/src/input_common/input_engine.h b/src/input_common/input_engine.h index 390581c94..fe2faee5a 100644 --- a/src/input_common/input_engine.h +++ b/src/input_common/input_engine.h @@ -16,7 +16,7 @@ // Pad Identifier of data source struct PadIdentifier { - Common::UUID guid{}; + Common::UUID guid{Common::INVALID_UUID}; std::size_t port{}; std::size_t pad{}; @@ -89,7 +89,7 @@ struct UpdateCallback { // Triggered if data changed on the controller and the engine is on configuring mode struct MappingCallback { - std::function<void(MappingData)> on_data; + std::function<void(const MappingData&)> on_data; }; // Input Identifier of data source diff --git a/src/input_common/input_mapping.cpp b/src/input_common/input_mapping.cpp index 475257f42..a7a6ad8c2 100644 --- a/src/input_common/input_mapping.cpp +++ b/src/input_common/input_mapping.cpp @@ -2,14 +2,13 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included -#include "common/common_types.h" #include "common/settings.h" #include "input_common/input_engine.h" #include "input_common/input_mapping.h" namespace InputCommon { -MappingFactory::MappingFactory() {} +MappingFactory::MappingFactory() = default; void MappingFactory::BeginMapping(Polling::InputType type) { is_enabled = true; @@ -19,7 +18,7 @@ void MappingFactory::BeginMapping(Polling::InputType type) { second_axis = -1; } -[[nodiscard]] const Common::ParamPackage MappingFactory::GetNextInput() { +Common::ParamPackage MappingFactory::GetNextInput() { Common::ParamPackage input; input_queue.Pop(input); return input; @@ -57,7 +56,7 @@ void MappingFactory::StopMapping() { void MappingFactory::RegisterButton(const MappingData& data) { Common::ParamPackage new_input; new_input.Set("engine", data.engine); - if (data.pad.guid != Common::UUID{}) { + if (data.pad.guid.IsValid()) { new_input.Set("guid", data.pad.guid.Format()); } new_input.Set("port", static_cast<int>(data.pad.port)); @@ -93,7 +92,7 @@ void MappingFactory::RegisterButton(const MappingData& data) { void MappingFactory::RegisterStick(const MappingData& data) { Common::ParamPackage new_input; new_input.Set("engine", data.engine); - if (data.pad.guid != Common::UUID{}) { + if (data.pad.guid.IsValid()) { new_input.Set("guid", data.pad.guid.Format()); } new_input.Set("port", static_cast<int>(data.pad.port)); @@ -138,7 +137,7 @@ void MappingFactory::RegisterStick(const MappingData& data) { void MappingFactory::RegisterMotion(const MappingData& data) { Common::ParamPackage new_input; new_input.Set("engine", data.engine); - if (data.pad.guid != Common::UUID{}) { + if (data.pad.guid.IsValid()) { new_input.Set("guid", data.pad.guid.Format()); } new_input.Set("port", static_cast<int>(data.pad.port)); diff --git a/src/input_common/input_mapping.h b/src/input_common/input_mapping.h index 93564b5f8..e0dfbc7ad 100644 --- a/src/input_common/input_mapping.h +++ b/src/input_common/input_mapping.h @@ -3,8 +3,14 @@ // Refer to the license.txt file included #pragma once + +#include "common/param_package.h" #include "common/threadsafe_queue.h" +namespace InputCommon::Polling { +enum class InputType; +} + namespace InputCommon { class InputEngine; struct MappingData; @@ -20,7 +26,7 @@ public: void BeginMapping(Polling::InputType type); /// Returns an input event with mapping information from the input_queue - [[nodiscard]] const Common::ParamPackage GetNextInput(); + [[nodiscard]] Common::ParamPackage GetNextInput(); /** * Registers mapping input data from the driver diff --git a/src/input_common/main.cpp b/src/input_common/main.cpp index 940744c5f..a4d7ed645 100644 --- a/src/input_common/main.cpp +++ b/src/input_common/main.cpp @@ -27,7 +27,7 @@ namespace InputCommon { struct InputSubsystem::Impl { void Initialize() { mapping_factory = std::make_shared<MappingFactory>(); - MappingCallback mapping_callback{[this](MappingData data) { RegisterInput(data); }}; + MappingCallback mapping_callback{[this](const MappingData& data) { RegisterInput(data); }}; keyboard = std::make_shared<Keyboard>("keyboard"); keyboard->SetMappingCallback(mapping_callback); @@ -284,7 +284,7 @@ struct InputSubsystem::Impl { #endif } - void RegisterInput(MappingData data) { + void RegisterInput(const MappingData& data) { mapping_factory->RegisterInput(data); } @@ -394,7 +394,7 @@ void InputSubsystem::BeginMapping(Polling::InputType type) { impl->mapping_factory->BeginMapping(type); } -const Common::ParamPackage InputSubsystem::GetNextInput() const { +Common::ParamPackage InputSubsystem::GetNextInput() const { return impl->mapping_factory->GetNextInput(); } diff --git a/src/input_common/main.h b/src/input_common/main.h index c6f97f691..baf107e0f 100644 --- a/src/input_common/main.h +++ b/src/input_common/main.h @@ -126,7 +126,7 @@ public: void BeginMapping(Polling::InputType type); /// Returns an input event with mapping information. - [[nodiscard]] const Common::ParamPackage GetNextInput() const; + [[nodiscard]] Common::ParamPackage GetNextInput() const; /// Stop polling from all backends. void StopMapping() const; diff --git a/src/shader_recompiler/frontend/maxwell/translate_program.h b/src/shader_recompiler/frontend/maxwell/translate_program.h index cd535f20d..eac83da9d 100644 --- a/src/shader_recompiler/frontend/maxwell/translate_program.h +++ b/src/shader_recompiler/frontend/maxwell/translate_program.h @@ -21,7 +21,6 @@ namespace Shader::Maxwell { [[nodiscard]] IR::Program MergeDualVertexPrograms(IR::Program& vertex_a, IR::Program& vertex_b, Environment& env_vertex_b); -[[nodiscard]] void ConvertLegacyToGeneric(IR::Program& program, - const Shader::RuntimeInfo& runtime_info); +void ConvertLegacyToGeneric(IR::Program& program, const RuntimeInfo& runtime_info); } // namespace Shader::Maxwell diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index b18b8a02a..c38ebd670 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp @@ -240,7 +240,7 @@ void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters) ((method - MacroRegistersStart) >> 1) % static_cast<u32>(macro_positions.size()); // Execute the current macro. - macro_engine->Execute(*this, macro_positions[entry], parameters); + macro_engine->Execute(macro_positions[entry], parameters); if (mme_draw.current_mode != MMEDrawMode::Undefined) { FlushMMEInlineDraw(); } diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 3188b83ed..26b8ea233 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -12,9 +12,6 @@ #include "video_core/framebuffer_config.h" namespace Core { -namespace Frontend { -class EmuWindow; -} class System; } // namespace Core @@ -25,7 +22,6 @@ class ShaderNotify; namespace Tegra { class DmaPusher; -class CDmaPusher; struct CommandList; enum class RenderTargetFormat : u32 { @@ -88,15 +84,9 @@ enum class DepthFormat : u32 { D32_FLOAT_S8X24_UINT = 0x19, }; -struct CommandListHeader; -class DebugContext; - namespace Engines { -class Fermi2D; class Maxwell3D; -class MaxwellDMA; class KeplerCompute; -class KeplerMemory; } // namespace Engines enum class EngineID { @@ -190,12 +180,6 @@ public: /// Returns a const reference to the GPU DMA pusher. [[nodiscard]] const Tegra::DmaPusher& DmaPusher() const; - /// Returns a reference to the GPU CDMA pusher. - [[nodiscard]] Tegra::CDmaPusher& CDmaPusher(); - - /// Returns a const reference to the GPU CDMA pusher. - [[nodiscard]] const Tegra::CDmaPusher& CDmaPusher() const; - /// Returns a reference to the underlying renderer. [[nodiscard]] VideoCore::RendererBase& Renderer(); diff --git a/src/video_core/macro/macro.cpp b/src/video_core/macro/macro.cpp index d7fabe605..0aeda4ce8 100644 --- a/src/video_core/macro/macro.cpp +++ b/src/video_core/macro/macro.cpp @@ -2,12 +2,13 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <cstring> #include <optional> + #include <boost/container_hash/hash.hpp> + #include "common/assert.h" -#include "common/logging/log.h" #include "common/settings.h" -#include "video_core/engines/maxwell_3d.h" #include "video_core/macro/macro.h" #include "video_core/macro/macro_hle.h" #include "video_core/macro/macro_interpreter.h" @@ -24,8 +25,7 @@ void MacroEngine::AddCode(u32 method, u32 data) { uploaded_macro_code[method].push_back(data); } -void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method, - const std::vector<u32>& parameters) { +void MacroEngine::Execute(u32 method, const std::vector<u32>& parameters) { auto compiled_macro = macro_cache.find(method); if (compiled_macro != macro_cache.end()) { const auto& cache_info = compiled_macro->second; @@ -66,10 +66,9 @@ void MacroEngine::Execute(Engines::Maxwell3D& maxwell3d, u32 method, cache_info.lle_program = Compile(code); } - auto hle_program = hle_macros->GetHLEProgram(cache_info.hash); - if (hle_program.has_value()) { + if (auto hle_program = hle_macros->GetHLEProgram(cache_info.hash)) { cache_info.has_hle_program = true; - cache_info.hle_program = std::move(hle_program.value()); + cache_info.hle_program = std::move(hle_program); cache_info.hle_program->Execute(parameters, method); } else { cache_info.lle_program->Execute(parameters, method); diff --git a/src/video_core/macro/macro.h b/src/video_core/macro/macro.h index 31ee3440a..7aaa49286 100644 --- a/src/video_core/macro/macro.h +++ b/src/video_core/macro/macro.h @@ -119,7 +119,7 @@ public: void AddCode(u32 method, u32 data); // Compiles the macro if its not in the cache, and executes the compiled macro - void Execute(Engines::Maxwell3D& maxwell3d, u32 method, const std::vector<u32>& parameters); + void Execute(u32 method, const std::vector<u32>& parameters); protected: virtual std::unique_ptr<CachedMacro> Compile(const std::vector<u32>& code) = 0; diff --git a/src/video_core/macro/macro_hle.cpp b/src/video_core/macro/macro_hle.cpp index 70ac7c620..900ad23c9 100644 --- a/src/video_core/macro/macro_hle.cpp +++ b/src/video_core/macro/macro_hle.cpp @@ -5,12 +5,15 @@ #include <array> #include <vector> #include "video_core/engines/maxwell_3d.h" +#include "video_core/macro/macro.h" #include "video_core/macro/macro_hle.h" #include "video_core/rasterizer_interface.h" namespace Tegra { - namespace { + +using HLEFunction = void (*)(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters); + // HLE'd functions void HLE_771BB18C62444DA0(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters) { const u32 instance_count = parameters[2] & maxwell3d.GetRegisterValue(0xD1B); @@ -77,7 +80,6 @@ void HLE_0217920100488FF7(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& maxwell3d.CallMethodFromMME(0x8e5, 0x0); maxwell3d.mme_draw.current_mode = Engines::Maxwell3D::MMEDrawMode::Undefined; } -} // Anonymous namespace constexpr std::array<std::pair<u64, HLEFunction>, 3> hle_funcs{{ {0x771BB18C62444DA0, &HLE_771BB18C62444DA0}, @@ -85,25 +87,31 @@ constexpr std::array<std::pair<u64, HLEFunction>, 3> hle_funcs{{ {0x0217920100488FF7, &HLE_0217920100488FF7}, }}; +class HLEMacroImpl final : public CachedMacro { +public: + explicit HLEMacroImpl(Engines::Maxwell3D& maxwell3d_, HLEFunction func_) + : maxwell3d{maxwell3d_}, func{func_} {} + + void Execute(const std::vector<u32>& parameters, u32 method) override { + func(maxwell3d, parameters); + } + +private: + Engines::Maxwell3D& maxwell3d; + HLEFunction func; +}; +} // Anonymous namespace + HLEMacro::HLEMacro(Engines::Maxwell3D& maxwell3d_) : maxwell3d{maxwell3d_} {} HLEMacro::~HLEMacro() = default; -std::optional<std::unique_ptr<CachedMacro>> HLEMacro::GetHLEProgram(u64 hash) const { +std::unique_ptr<CachedMacro> HLEMacro::GetHLEProgram(u64 hash) const { const auto it = std::find_if(hle_funcs.cbegin(), hle_funcs.cend(), [hash](const auto& pair) { return pair.first == hash; }); if (it == hle_funcs.end()) { - return std::nullopt; + return nullptr; } return std::make_unique<HLEMacroImpl>(maxwell3d, it->second); } -HLEMacroImpl::~HLEMacroImpl() = default; - -HLEMacroImpl::HLEMacroImpl(Engines::Maxwell3D& maxwell3d_, HLEFunction func_) - : maxwell3d{maxwell3d_}, func{func_} {} - -void HLEMacroImpl::Execute(const std::vector<u32>& parameters, u32 method) { - func(maxwell3d, parameters); -} - } // namespace Tegra diff --git a/src/video_core/macro/macro_hle.h b/src/video_core/macro/macro_hle.h index cb3bd1600..b86ba84a1 100644 --- a/src/video_core/macro/macro_hle.h +++ b/src/video_core/macro/macro_hle.h @@ -5,10 +5,7 @@ #pragma once #include <memory> -#include <optional> -#include <vector> #include "common/common_types.h" -#include "video_core/macro/macro.h" namespace Tegra { @@ -16,29 +13,17 @@ namespace Engines { class Maxwell3D; } -using HLEFunction = void (*)(Engines::Maxwell3D& maxwell3d, const std::vector<u32>& parameters); - class HLEMacro { public: explicit HLEMacro(Engines::Maxwell3D& maxwell3d_); ~HLEMacro(); - std::optional<std::unique_ptr<CachedMacro>> GetHLEProgram(u64 hash) const; - -private: - Engines::Maxwell3D& maxwell3d; -}; - -class HLEMacroImpl : public CachedMacro { -public: - explicit HLEMacroImpl(Engines::Maxwell3D& maxwell3d, HLEFunction func); - ~HLEMacroImpl(); - - void Execute(const std::vector<u32>& parameters, u32 method) override; + // Allocates and returns a cached macro if the hash matches a known function. + // Returns nullptr otherwise. + [[nodiscard]] std::unique_ptr<CachedMacro> GetHLEProgram(u64 hash) const; private: Engines::Maxwell3D& maxwell3d; - HLEFunction func; }; } // namespace Tegra diff --git a/src/video_core/macro/macro_interpreter.cpp b/src/video_core/macro/macro_interpreter.cpp index 8da26fd59..fba755448 100644 --- a/src/video_core/macro/macro_interpreter.cpp +++ b/src/video_core/macro/macro_interpreter.cpp @@ -2,6 +2,9 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <array> +#include <optional> + #include "common/assert.h" #include "common/logging/log.h" #include "common/microprofile.h" @@ -11,16 +14,81 @@ MICROPROFILE_DEFINE(MacroInterp, "GPU", "Execute macro interpreter", MP_RGB(128, 128, 192)); namespace Tegra { -MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d_) - : MacroEngine{maxwell3d_}, maxwell3d{maxwell3d_} {} +namespace { +class MacroInterpreterImpl final : public CachedMacro { +public: + explicit MacroInterpreterImpl(Engines::Maxwell3D& maxwell3d_, const std::vector<u32>& code_) + : maxwell3d{maxwell3d_}, code{code_} {} -std::unique_ptr<CachedMacro> MacroInterpreter::Compile(const std::vector<u32>& code) { - return std::make_unique<MacroInterpreterImpl>(maxwell3d, code); -} + void Execute(const std::vector<u32>& params, u32 method) override; + +private: + /// Resets the execution engine state, zeroing registers, etc. + void Reset(); + + /** + * Executes a single macro instruction located at the current program counter. Returns whether + * the interpreter should keep running. + * + * @param is_delay_slot Whether the current step is being executed due to a delay slot in a + * previous instruction. + */ + bool Step(bool is_delay_slot); + + /// Calculates the result of an ALU operation. src_a OP src_b; + u32 GetALUResult(Macro::ALUOperation operation, u32 src_a, u32 src_b); + + /// Performs the result operation on the input result and stores it in the specified register + /// (if necessary). + void ProcessResult(Macro::ResultOperation operation, u32 reg, u32 result); + + /// Evaluates the branch condition and returns whether the branch should be taken or not. + bool EvaluateBranchCondition(Macro::BranchCondition cond, u32 value) const; + + /// Reads an opcode at the current program counter location. + Macro::Opcode GetOpcode() const; + + /// Returns the specified register's value. Register 0 is hardcoded to always return 0. + u32 GetRegister(u32 register_id) const; + + /// Sets the register to the input value. + void SetRegister(u32 register_id, u32 value); + + /// Sets the method address to use for the next Send instruction. + void SetMethodAddress(u32 address); -MacroInterpreterImpl::MacroInterpreterImpl(Engines::Maxwell3D& maxwell3d_, - const std::vector<u32>& code_) - : maxwell3d{maxwell3d_}, code{code_} {} + /// Calls a GPU Engine method with the input parameter. + void Send(u32 value); + + /// Reads a GPU register located at the method address. + u32 Read(u32 method) const; + + /// Returns the next parameter in the parameter queue. + u32 FetchParameter(); + + Engines::Maxwell3D& maxwell3d; + + /// Current program counter + u32 pc{}; + /// Program counter to execute at after the delay slot is executed. + std::optional<u32> delayed_pc; + + /// General purpose macro registers. + std::array<u32, Macro::NUM_MACRO_REGISTERS> registers = {}; + + /// Method address to use for the next Send instruction. + Macro::MethodAddress method_address = {}; + + /// Input parameters of the current macro. + std::unique_ptr<u32[]> parameters; + std::size_t num_parameters = 0; + std::size_t parameters_capacity = 0; + /// Index of the next parameter that will be fetched by the 'parm' instruction. + u32 next_parameter_index = 0; + + bool carry_flag = false; + const std::vector<u32>& code; +}; void MacroInterpreterImpl::Execute(const std::vector<u32>& params, u32 method) { MICROPROFILE_SCOPE(MacroInterp); @@ -283,5 +351,13 @@ u32 MacroInterpreterImpl::FetchParameter() { ASSERT(next_parameter_index < num_parameters); return parameters[next_parameter_index++]; } +} // Anonymous namespace + +MacroInterpreter::MacroInterpreter(Engines::Maxwell3D& maxwell3d_) + : MacroEngine{maxwell3d_}, maxwell3d{maxwell3d_} {} + +std::unique_ptr<CachedMacro> MacroInterpreter::Compile(const std::vector<u32>& code) { + return std::make_unique<MacroInterpreterImpl>(maxwell3d, code); +} } // namespace Tegra diff --git a/src/video_core/macro/macro_interpreter.h b/src/video_core/macro/macro_interpreter.h index d50c619ce..8a9648e46 100644 --- a/src/video_core/macro/macro_interpreter.h +++ b/src/video_core/macro/macro_interpreter.h @@ -3,10 +3,9 @@ // Refer to the license.txt file included. #pragma once -#include <array> -#include <optional> + #include <vector> -#include "common/bit_field.h" + #include "common/common_types.h" #include "video_core/macro/macro.h" @@ -26,77 +25,4 @@ private: Engines::Maxwell3D& maxwell3d; }; -class MacroInterpreterImpl : public CachedMacro { -public: - explicit MacroInterpreterImpl(Engines::Maxwell3D& maxwell3d_, const std::vector<u32>& code_); - void Execute(const std::vector<u32>& params, u32 method) override; - -private: - /// Resets the execution engine state, zeroing registers, etc. - void Reset(); - - /** - * Executes a single macro instruction located at the current program counter. Returns whether - * the interpreter should keep running. - * - * @param is_delay_slot Whether the current step is being executed due to a delay slot in a - * previous instruction. - */ - bool Step(bool is_delay_slot); - - /// Calculates the result of an ALU operation. src_a OP src_b; - u32 GetALUResult(Macro::ALUOperation operation, u32 src_a, u32 src_b); - - /// Performs the result operation on the input result and stores it in the specified register - /// (if necessary). - void ProcessResult(Macro::ResultOperation operation, u32 reg, u32 result); - - /// Evaluates the branch condition and returns whether the branch should be taken or not. - bool EvaluateBranchCondition(Macro::BranchCondition cond, u32 value) const; - - /// Reads an opcode at the current program counter location. - Macro::Opcode GetOpcode() const; - - /// Returns the specified register's value. Register 0 is hardcoded to always return 0. - u32 GetRegister(u32 register_id) const; - - /// Sets the register to the input value. - void SetRegister(u32 register_id, u32 value); - - /// Sets the method address to use for the next Send instruction. - void SetMethodAddress(u32 address); - - /// Calls a GPU Engine method with the input parameter. - void Send(u32 value); - - /// Reads a GPU register located at the method address. - u32 Read(u32 method) const; - - /// Returns the next parameter in the parameter queue. - u32 FetchParameter(); - - Engines::Maxwell3D& maxwell3d; - - /// Current program counter - u32 pc; - /// Program counter to execute at after the delay slot is executed. - std::optional<u32> delayed_pc; - - /// General purpose macro registers. - std::array<u32, Macro::NUM_MACRO_REGISTERS> registers = {}; - - /// Method address to use for the next Send instruction. - Macro::MethodAddress method_address = {}; - - /// Input parameters of the current macro. - std::unique_ptr<u32[]> parameters; - std::size_t num_parameters = 0; - std::size_t parameters_capacity = 0; - /// Index of the next parameter that will be fetched by the 'parm' instruction. - u32 next_parameter_index = 0; - - bool carry_flag = false; - const std::vector<u32>& code; -}; - } // namespace Tegra diff --git a/src/video_core/macro/macro_jit_x64.cpp b/src/video_core/macro/macro_jit_x64.cpp index c6b2b2109..924c9fe5c 100644 --- a/src/video_core/macro/macro_jit_x64.cpp +++ b/src/video_core/macro/macro_jit_x64.cpp @@ -2,9 +2,17 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <array> +#include <bitset> +#include <optional> + +#include <xbyak/xbyak.h> + #include "common/assert.h" +#include "common/bit_field.h" #include "common/logging/log.h" #include "common/microprofile.h" +#include "common/x64/xbyak_abi.h" #include "common/x64/xbyak_util.h" #include "video_core/engines/maxwell_3d.h" #include "video_core/macro/macro_interpreter.h" @@ -14,13 +22,14 @@ MICROPROFILE_DEFINE(MacroJitCompile, "GPU", "Compile macro JIT", MP_RGB(173, 255 MICROPROFILE_DEFINE(MacroJitExecute, "GPU", "Execute macro JIT", MP_RGB(255, 255, 0)); namespace Tegra { +namespace { constexpr Xbyak::Reg64 STATE = Xbyak::util::rbx; constexpr Xbyak::Reg32 RESULT = Xbyak::util::ebp; constexpr Xbyak::Reg64 PARAMETERS = Xbyak::util::r12; constexpr Xbyak::Reg32 METHOD_ADDRESS = Xbyak::util::r14d; constexpr Xbyak::Reg64 BRANCH_HOLDER = Xbyak::util::r15; -static const std::bitset<32> PERSISTENT_REGISTERS = Common::X64::BuildRegSet({ +const std::bitset<32> PERSISTENT_REGISTERS = Common::X64::BuildRegSet({ STATE, RESULT, PARAMETERS, @@ -28,19 +37,75 @@ static const std::bitset<32> PERSISTENT_REGISTERS = Common::X64::BuildRegSet({ BRANCH_HOLDER, }); -MacroJITx64::MacroJITx64(Engines::Maxwell3D& maxwell3d_) - : MacroEngine{maxwell3d_}, maxwell3d{maxwell3d_} {} +// Arbitrarily chosen based on current booting games. +constexpr size_t MAX_CODE_SIZE = 0x10000; -std::unique_ptr<CachedMacro> MacroJITx64::Compile(const std::vector<u32>& code) { - return std::make_unique<MacroJITx64Impl>(maxwell3d, code); +std::bitset<32> PersistentCallerSavedRegs() { + return PERSISTENT_REGISTERS & Common::X64::ABI_ALL_CALLER_SAVED; } -MacroJITx64Impl::MacroJITx64Impl(Engines::Maxwell3D& maxwell3d_, const std::vector<u32>& code_) - : CodeGenerator{MAX_CODE_SIZE}, code{code_}, maxwell3d{maxwell3d_} { - Compile(); -} +class MacroJITx64Impl final : public Xbyak::CodeGenerator, public CachedMacro { +public: + explicit MacroJITx64Impl(Engines::Maxwell3D& maxwell3d_, const std::vector<u32>& code_) + : CodeGenerator{MAX_CODE_SIZE}, code{code_}, maxwell3d{maxwell3d_} { + Compile(); + } + + void Execute(const std::vector<u32>& parameters, u32 method) override; + + void Compile_ALU(Macro::Opcode opcode); + void Compile_AddImmediate(Macro::Opcode opcode); + void Compile_ExtractInsert(Macro::Opcode opcode); + void Compile_ExtractShiftLeftImmediate(Macro::Opcode opcode); + void Compile_ExtractShiftLeftRegister(Macro::Opcode opcode); + void Compile_Read(Macro::Opcode opcode); + void Compile_Branch(Macro::Opcode opcode); + +private: + void Optimizer_ScanFlags(); + + void Compile(); + bool Compile_NextInstruction(); + + Xbyak::Reg32 Compile_FetchParameter(); + Xbyak::Reg32 Compile_GetRegister(u32 index, Xbyak::Reg32 dst); + + void Compile_ProcessResult(Macro::ResultOperation operation, u32 reg); + void Compile_Send(Xbyak::Reg32 value); -MacroJITx64Impl::~MacroJITx64Impl() = default; + Macro::Opcode GetOpCode() const; + + struct JITState { + Engines::Maxwell3D* maxwell3d{}; + std::array<u32, Macro::NUM_MACRO_REGISTERS> registers{}; + u32 carry_flag{}; + }; + static_assert(offsetof(JITState, maxwell3d) == 0, "Maxwell3D is not at 0x0"); + using ProgramType = void (*)(JITState*, const u32*); + + struct OptimizerState { + bool can_skip_carry{}; + bool has_delayed_pc{}; + bool zero_reg_skip{}; + bool skip_dummy_addimmediate{}; + bool optimize_for_method_move{}; + bool enable_asserts{}; + }; + OptimizerState optimizer{}; + + std::optional<Macro::Opcode> next_opcode{}; + ProgramType program{nullptr}; + + std::array<Xbyak::Label, MAX_CODE_SIZE> labels; + std::array<Xbyak::Label, MAX_CODE_SIZE> delay_skip; + Xbyak::Label end_of_code{}; + + bool is_delay_slot{}; + u32 pc{}; + + const std::vector<u32>& code; + Engines::Maxwell3D& maxwell3d; +}; void MacroJITx64Impl::Execute(const std::vector<u32>& parameters, u32 method) { MICROPROFILE_SCOPE(MacroJitExecute); @@ -307,11 +372,11 @@ void MacroJITx64Impl::Compile_Read(Macro::Opcode opcode) { Compile_ProcessResult(opcode.result_operation, opcode.dst); } -static void Send(Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) { +void Send(Engines::Maxwell3D* maxwell3d, Macro::MethodAddress method_address, u32 value) { maxwell3d->CallMethodFromMME(method_address.address, value); } -void Tegra::MacroJITx64Impl::Compile_Send(Xbyak::Reg32 value) { +void MacroJITx64Impl::Compile_Send(Xbyak::Reg32 value) { Common::X64::ABI_PushRegistersAndAdjustStack(*this, PersistentCallerSavedRegs(), 0); mov(Common::X64::ABI_PARAM1, qword[STATE]); mov(Common::X64::ABI_PARAM2, METHOD_ADDRESS); @@ -338,7 +403,7 @@ void Tegra::MacroJITx64Impl::Compile_Send(Xbyak::Reg32 value) { L(dont_process); } -void Tegra::MacroJITx64Impl::Compile_Branch(Macro::Opcode opcode) { +void MacroJITx64Impl::Compile_Branch(Macro::Opcode opcode) { ASSERT_MSG(!is_delay_slot, "Executing a branch in a delay slot is not valid"); const s32 jump_address = static_cast<s32>(pc) + static_cast<s32>(opcode.GetBranchTarget() / sizeof(s32)); @@ -392,7 +457,7 @@ void Tegra::MacroJITx64Impl::Compile_Branch(Macro::Opcode opcode) { L(end); } -void Tegra::MacroJITx64Impl::Optimizer_ScanFlags() { +void MacroJITx64Impl::Optimizer_ScanFlags() { optimizer.can_skip_carry = true; optimizer.has_delayed_pc = false; for (auto raw_op : code) { @@ -534,7 +599,7 @@ bool MacroJITx64Impl::Compile_NextInstruction() { return true; } -Xbyak::Reg32 Tegra::MacroJITx64Impl::Compile_FetchParameter() { +Xbyak::Reg32 MacroJITx64Impl::Compile_FetchParameter() { mov(eax, dword[PARAMETERS]); add(PARAMETERS, sizeof(u32)); return eax; @@ -611,9 +676,12 @@ Macro::Opcode MacroJITx64Impl::GetOpCode() const { ASSERT(pc < code.size()); return {code[pc]}; } +} // Anonymous namespace -std::bitset<32> MacroJITx64Impl::PersistentCallerSavedRegs() const { - return PERSISTENT_REGISTERS & Common::X64::ABI_ALL_CALLER_SAVED; -} +MacroJITx64::MacroJITx64(Engines::Maxwell3D& maxwell3d_) + : MacroEngine{maxwell3d_}, maxwell3d{maxwell3d_} {} +std::unique_ptr<CachedMacro> MacroJITx64::Compile(const std::vector<u32>& code) { + return std::make_unique<MacroJITx64Impl>(maxwell3d, code); +} } // namespace Tegra diff --git a/src/video_core/macro/macro_jit_x64.h b/src/video_core/macro/macro_jit_x64.h index d03d480b4..773b037ae 100644 --- a/src/video_core/macro/macro_jit_x64.h +++ b/src/video_core/macro/macro_jit_x64.h @@ -4,12 +4,7 @@ #pragma once -#include <array> -#include <bitset> -#include <xbyak/xbyak.h> -#include "common/bit_field.h" #include "common/common_types.h" -#include "common/x64/xbyak_abi.h" #include "video_core/macro/macro.h" namespace Tegra { @@ -18,9 +13,6 @@ namespace Engines { class Maxwell3D; } -/// MAX_CODE_SIZE is arbitrarily chosen based on current booting games -constexpr size_t MAX_CODE_SIZE = 0x10000; - class MacroJITx64 final : public MacroEngine { public: explicit MacroJITx64(Engines::Maxwell3D& maxwell3d_); @@ -32,67 +24,4 @@ private: Engines::Maxwell3D& maxwell3d; }; -class MacroJITx64Impl : public Xbyak::CodeGenerator, public CachedMacro { -public: - explicit MacroJITx64Impl(Engines::Maxwell3D& maxwell3d_, const std::vector<u32>& code_); - ~MacroJITx64Impl(); - - void Execute(const std::vector<u32>& parameters, u32 method) override; - - void Compile_ALU(Macro::Opcode opcode); - void Compile_AddImmediate(Macro::Opcode opcode); - void Compile_ExtractInsert(Macro::Opcode opcode); - void Compile_ExtractShiftLeftImmediate(Macro::Opcode opcode); - void Compile_ExtractShiftLeftRegister(Macro::Opcode opcode); - void Compile_Read(Macro::Opcode opcode); - void Compile_Branch(Macro::Opcode opcode); - -private: - void Optimizer_ScanFlags(); - - void Compile(); - bool Compile_NextInstruction(); - - Xbyak::Reg32 Compile_FetchParameter(); - Xbyak::Reg32 Compile_GetRegister(u32 index, Xbyak::Reg32 dst); - - void Compile_ProcessResult(Macro::ResultOperation operation, u32 reg); - void Compile_Send(Xbyak::Reg32 value); - - Macro::Opcode GetOpCode() const; - std::bitset<32> PersistentCallerSavedRegs() const; - - struct JITState { - Engines::Maxwell3D* maxwell3d{}; - std::array<u32, Macro::NUM_MACRO_REGISTERS> registers{}; - u32 carry_flag{}; - }; - static_assert(offsetof(JITState, maxwell3d) == 0, "Maxwell3D is not at 0x0"); - using ProgramType = void (*)(JITState*, const u32*); - - struct OptimizerState { - bool can_skip_carry{}; - bool has_delayed_pc{}; - bool zero_reg_skip{}; - bool skip_dummy_addimmediate{}; - bool optimize_for_method_move{}; - bool enable_asserts{}; - }; - OptimizerState optimizer{}; - - std::optional<Macro::Opcode> next_opcode{}; - ProgramType program{nullptr}; - - std::array<Xbyak::Label, MAX_CODE_SIZE> labels; - std::array<Xbyak::Label, MAX_CODE_SIZE> delay_skip; - Xbyak::Label end_of_code{}; - - bool is_delay_slot{}; - u32 pc{}; - std::optional<u32> delayed_pc; - - const std::vector<u32>& code; - Engines::Maxwell3D& maxwell3d; -}; - } // namespace Tegra diff --git a/src/video_core/renderer_vulkan/vk_fsr.cpp b/src/video_core/renderer_vulkan/vk_fsr.cpp index 73629d229..b630090e8 100644 --- a/src/video_core/renderer_vulkan/vk_fsr.cpp +++ b/src/video_core/renderer_vulkan/vk_fsr.cpp @@ -214,7 +214,7 @@ VkImageView FSR::Draw(VKScheduler& scheduler, size_t image_index, VkImageView im { VkImageMemoryBarrier fsr_write_barrier = base_barrier; - fsr_write_barrier.image = *images[image_index], + fsr_write_barrier.image = *images[image_index]; fsr_write_barrier.oldLayout = VK_IMAGE_LAYOUT_UNDEFINED; cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_ALL_COMMANDS_BIT, diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 8c370ff91..2c8c10c50 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -65,18 +65,18 @@ const std::array<int, 2> Config::default_stick_mod = { // This must be in alphabetical order according to action name as it must have the same order as // UISetting::values.shortcuts, which is alphabetically ordered. // clang-format off -const std::array<UISettings::Shortcut, 21> Config::default_hotkeys{{ +const std::array<UISettings::Shortcut, 20> Config::default_hotkeys{{ + {QStringLiteral("Audio Mute/Unmute"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), QStringLiteral("Home+Dpad_Right"), Qt::WindowShortcut}}, + {QStringLiteral("Audio Volume Down"), QStringLiteral("Main Window"), {QStringLiteral("-"), QStringLiteral("Home+Dpad_Down"), Qt::ApplicationShortcut}}, + {QStringLiteral("Audio Volume Up"), QStringLiteral("Main Window"), {QStringLiteral("+"), QStringLiteral("Home+Dpad_Up"), Qt::ApplicationShortcut}}, {QStringLiteral("Capture Screenshot"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+P"), QStringLiteral("Screenshot"), Qt::WidgetWithChildrenShortcut}}, {QStringLiteral("Change Docked Mode"), QStringLiteral("Main Window"), {QStringLiteral("F10"), QStringLiteral("Home+X"), Qt::ApplicationShortcut}}, {QStringLiteral("Continue/Pause Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F4"), QStringLiteral("Home+Plus"), Qt::WindowShortcut}}, - {QStringLiteral("Decrease Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("-"), QStringLiteral(""), Qt::ApplicationShortcut}}, {QStringLiteral("Exit Fullscreen"), QStringLiteral("Main Window"), {QStringLiteral("Esc"), QStringLiteral(""), Qt::WindowShortcut}}, {QStringLiteral("Exit yuzu"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Q"), QStringLiteral("Home+Minus"), Qt::WindowShortcut}}, {QStringLiteral("Fullscreen"), QStringLiteral("Main Window"), {QStringLiteral("F11"), QStringLiteral("Home+B"), Qt::WindowShortcut}}, - {QStringLiteral("Increase Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("+"), QStringLiteral(""), Qt::ApplicationShortcut}}, {QStringLiteral("Load Amiibo"), QStringLiteral("Main Window"), {QStringLiteral("F2"), QStringLiteral("Home+A"), Qt::WidgetWithChildrenShortcut}}, {QStringLiteral("Load File"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+O"), QStringLiteral(""), Qt::WidgetWithChildrenShortcut}}, - {QStringLiteral("Mute Audio"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+M"), QStringLiteral(""), Qt::WindowShortcut}}, {QStringLiteral("Restart Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F6"), QStringLiteral(""), Qt::WindowShortcut}}, {QStringLiteral("Stop Emulation"), QStringLiteral("Main Window"), {QStringLiteral("F5"), QStringLiteral(""), Qt::WindowShortcut}}, {QStringLiteral("TAS Start/Stop"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F5"), QStringLiteral(""), Qt::ApplicationShortcut}}, @@ -85,7 +85,6 @@ const std::array<UISettings::Shortcut, 21> Config::default_hotkeys{{ {QStringLiteral("Toggle Filter Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F"), QStringLiteral(""), Qt::WindowShortcut}}, {QStringLiteral("Toggle Framerate Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+U"), QStringLiteral("Home+Y"), Qt::ApplicationShortcut}}, {QStringLiteral("Toggle Mouse Panning"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+F9"), QStringLiteral(""), Qt::ApplicationShortcut}}, - {QStringLiteral("Toggle Speed Limit"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+Z"), QStringLiteral(""), Qt::ApplicationShortcut}}, {QStringLiteral("Toggle Status Bar"), QStringLiteral("Main Window"), {QStringLiteral("Ctrl+S"), QStringLiteral(""), Qt::WindowShortcut}}, }}; // clang-format on @@ -394,6 +393,8 @@ void Config::ReadControlValues() { ReadGlobalSetting(Settings::values.enable_accurate_vibrations); ReadGlobalSetting(Settings::values.motion_enabled); + ReadBasicSetting(Settings::values.controller_navigation); + qt_config->endGroup(); } @@ -1002,6 +1003,7 @@ void Config::SaveControlValues() { WriteBasicSetting(Settings::values.keyboard_enabled); WriteBasicSetting(Settings::values.emulate_analog_keyboard); WriteBasicSetting(Settings::values.mouse_panning_sensitivity); + WriteBasicSetting(Settings::values.controller_navigation); WriteBasicSetting(Settings::values.tas_enable); WriteBasicSetting(Settings::values.tas_loop); diff --git a/src/yuzu/configuration/config.h b/src/yuzu/configuration/config.h index 8f4576def..60b20a62f 100644 --- a/src/yuzu/configuration/config.h +++ b/src/yuzu/configuration/config.h @@ -46,7 +46,7 @@ public: default_mouse_buttons; static const std::array<int, Settings::NativeKeyboard::NumKeyboardKeys> default_keyboard_keys; static const std::array<int, Settings::NativeKeyboard::NumKeyboardMods> default_keyboard_mods; - static const std::array<UISettings::Shortcut, 21> default_hotkeys; + static const std::array<UISettings::Shortcut, 20> default_hotkeys; static constexpr UISettings::Theme default_theme{ #ifdef _WIN32 diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 9241678e4..74f0e0b79 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui @@ -429,7 +429,7 @@ </item> <item> <property name="text"> - <string>AMD FidelityFX™️ Super Resolution [Vulkan Only]</string> + <string>AMD FidelityFX™️ Super Resolution (Vulkan Only)</string> </property> </item> </widget> diff --git a/src/yuzu/configuration/configure_input_advanced.cpp b/src/yuzu/configuration/configure_input_advanced.cpp index 65c8e59ac..20fc2599d 100644 --- a/src/yuzu/configuration/configure_input_advanced.cpp +++ b/src/yuzu/configuration/configure_input_advanced.cpp @@ -131,6 +131,7 @@ void ConfigureInputAdvanced::ApplyConfiguration() { Settings::values.touchscreen.enabled = ui->touchscreen_enabled->isChecked(); Settings::values.enable_raw_input = ui->enable_raw_input->isChecked(); Settings::values.enable_udp_controller = ui->enable_udp_controller->isChecked(); + Settings::values.controller_navigation = ui->controller_navigation->isChecked(); } void ConfigureInputAdvanced::LoadConfiguration() { @@ -162,6 +163,7 @@ void ConfigureInputAdvanced::LoadConfiguration() { ui->touchscreen_enabled->setChecked(Settings::values.touchscreen.enabled); ui->enable_raw_input->setChecked(Settings::values.enable_raw_input.GetValue()); ui->enable_udp_controller->setChecked(Settings::values.enable_udp_controller.GetValue()); + ui->controller_navigation->setChecked(Settings::values.controller_navigation.GetValue()); UpdateUIEnabled(); } diff --git a/src/yuzu/configuration/configure_input_advanced.ui b/src/yuzu/configuration/configure_input_advanced.ui index df0e4d602..66f2075f2 100644 --- a/src/yuzu/configuration/configure_input_advanced.ui +++ b/src/yuzu/configuration/configure_input_advanced.ui @@ -2655,6 +2655,19 @@ </widget> </item> <item row="4" column="0"> + <widget class="QCheckBox" name="controller_navigation"> + <property name="minimumSize"> + <size> + <width>0</width> + <height>23</height> + </size> + </property> + <property name="text"> + <string>Controller navigation</string> + </property> + </widget> + </item> + <item row="5" column="0"> <widget class="QCheckBox" name="mouse_panning"> <property name="minimumSize"> <size> @@ -2667,7 +2680,7 @@ </property> </widget> </item> - <item row="4" column="2"> + <item row="5" column="2"> <widget class="QSpinBox" name="mouse_panning_sensitivity"> <property name="toolTip"> <string>Mouse sensitivity</string> @@ -2689,14 +2702,14 @@ </property> </widget> </item> - <item row="5" column="0"> + <item row="6" column="0"> <widget class="QLabel" name="motion_touch"> <property name="text"> <string>Motion / Touch</string> </property> </widget> </item> - <item row="5" column="2"> + <item row="6" column="2"> <widget class="QPushButton" name="buttonMotionTouch"> <property name="text"> <string>Configure</string> diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index d2132b408..7029287a9 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp @@ -147,7 +147,7 @@ QString ConfigureInputPlayer::ButtonToText(const Common::ParamPackage& param) { // Retrieve the names from Qt if (param.Get("engine", "") == "keyboard") { const QString button_str = GetKeyName(param.Get("code", 0)); - return QObject::tr("%1%2").arg(toggle, button_str); + return QObject::tr("%1%2%3").arg(toggle, inverted, button_str); } if (common_button_name == Common::Input::ButtonNames::Invalid) { @@ -341,7 +341,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i emulated_controller->SetButtonParam(button_id, {}); button_map[button_id]->setText(tr("[not set]")); }); - if (param.Has("button") || param.Has("hat")) { + if (param.Has("code") || param.Has("button") || param.Has("hat")) { context_menu.addAction(tr("Toggle button"), [&] { const bool toggle_value = !param.Get("toggle", false); param.Set("toggle", toggle_value); @@ -349,8 +349,8 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i emulated_controller->SetButtonParam(button_id, param); }); context_menu.addAction(tr("Invert button"), [&] { - const bool toggle_value = !param.Get("inverted", false); - param.Set("inverted", toggle_value); + const bool invert_value = !param.Get("inverted", false); + param.Set("inverted", invert_value); button_map[button_id]->setText(ButtonToText(param)); emulated_controller->SetButtonParam(button_id, param); }); @@ -510,28 +510,37 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_i analog_map_modifier_button[analog_id]->setContextMenuPolicy(Qt::CustomContextMenu); - connect(analog_map_modifier_button[analog_id], &QPushButton::customContextMenuRequested, - [=, this](const QPoint& menu_location) { - QMenu context_menu; - Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); - context_menu.addAction(tr("Clear"), [&] { - param.Set("modifier", ""); - analog_map_modifier_button[analog_id]->setText(tr("[not set]")); - emulated_controller->SetStickParam(analog_id, param); - }); - context_menu.addAction(tr("Toggle button"), [&] { - Common::ParamPackage modifier_param = - Common::ParamPackage{param.Get("modifier", "")}; - const bool toggle_value = !modifier_param.Get("toggle", false); - modifier_param.Set("toggle", toggle_value); - param.Set("modifier", modifier_param.Serialize()); - analog_map_modifier_button[analog_id]->setText( - ButtonToText(modifier_param)); - emulated_controller->SetStickParam(analog_id, param); - }); - context_menu.exec( - analog_map_modifier_button[analog_id]->mapToGlobal(menu_location)); + connect( + analog_map_modifier_button[analog_id], &QPushButton::customContextMenuRequested, + [=, this](const QPoint& menu_location) { + QMenu context_menu; + Common::ParamPackage param = emulated_controller->GetStickParam(analog_id); + context_menu.addAction(tr("Clear"), [&] { + param.Set("modifier", ""); + analog_map_modifier_button[analog_id]->setText(tr("[not set]")); + emulated_controller->SetStickParam(analog_id, param); + }); + context_menu.addAction(tr("Toggle button"), [&] { + Common::ParamPackage modifier_param = + Common::ParamPackage{param.Get("modifier", "")}; + const bool toggle_value = !modifier_param.Get("toggle", false); + modifier_param.Set("toggle", toggle_value); + param.Set("modifier", modifier_param.Serialize()); + analog_map_modifier_button[analog_id]->setText(ButtonToText(modifier_param)); + emulated_controller->SetStickParam(analog_id, param); }); + context_menu.addAction(tr("Invert button"), [&] { + Common::ParamPackage modifier_param = + Common::ParamPackage{param.Get("modifier", "")}; + const bool invert_value = !modifier_param.Get("inverted", false); + modifier_param.Set("inverted", invert_value); + param.Set("modifier", modifier_param.Serialize()); + analog_map_modifier_button[analog_id]->setText(ButtonToText(modifier_param)); + emulated_controller->SetStickParam(analog_id, param); + }); + context_menu.exec( + analog_map_modifier_button[analog_id]->mapToGlobal(menu_location)); + }); connect(analog_map_range_spinbox[analog_id], qOverload<int>(&QSpinBox::valueChanged), [=, this] { diff --git a/src/yuzu/hotkeys.cpp b/src/yuzu/hotkeys.cpp index d96497c4e..6ed9611c7 100644 --- a/src/yuzu/hotkeys.cpp +++ b/src/yuzu/hotkeys.cpp @@ -190,6 +190,9 @@ void ControllerShortcut::ControllerUpdateEvent(Core::HID::ControllerTriggerType if (type != Core::HID::ControllerTriggerType::Button) { return; } + if (!Settings::values.controller_navigation) { + return; + } if (button_sequence.npad.raw == Core::HID::NpadButton::None && button_sequence.capture.raw == 0 && button_sequence.home.raw == 0) { return; diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index e10eb70a2..d9e689d14 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -1008,33 +1008,24 @@ void GMainWindow::InitializeHotkeys() { ToggleFullscreen(); } }); - connect_shortcut(QStringLiteral("Toggle Speed Limit"), [&] { - Settings::values.use_speed_limit.SetValue(!Settings::values.use_speed_limit.GetValue()); - UpdateStatusBar(); - }); - constexpr u16 SPEED_LIMIT_STEP = 5; - connect_shortcut(QStringLiteral("Increase Speed Limit"), [&] { - if (Settings::values.speed_limit.GetValue() < 9999 - SPEED_LIMIT_STEP) { - Settings::values.speed_limit.SetValue(SPEED_LIMIT_STEP + - Settings::values.speed_limit.GetValue()); - UpdateStatusBar(); - } - }); - connect_shortcut(QStringLiteral("Decrease Speed Limit"), [&] { - if (Settings::values.speed_limit.GetValue() > SPEED_LIMIT_STEP) { - Settings::values.speed_limit.SetValue(Settings::values.speed_limit.GetValue() - - SPEED_LIMIT_STEP); - UpdateStatusBar(); - } - }); connect_shortcut(QStringLiteral("Change Docked Mode"), [&] { Settings::values.use_docked_mode.SetValue(!Settings::values.use_docked_mode.GetValue()); OnDockedModeChanged(!Settings::values.use_docked_mode.GetValue(), Settings::values.use_docked_mode.GetValue(), *system); dock_status_button->setChecked(Settings::values.use_docked_mode.GetValue()); }); - connect_shortcut(QStringLiteral("Mute Audio"), + connect_shortcut(QStringLiteral("Audio Mute/Unmute"), [] { Settings::values.audio_muted = !Settings::values.audio_muted; }); + connect_shortcut(QStringLiteral("Audio Volume Down"), [] { + const auto current_volume = static_cast<int>(Settings::values.volume.GetValue()); + const auto new_volume = std::max(current_volume - 5, 0); + Settings::values.volume.SetValue(static_cast<u8>(new_volume)); + }); + connect_shortcut(QStringLiteral("Audio Volume Up"), [] { + const auto current_volume = static_cast<int>(Settings::values.volume.GetValue()); + const auto new_volume = std::min(current_volume + 5, 100); + Settings::values.volume.SetValue(static_cast<u8>(new_volume)); + }); connect_shortcut(QStringLiteral("Toggle Framerate Limit"), [] { Settings::values.disable_fps_limit.SetValue(!Settings::values.disable_fps_limit.GetValue()); }); diff --git a/src/yuzu/util/controller_navigation.cpp b/src/yuzu/util/controller_navigation.cpp index 86fb28b9f..c2b13123d 100644 --- a/src/yuzu/util/controller_navigation.cpp +++ b/src/yuzu/util/controller_navigation.cpp @@ -40,6 +40,9 @@ void ControllerNavigation::TriggerButton(Settings::NativeButton::Values native_b void ControllerNavigation::ControllerUpdateEvent(Core::HID::ControllerTriggerType type) { std::lock_guard lock{mutex}; + if (!Settings::values.controller_navigation) { + return; + } if (type == Core::HID::ControllerTriggerType::Button) { ControllerUpdateButton(); return; |