diff options
36 files changed, 237 insertions, 113 deletions
diff --git a/CMakeLists.txt b/CMakeLists.txt index 123a3082a..eb403205c 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -411,12 +411,13 @@ if (CONAN_REQUIRED_LIBS) # Download conan.cmake automatically, you can also just copy the conan.cmake file if(NOT EXISTS "${CMAKE_BINARY_DIR}/conan.cmake") message(STATUS "Downloading conan.cmake from https://github.com/conan-io/cmake-conan") - file(DOWNLOAD "https://github.com/conan-io/cmake-conan/raw/v0.15/conan.cmake" + # TODO: Use a tagged release. The latest tagged release does not support VS2022 as of this writing. + file(DOWNLOAD "https://raw.githubusercontent.com/conan-io/cmake-conan/43e385830ee35377dbd2dcbe8d5a9e750301ea00/conan.cmake" "${CMAKE_BINARY_DIR}/conan.cmake") endif() include(${CMAKE_BINARY_DIR}/conan.cmake) - conan_check(VERSION 1.24.0 REQUIRED) + conan_check(VERSION 1.41.0 REQUIRED) # Manually add iconv to fix a dep conflict between qt and sdl2 # We don't need to add it through find_package or anything since the other two can find it just fine diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 6e66dc1df..63dd9febf 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -32,6 +32,7 @@ if (MSVC) # /Zc:externConstexpr - Allow extern constexpr variables to have external linkage, like the standard mandates # /Zc:inline - Let codegen omit inline functions in object files # /Zc:throwingNew - Let codegen assume `operator new` (without std::nothrow) will never return null + # /GT - Supports fiber safety for data allocated using static thread-local storage add_compile_options( /MP /Zi @@ -44,6 +45,7 @@ if (MSVC) /Zc:externConstexpr /Zc:inline /Zc:throwingNew + /GT # External headers diagnostics /experimental:external # Enables the external headers options. This option isn't required in Visual Studio 2019 version 16.10 and later @@ -69,6 +71,10 @@ if (MSVC) /we5038 # data member 'member1' will be initialized after data member 'member2' ) + if (ARCHITECTURE_x86_64) + add_compile_options(/QIntel-jcc-erratum) + endif() + # /GS- - No stack buffer overflow checks add_compile_options("$<$<CONFIG:Release>:/GS->") diff --git a/src/common/alignment.h b/src/common/alignment.h index 1b56569d1..8570c7d3c 100644 --- a/src/common/alignment.h +++ b/src/common/alignment.h @@ -64,7 +64,7 @@ public: using propagate_on_container_copy_assignment = std::true_type; using propagate_on_container_move_assignment = std::true_type; using propagate_on_container_swap = std::true_type; - using is_always_equal = std::true_type; + using is_always_equal = std::false_type; constexpr AlignmentAllocator() noexcept = default; @@ -83,6 +83,11 @@ public: struct rebind { using other = AlignmentAllocator<T2, Align>; }; + + template <typename T2, size_t Align2> + constexpr bool operator==(const AlignmentAllocator<T2, Align2>&) const noexcept { + return std::is_same_v<T, T2> && Align == Align2; + } }; } // namespace Common diff --git a/src/common/settings.h b/src/common/settings.h index 402339443..9ff4cf85d 100644 --- a/src/common/settings.h +++ b/src/common/settings.h @@ -7,7 +7,6 @@ #include <algorithm> #include <array> #include <atomic> -#include <chrono> #include <map> #include <optional> #include <string> @@ -487,9 +486,9 @@ struct Values { // System Setting<std::optional<u32>> rng_seed{std::optional<u32>(), "rng_seed"}; // Measured in seconds since epoch - std::optional<std::chrono::seconds> custom_rtc; + std::optional<s64> custom_rtc; // Set on game boot, reset on stop. Seconds difference between current time and `custom_rtc` - std::chrono::seconds custom_rtc_differential; + s64 custom_rtc_differential; BasicSetting<s32> current_user{0, "current_user"}; RangedSetting<s32> language_index{1, 0, 17, "language_index"}; diff --git a/src/core/arm/dynarmic/arm_dynarmic_64.cpp b/src/core/arm/dynarmic/arm_dynarmic_64.cpp index bf27ffe71..4fd15f111 100644 --- a/src/core/arm/dynarmic/arm_dynarmic_64.cpp +++ b/src/core/arm/dynarmic/arm_dynarmic_64.cpp @@ -263,7 +263,7 @@ void ARM_Dynarmic_64::Run() { } void ARM_Dynarmic_64::Step() { - cb->InterpreterFallback(jit->GetPC(), 1); + jit->Step(); } ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, diff --git a/src/core/core.cpp b/src/core/core.cpp index 3042d611b..3c75f42ae 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp @@ -196,8 +196,9 @@ struct System::Impl { cpu_manager.Initialize(); core_timing.Initialize([&system]() { system.RegisterHostThread(); }); - const auto current_time = std::chrono::duration_cast<std::chrono::seconds>( - std::chrono::system_clock::now().time_since_epoch()); + const auto posix_time = std::chrono::system_clock::now().time_since_epoch(); + const auto current_time = + std::chrono::duration_cast<std::chrono::seconds>(posix_time).count(); Settings::values.custom_rtc_differential = Settings::values.custom_rtc.value_or(current_time) - current_time; diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index f66759815..05936f3c3 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp @@ -9,7 +9,7 @@ namespace FileSys { -const std::array<const char*, 15> LANGUAGE_NAMES{{ +const std::array<const char*, 16> LANGUAGE_NAMES{{ "AmericanEnglish", "BritishEnglish", "Japanese", @@ -25,6 +25,7 @@ const std::array<const char*, 15> LANGUAGE_NAMES{{ "Korean", "Taiwanese", "Chinese", + "BrazilianPortuguese", }}; std::string LanguageEntry::GetApplicationName() const { diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index dd9837cf5..af2b723df 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h @@ -88,11 +88,12 @@ enum class Language : u8 { Korean = 12, Taiwanese = 13, Chinese = 14, + BrazilianPortuguese = 15, Default = 255, }; -extern const std::array<const char*, 15> LANGUAGE_NAMES; +extern const std::array<const char*, 16> LANGUAGE_NAMES; // A class representing the format used by NX metadata files, typically named Control.nacp. // These store application name, dev name, title id, and other miscellaneous data. diff --git a/src/core/hle/kernel/k_page_table.cpp b/src/core/hle/kernel/k_page_table.cpp index 701268545..5e0b620c2 100644 --- a/src/core/hle/kernel/k_page_table.cpp +++ b/src/core/hle/kernel/k_page_table.cpp @@ -363,6 +363,8 @@ ResultCode KPageTable::UnmapProcessCodeMemory(VAddr dst_addr, VAddr src_addr, st block_manager->Update(src_addr, num_pages, KMemoryState::Normal, KMemoryPermission::ReadAndWrite); + system.InvalidateCpuInstructionCacheRange(dst_addr, size); + return ResultSuccess; } diff --git a/src/core/hle/kernel/k_scheduler.h b/src/core/hle/kernel/k_scheduler.h index c8ccc1ae4..7df288438 100644 --- a/src/core/hle/kernel/k_scheduler.h +++ b/src/core/hle/kernel/k_scheduler.h @@ -49,6 +49,11 @@ public: /// Gets the current running thread [[nodiscard]] KThread* GetCurrentThread() const; + /// Gets the idle thread + [[nodiscard]] KThread* GetIdleThread() const { + return idle_thread; + } + /// Returns true if the scheduler is idle [[nodiscard]] bool IsIdle() const { return GetCurrentThread() == idle_thread; diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index f98f24a60..7f38ade1c 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp @@ -886,7 +886,24 @@ static ResultCode GetInfo(Core::System& system, u64* result, u64 info_id, Handle *result = out_ticks; return ResultSuccess; } + case GetInfoType::IdleTickCount: { + if (handle == 0) { + LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", + static_cast<Handle>(handle)); + return ResultInvalidHandle; + } + if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id != system.CurrentCoreIndex()) { + LOG_ERROR(Kernel_SVC, "Core is not the current core, got {}", info_sub_id); + return ResultInvalidCombination; + } + + const auto& scheduler = *system.Kernel().CurrentScheduler(); + const auto* const idle_thread = scheduler.GetIdleThread(); + + *result = idle_thread->GetCpuTime(); + return ResultSuccess; + } default: LOG_ERROR(Kernel_SVC, "Unimplemented svcGetInfo id=0x{:016X}", info_id); return ResultInvalidEnumValue; diff --git a/src/core/hle/result.h b/src/core/hle/result.h index a755008d5..2c6b24848 100644 --- a/src/core/hle/result.h +++ b/src/core/hle/result.h @@ -206,7 +206,7 @@ public: return result; } - ResultVal(const ResultVal& o) : result_code(o.result_code) { + ResultVal(const ResultVal& o) noexcept : result_code(o.result_code) { if (!o.empty()) { new (&object) T(o.object); } @@ -224,7 +224,7 @@ public: } } - ResultVal& operator=(const ResultVal& o) { + ResultVal& operator=(const ResultVal& o) noexcept { if (this == &o) { return *this; } @@ -244,6 +244,26 @@ public: return *this; } + ResultVal& operator=(ResultVal&& o) noexcept { + if (this == &o) { + return *this; + } + if (!empty()) { + if (!o.empty()) { + object = std::move(o.object); + } else { + object.~T(); + } + } else { + if (!o.empty()) { + new (&object) T(std::move(o.object)); + } + } + result_code = o.result_code; + + return *this; + } + /** * Replaces the current result with a new constructed result value in-place. The code must not * be an error code. @@ -329,8 +349,8 @@ template <typename T, typename... Args> * copy or move constructing. */ template <typename Arg> -[[nodiscard]] ResultVal<std::remove_reference_t<Arg>> MakeResult(Arg&& arg) { - return ResultVal<std::remove_reference_t<Arg>>::WithCode(ResultSuccess, std::forward<Arg>(arg)); +[[nodiscard]] ResultVal<std::remove_cvref_t<Arg>> MakeResult(Arg&& arg) { + return ResultVal<std::remove_cvref_t<Arg>>::WithCode(ResultSuccess, std::forward<Arg>(arg)); } /** diff --git a/src/core/hle/service/ns/language.cpp b/src/core/hle/service/ns/language.cpp index 7d9e4a20b..e01c6be47 100644 --- a/src/core/hle/service/ns/language.cpp +++ b/src/core/hle/service/ns/language.cpp @@ -277,6 +277,25 @@ constexpr ApplicationLanguagePriorityList priority_list_simplified_chinese = {{ ApplicationLanguage::Korean, }}; +constexpr ApplicationLanguagePriorityList priority_list_brazilian_portuguese = {{ + ApplicationLanguage::BrazilianPortuguese, + ApplicationLanguage::Portuguese, + ApplicationLanguage::LatinAmericanSpanish, + ApplicationLanguage::AmericanEnglish, + ApplicationLanguage::BritishEnglish, + ApplicationLanguage::Japanese, + ApplicationLanguage::French, + ApplicationLanguage::German, + ApplicationLanguage::Spanish, + ApplicationLanguage::Italian, + ApplicationLanguage::Dutch, + ApplicationLanguage::CanadianFrench, + ApplicationLanguage::Russian, + ApplicationLanguage::Korean, + ApplicationLanguage::SimplifiedChinese, + ApplicationLanguage::TraditionalChinese, +}}; + const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList( const ApplicationLanguage lang) { switch (lang) { @@ -310,6 +329,8 @@ const ApplicationLanguagePriorityList* GetApplicationLanguagePriorityList( return &priority_list_traditional_chinese; case ApplicationLanguage::SimplifiedChinese: return &priority_list_simplified_chinese; + case ApplicationLanguage::BrazilianPortuguese: + return &priority_list_brazilian_portuguese; default: return nullptr; } @@ -339,7 +360,6 @@ std::optional<ApplicationLanguage> ConvertToApplicationLanguage( case Set::LanguageCode::FR_CA: return ApplicationLanguage::CanadianFrench; case Set::LanguageCode::PT: - case Set::LanguageCode::PT_BR: return ApplicationLanguage::Portuguese; case Set::LanguageCode::RU: return ApplicationLanguage::Russian; @@ -351,6 +371,8 @@ std::optional<ApplicationLanguage> ConvertToApplicationLanguage( case Set::LanguageCode::ZH_CN: case Set::LanguageCode::ZH_HANS: return ApplicationLanguage::SimplifiedChinese; + case Set::LanguageCode::PT_BR: + return ApplicationLanguage::BrazilianPortuguese; default: return std::nullopt; } @@ -388,6 +410,8 @@ std::optional<Set::LanguageCode> ConvertToLanguageCode(const ApplicationLanguage return Set::LanguageCode::ZH_HANT; case ApplicationLanguage::SimplifiedChinese: return Set::LanguageCode::ZH_HANS; + case ApplicationLanguage::BrazilianPortuguese: + return Set::LanguageCode::PT_BR; default: return std::nullopt; } diff --git a/src/core/hle/service/ns/language.h b/src/core/hle/service/ns/language.h index e9829f9d2..d84c3f277 100644 --- a/src/core/hle/service/ns/language.h +++ b/src/core/hle/service/ns/language.h @@ -30,6 +30,7 @@ enum class ApplicationLanguage : u8 { Korean, TraditionalChinese, SimplifiedChinese, + BrazilianPortuguese, Count }; using ApplicationLanguagePriorityList = diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp index 845de724d..e61261f98 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp @@ -69,8 +69,7 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u std::vector<Reloc> relocs(params.relocation_count); std::vector<u32> reloc_shifts(params.relocation_count); std::vector<SyncptIncr> syncpt_increments(params.syncpoint_count); - std::vector<SyncptIncr> wait_checks(params.syncpoint_count); - std::vector<Fence> fences(params.fence_count); + std::vector<u32> fence_thresholds(params.fence_count); // Slice input into their respective buffers std::size_t offset = sizeof(IoctlSubmit); @@ -78,15 +77,13 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u offset += SliceVectors(input, relocs, params.relocation_count, offset); offset += SliceVectors(input, reloc_shifts, params.relocation_count, offset); offset += SliceVectors(input, syncpt_increments, params.syncpoint_count, offset); - offset += SliceVectors(input, wait_checks, params.syncpoint_count, offset); - offset += SliceVectors(input, fences, params.fence_count, offset); + offset += SliceVectors(input, fence_thresholds, params.fence_count, offset); auto& gpu = system.GPU(); if (gpu.UseNvdec()) { for (std::size_t i = 0; i < syncpt_increments.size(); i++) { const SyncptIncr& syncpt_incr = syncpt_increments[i]; - fences[i].id = syncpt_incr.id; - fences[i].value = + fence_thresholds[i] = syncpoint_manager.IncreaseSyncpoint(syncpt_incr.id, syncpt_incr.increments); } } @@ -98,11 +95,6 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u cmdlist.size() * sizeof(u32)); gpu.PushCommandBuffer(cmdlist); } - if (gpu.UseNvdec()) { - fences[0].value = syncpoint_manager.IncreaseSyncpoint(fences[0].id, 1); - Tegra::ChCommandHeaderList cmdlist{{(4 << 28) | fences[0].id}}; - gpu.PushCommandBuffer(cmdlist); - } std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit)); // Some games expect command_buffers to be written back offset = sizeof(IoctlSubmit); @@ -110,8 +102,7 @@ NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u offset += WriteVectors(output, relocs, offset); offset += WriteVectors(output, reloc_shifts, offset); offset += WriteVectors(output, syncpt_increments, offset); - offset += WriteVectors(output, wait_checks, offset); - offset += WriteVectors(output, fences, offset); + offset += WriteVectors(output, fence_thresholds, offset); return NvResult::Success; } diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h index af59f00d2..ae4199b79 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h @@ -56,19 +56,16 @@ protected: s32 target{}; s32 target_offset{}; }; - static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size"); + static_assert(sizeof(Reloc) == 0x10, "Reloc has incorrect size"); struct SyncptIncr { u32 id{}; u32 increments{}; + u32 unk0{}; + u32 unk1{}; + u32 unk2{}; }; - static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size"); - - struct Fence { - u32 id{}; - u32 value{}; - }; - static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size"); + static_assert(sizeof(SyncptIncr) == 0x14, "SyncptIncr has incorrect size"); struct IoctlGetSyncpoint { // Input diff --git a/src/core/hle/service/time/time_manager.cpp b/src/core/hle/service/time/time_manager.cpp index 4bbc606a1..9c4c960ef 100644 --- a/src/core/hle/service/time/time_manager.cpp +++ b/src/core/hle/service/time/time_manager.cpp @@ -13,18 +13,19 @@ #include "core/hle/service/time/time_manager.h" namespace Service::Time { - +namespace { constexpr Clock::TimeSpanType standard_network_clock_accuracy{0x0009356907420000ULL}; -static std::chrono::seconds GetSecondsSinceEpoch() { - return std::chrono::duration_cast<std::chrono::seconds>( - std::chrono::system_clock::now().time_since_epoch()) + +s64 GetSecondsSinceEpoch() { + const auto time_since_epoch = std::chrono::system_clock::now().time_since_epoch(); + return std::chrono::duration_cast<std::chrono::seconds>(time_since_epoch).count() + Settings::values.custom_rtc_differential; } -static s64 GetExternalRtcValue() { - return GetSecondsSinceEpoch().count() + TimeManager::GetExternalTimeZoneOffset(); +s64 GetExternalRtcValue() { + return GetSecondsSinceEpoch() + TimeManager::GetExternalTimeZoneOffset(); } +} // Anonymous namespace struct TimeManager::Impl final { explicit Impl(Core::System& system) diff --git a/src/input_common/udp/client.cpp b/src/input_common/udp/client.cpp index 9b0aec797..b9512aa2e 100644 --- a/src/input_common/udp/client.cpp +++ b/src/input_common/udp/client.cpp @@ -471,46 +471,42 @@ CalibrationConfigurationJob::CalibrationConfigurationJob( std::function<void(u16, u16, u16, u16)> data_callback) { std::thread([=, this] { - constexpr u16 CALIBRATION_THRESHOLD = 100; - - u16 min_x{UINT16_MAX}; - u16 min_y{UINT16_MAX}; - u16 max_x{}; - u16 max_y{}; - Status current_status{Status::Initialized}; - SocketCallback callback{[](Response::Version) {}, [](Response::PortInfo) {}, - [&](Response::PadData data) { - if (current_status == Status::Initialized) { - // Receiving data means the communication is ready now - current_status = Status::Ready; - status_callback(current_status); - } - if (data.touch[0].is_active == 0) { - return; - } - LOG_DEBUG(Input, "Current touch: {} {}", data.touch[0].x, - data.touch[0].y); - min_x = std::min(min_x, static_cast<u16>(data.touch[0].x)); - min_y = std::min(min_y, static_cast<u16>(data.touch[0].y)); - if (current_status == Status::Ready) { - // First touch - min data (min_x/min_y) - current_status = Status::Stage1Completed; - status_callback(current_status); - } - if (data.touch[0].x - min_x > CALIBRATION_THRESHOLD && - data.touch[0].y - min_y > CALIBRATION_THRESHOLD) { - // Set the current position as max value and finishes - // configuration - max_x = data.touch[0].x; - max_y = data.touch[0].y; - current_status = Status::Completed; - data_callback(min_x, min_y, max_x, max_y); - status_callback(current_status); - - complete_event.Set(); - } - }}; + SocketCallback callback{ + [](Response::Version) {}, [](Response::PortInfo) {}, + [&](Response::PadData data) { + static constexpr u16 CALIBRATION_THRESHOLD = 100; + static constexpr u16 MAX_VALUE = UINT16_MAX; + + if (current_status == Status::Initialized) { + // Receiving data means the communication is ready now + current_status = Status::Ready; + status_callback(current_status); + } + const auto& touchpad_0 = data.touch[0]; + if (touchpad_0.is_active == 0) { + return; + } + LOG_DEBUG(Input, "Current touch: {} {}", touchpad_0.x, touchpad_0.y); + const u16 min_x = std::min(MAX_VALUE, static_cast<u16>(touchpad_0.x)); + const u16 min_y = std::min(MAX_VALUE, static_cast<u16>(touchpad_0.y)); + if (current_status == Status::Ready) { + // First touch - min data (min_x/min_y) + current_status = Status::Stage1Completed; + status_callback(current_status); + } + if (touchpad_0.x - min_x > CALIBRATION_THRESHOLD && + touchpad_0.y - min_y > CALIBRATION_THRESHOLD) { + // Set the current position as max value and finishes configuration + const u16 max_x = touchpad_0.x; + const u16 max_y = touchpad_0.y; + current_status = Status::Completed; + data_callback(min_x, min_y, max_x, max_y); + status_callback(current_status); + + complete_event.Set(); + } + }}; Socket socket{host, port, std::move(callback)}; std::thread worker_thread{SocketLoop, &socket}; complete_event.Wait(); diff --git a/src/shader_recompiler/ir_opt/texture_pass.cpp b/src/shader_recompiler/ir_opt/texture_pass.cpp index 225c238fb..96c997a58 100644 --- a/src/shader_recompiler/ir_opt/texture_pass.cpp +++ b/src/shader_recompiler/ir_opt/texture_pass.cpp @@ -492,7 +492,7 @@ void TexturePass(Environment& env, IR::Program& program) { const auto insert_point{IR::Block::InstructionList::s_iterator_to(*inst)}; IR::IREmitter ir{*texture_inst.block, insert_point}; const IR::U32 shift{ir.Imm32(std::countr_zero(DESCRIPTOR_SIZE))}; - inst->SetArg(0, ir.SMin(ir.ShiftRightArithmetic(cbuf.dynamic_offset, shift), + inst->SetArg(0, ir.UMin(ir.ShiftRightArithmetic(cbuf.dynamic_offset, shift), ir.Imm32(DESCRIPTOR_SIZE - 1))); } else { inst->SetArg(0, IR::Value{}); diff --git a/src/video_core/dirty_flags.h b/src/video_core/dirty_flags.h index 504465d3f..f0d545f90 100644 --- a/src/video_core/dirty_flags.h +++ b/src/video_core/dirty_flags.h @@ -38,6 +38,9 @@ enum : u8 { Shaders, + // Special entries + DepthBiasGlobal, + LastCommonEntry, }; diff --git a/src/video_core/renderer_opengl/gl_device.cpp b/src/video_core/renderer_opengl/gl_device.cpp index 9692b8e94..0764ea6e0 100644 --- a/src/video_core/renderer_opengl/gl_device.cpp +++ b/src/video_core/renderer_opengl/gl_device.cpp @@ -10,6 +10,7 @@ #include <limits> #include <optional> #include <span> +#include <stdexcept> #include <vector> #include <glad/glad.h> @@ -180,6 +181,21 @@ Device::Device() { LOG_ERROR(Render_OpenGL, "Assembly shaders enabled but not supported"); shader_backend = Settings::ShaderBackend::GLSL; } + + if (shader_backend == Settings::ShaderBackend::GLSL && is_nvidia && + !Settings::values.renderer_debug) { + const std::string_view driver_version = version.substr(13); + const int version_major = + std::atoi(driver_version.substr(0, driver_version.find(".")).data()); + + if (version_major >= 495) { + LOG_WARNING(Render_OpenGL, "NVIDIA drivers 495 and later causes significant problems " + "with yuzu. Forcing GLASM as a mitigation."); + shader_backend = Settings::ShaderBackend::GLASM; + use_assembly_shaders = true; + } + } + // Blocks AMD and Intel OpenGL drivers on Windows from using asynchronous shader compilation. use_asynchronous_shaders = Settings::values.use_asynchronous_shaders.GetValue() && !(is_amd || (is_intel && !is_linux)); diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 3bcd6d6cc..30b47a7a0 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -627,9 +627,21 @@ void RasterizerVulkan::UpdateDepthBias(Tegra::Engines::Maxwell3D::Regs& regs) { if (!state_tracker.TouchDepthBias()) { return; } - scheduler.Record([constant = regs.polygon_offset_units, clamp = regs.polygon_offset_clamp, + float units = regs.polygon_offset_units / 2.0f; + const bool is_d24 = regs.zeta.format == Tegra::DepthFormat::S8_UINT_Z24_UNORM || + regs.zeta.format == Tegra::DepthFormat::D24X8_UNORM || + regs.zeta.format == Tegra::DepthFormat::D24S8_UNORM || + regs.zeta.format == Tegra::DepthFormat::D24C8_UNORM; + if (is_d24 && !device.SupportsD24DepthBuffer()) { + // the base formulas can be obtained from here: + // https://docs.microsoft.com/en-us/windows/win32/direct3d11/d3d10-graphics-programming-guide-output-merger-stage-depth-bias + const double rescale_factor = + static_cast<double>(1ULL << (32 - 24)) / (static_cast<double>(0x1.ep+127)); + units = static_cast<float>(static_cast<double>(units) * rescale_factor); + } + scheduler.Record([constant = units, clamp = regs.polygon_offset_clamp, factor = regs.polygon_offset_factor](vk::CommandBuffer cmdbuf) { - cmdbuf.SetDepthBias(constant, clamp, factor / 2.0f); + cmdbuf.SetDepthBias(constant, clamp, factor); }); } diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.cpp b/src/video_core/renderer_vulkan/vk_state_tracker.cpp index e3b7dd61c..c00913f55 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.cpp +++ b/src/video_core/renderer_vulkan/vk_state_tracker.cpp @@ -54,6 +54,7 @@ void SetupDirtyViewports(Tables& tables) { FillBlock(tables[0], OFF(viewport_transform), NUM(viewport_transform), Viewports); FillBlock(tables[0], OFF(viewports), NUM(viewports), Viewports); tables[0][OFF(viewport_transform_enabled)] = Viewports; + tables[1][OFF(screen_y_control)] = Viewports; } void SetupDirtyScissors(Tables& tables) { diff --git a/src/video_core/renderer_vulkan/vk_state_tracker.h b/src/video_core/renderer_vulkan/vk_state_tracker.h index d90935f52..2f2d6b31f 100644 --- a/src/video_core/renderer_vulkan/vk_state_tracker.h +++ b/src/video_core/renderer_vulkan/vk_state_tracker.h @@ -79,7 +79,8 @@ public: } bool TouchDepthBias() { - return Exchange(Dirty::DepthBias, false); + return Exchange(Dirty::DepthBias, false) || + Exchange(VideoCommon::Dirty::DepthBiasGlobal, false); } bool TouchBlendConstants() { diff --git a/src/video_core/texture_cache/texture_cache.h b/src/video_core/texture_cache/texture_cache.h index 329df2e49..f70c1f764 100644 --- a/src/video_core/texture_cache/texture_cache.h +++ b/src/video_core/texture_cache/texture_cache.h @@ -221,6 +221,7 @@ void TextureCache<P>::UpdateRenderTargets(bool is_clear) { BindRenderTarget(&render_targets.depth_buffer_id, FindDepthBuffer(is_clear)); } const ImageViewId depth_buffer_id = render_targets.depth_buffer_id; + PrepareImageView(depth_buffer_id, true, is_clear && IsFullClear(depth_buffer_id)); for (size_t index = 0; index < NUM_RT; ++index) { @@ -230,6 +231,8 @@ void TextureCache<P>::UpdateRenderTargets(bool is_clear) { maxwell3d.regs.render_area.width, maxwell3d.regs.render_area.height, }; + + flags[Dirty::DepthBiasGlobal] = true; } template <class P> diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 6388ed2eb..0f807990c 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -623,6 +623,10 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR is_float16_supported = false; } + supports_d24_depth = + IsFormatSupported(VK_FORMAT_D24_UNORM_S8_UINT, + VK_FORMAT_FEATURE_DEPTH_STENCIL_ATTACHMENT_BIT, FormatType::Optimal); + graphics_queue = logical.GetQueue(graphics_family); present_queue = logical.GetQueue(present_family); } diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index d9e74f1aa..2d5daf6cd 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -332,6 +332,10 @@ public: return sets_per_pool; } + bool SupportsD24DepthBuffer() const { + return supports_d24_depth; + } + private: /// Checks if the physical device is suitable. void CheckSuitability(bool requires_swapchain) const; @@ -425,6 +429,7 @@ private: bool has_broken_cube_compatibility{}; ///< Has broken cube compatiblity bit bool has_renderdoc{}; ///< Has RenderDoc attached bool has_nsight_graphics{}; ///< Has Nsight Graphics attached + bool supports_d24_depth{}; ///< Supports D24 depth buffers. // Telemetry parameters std::string vendor_name; ///< Device's driver name. diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 402be6a78..d62fd566f 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt @@ -299,6 +299,11 @@ if (YUZU_USE_BUNDLED_QT) copy_yuzu_Qt5_deps(yuzu) endif() +if (ENABLE_SDL2) + target_link_libraries(yuzu PRIVATE SDL2) + target_compile_definitions(yuzu PRIVATE HAVE_SDL2) +endif() + if (MSVC) include(CopyYuzuSDLDeps) include(CopyYuzuFFmpegDeps) diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index 30a864135..faea5dda1 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp @@ -918,8 +918,7 @@ void Config::ReadSystemValues() { const auto custom_rtc_enabled = ReadSetting(QStringLiteral("custom_rtc_enabled"), false).toBool(); if (custom_rtc_enabled) { - Settings::values.custom_rtc = - std::chrono::seconds(ReadSetting(QStringLiteral("custom_rtc"), 0).toULongLong()); + Settings::values.custom_rtc = ReadSetting(QStringLiteral("custom_rtc"), 0).toLongLong(); } else { Settings::values.custom_rtc = std::nullopt; } @@ -1450,9 +1449,7 @@ void Config::SaveSystemValues() { WriteSetting(QStringLiteral("custom_rtc_enabled"), Settings::values.custom_rtc.has_value(), false); WriteSetting(QStringLiteral("custom_rtc"), - QVariant::fromValue<long long>( - Settings::values.custom_rtc.value_or(std::chrono::seconds{}).count()), - 0); + QVariant::fromValue<long long>(Settings::values.custom_rtc.value_or(0)), 0); } WriteGlobalSetting(Settings::values.sound_index); diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index 4fa0c4a43..642a5f966 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -81,8 +81,11 @@ ConfigureDialog::ConfigureDialog(QWidget* parent, HotkeyRegistry& registry, SetConfiguration(); PopulateSelectionList(); - connect(ui->tabWidget, &QTabWidget::currentChanged, this, - [this]() { debug_tab_tab->SetCurrentIndex(0); }); + connect(ui->tabWidget, &QTabWidget::currentChanged, this, [this](int index) { + if (index != -1) { + debug_tab_tab->SetCurrentIndex(0); + } + }); connect(ui_tab.get(), &ConfigureUi::LanguageChanged, this, &ConfigureDialog::OnLanguageChanged); connect(ui->selectorList, &QListWidget::itemSelectionChanged, this, &ConfigureDialog::UpdateVisibleTabs); diff --git a/src/yuzu/configuration/configure_per_game.cpp b/src/yuzu/configuration/configure_per_game.cpp index 1031399e1..12699c126 100644 --- a/src/yuzu/configuration/configure_per_game.cpp +++ b/src/yuzu/configuration/configure_per_game.cpp @@ -66,7 +66,7 @@ ConfigurePerGame::ConfigurePerGame(QWidget* parent, u64 title_id, const std::str ui->tabWidget->addTab(system_tab.get(), tr("System")); ui->tabWidget->addTab(cpu_tab.get(), tr("CPU")); ui->tabWidget->addTab(graphics_tab.get(), tr("Graphics")); - ui->tabWidget->addTab(graphics_advanced_tab.get(), tr("GraphicsAdvanced")); + ui->tabWidget->addTab(graphics_advanced_tab.get(), tr("Adv. Graphics")); ui->tabWidget->addTab(audio_tab.get(), tr("Audio")); setFocusPolicy(Qt::ClickFocus); diff --git a/src/yuzu/configuration/configure_per_game.ui b/src/yuzu/configuration/configure_per_game.ui index 60efdbf21..85c86e107 100644 --- a/src/yuzu/configuration/configure_per_game.ui +++ b/src/yuzu/configuration/configure_per_game.ui @@ -2,14 +2,6 @@ <ui version="4.0"> <class>ConfigurePerGame</class> <widget class="QDialog" name="ConfigurePerGame"> - <property name="geometry"> - <rect> - <x>0</x> - <y>0</y> - <width>900</width> - <height>630</height> - </rect> - </property> <property name="minimumSize"> <size> <width>900</width> diff --git a/src/yuzu/configuration/configure_system.cpp b/src/yuzu/configuration/configure_system.cpp index eea45f8ea..56c762d64 100644 --- a/src/yuzu/configuration/configure_system.cpp +++ b/src/yuzu/configuration/configure_system.cpp @@ -65,8 +65,7 @@ void ConfigureSystem::SetConfiguration() { QStringLiteral("%1") .arg(Settings::values.rng_seed.GetValue().value_or(0), 8, 16, QLatin1Char{'0'}) .toUpper(); - const auto rtc_time = Settings::values.custom_rtc.value_or( - std::chrono::seconds(QDateTime::currentSecsSinceEpoch())); + const auto rtc_time = Settings::values.custom_rtc.value_or(QDateTime::currentSecsSinceEpoch()); ui->rng_seed_checkbox->setChecked(Settings::values.rng_seed.GetValue().has_value()); ui->rng_seed_edit->setEnabled(Settings::values.rng_seed.GetValue().has_value() && @@ -75,7 +74,7 @@ void ConfigureSystem::SetConfiguration() { ui->custom_rtc_checkbox->setChecked(Settings::values.custom_rtc.has_value()); ui->custom_rtc_edit->setEnabled(Settings::values.custom_rtc.has_value()); - ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time.count())); + ui->custom_rtc_edit->setDateTime(QDateTime::fromSecsSinceEpoch(rtc_time)); if (Settings::IsConfiguringGlobal()) { ui->combo_language->setCurrentIndex(Settings::values.language_index.GetValue()); @@ -108,10 +107,9 @@ void ConfigureSystem::ApplyConfiguration() { // to allow in-game time to be fast forwarded if (Settings::IsConfiguringGlobal()) { if (ui->custom_rtc_checkbox->isChecked()) { - Settings::values.custom_rtc = - std::chrono::seconds(ui->custom_rtc_edit->dateTime().toSecsSinceEpoch()); + Settings::values.custom_rtc = ui->custom_rtc_edit->dateTime().toSecsSinceEpoch(); if (system.IsPoweredOn()) { - const s64 posix_time{Settings::values.custom_rtc->count() + + const s64 posix_time{*Settings::values.custom_rtc + Service::Time::TimeManager::GetExternalTimeZoneOffset()}; system.GetTimeManager().UpdateLocalSystemClockTime(posix_time); } diff --git a/src/yuzu/configuration/configure_tas.ui b/src/yuzu/configuration/configure_tas.ui index 6caa19031..7d44895c4 100644 --- a/src/yuzu/configuration/configure_tas.ui +++ b/src/yuzu/configuration/configure_tas.ui @@ -14,14 +14,14 @@ <item row="0" column="0" colspan="4"> <widget class="QLabel" name="label_1"> <property name="text"> - <string>Reads controller input from scripts in the same format as TAS-nx scripts.<br/>For a more detailed explanation please consult the FAQ on the yuzu website.</string> + <string><html><head/><body><p>Reads controller input from scripts in the same format as TAS-nx scripts.<br/>For a more detailed explanation, please consult the <a href="https://yuzu-emu.org/help/feature/tas/"><span style=" text-decoration: underline; color:#039be5;">help page</span></a> on the yuzu website.</p></body></html></string> </property> </widget> </item> <item row="1" column="0" colspan="4"> <widget class="QLabel" name="label_2"> <property name="text"> - <string>To check which hotkeys control the playback/recording, please refer to the Hotkey settings (General -> Hotkeys).</string> + <string>To check which hotkeys control the playback/recording, please refer to the Hotkey settings (Configure -> General -> Hotkeys).</string> </property> <property name="wordWrap"> <bool>true</bool> diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 2af582fe5..e871fee36 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp @@ -66,6 +66,10 @@ static FileSys::VirtualFile VfsDirectoryCreateFileWrapper(const FileSys::Virtual #include <QUrl> #include <QtConcurrent/QtConcurrent> +#ifdef HAVE_SDL2 +#include <SDL.h> // For SDL ScreenSaver functions +#endif + #include <fmt/format.h> #include "common/detached_tasks.h" #include "common/fs/fs.h" @@ -287,6 +291,14 @@ GMainWindow::GMainWindow() ui->action_Fullscreen->setChecked(false); +#if defined(HAVE_SDL2) && !defined(_WIN32) + SDL_InitSubSystem(SDL_INIT_VIDEO); + // SDL disables the screen saver by default, and setting the hint + // SDL_HINT_VIDEO_ALLOW_SCREENSAVER doesn't seem to work, so we just enable the screen saver + // for now. + SDL_EnableScreenSaver(); +#endif + QStringList args = QApplication::arguments(); if (args.size() < 2) { @@ -357,8 +369,9 @@ GMainWindow::GMainWindow() GMainWindow::~GMainWindow() { // will get automatically deleted otherwise - if (render_window->parent() == nullptr) + if (render_window->parent() == nullptr) { delete render_window; + } } void GMainWindow::RegisterMetaTypes() { @@ -1223,12 +1236,16 @@ void GMainWindow::OnDisplayTitleBars(bool show) { void GMainWindow::PreventOSSleep() { #ifdef _WIN32 SetThreadExecutionState(ES_CONTINUOUS | ES_SYSTEM_REQUIRED | ES_DISPLAY_REQUIRED); +#elif defined(HAVE_SDL2) + SDL_DisableScreenSaver(); #endif } void GMainWindow::AllowOSSleep() { #ifdef _WIN32 SetThreadExecutionState(ES_CONTINUOUS); +#elif defined(HAVE_SDL2) + SDL_EnableScreenSaver(); #endif } diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index 8ca20679a..0b8fde691 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp @@ -412,8 +412,7 @@ void Config::ReadValues() { const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false); if (custom_rtc_enabled) { - Settings::values.custom_rtc = - std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0)); + Settings::values.custom_rtc = sdl2_config->GetInteger("System", "custom_rtc", 0); } else { Settings::values.custom_rtc = std::nullopt; } |