From fe4355877977974bf5c629390f7d73b111073872 Mon Sep 17 00:00:00 2001 From: GPUCode Date: Thu, 15 Feb 2024 00:52:57 +0200 Subject: [PATCH 1/3] common: Rework timekeeping with native RDTSC and port to linux --- .gitmodules | 7 +- CMakeLists.txt | 17 +- src/common/log.cpp | 4 + src/common/native_clock.cpp | 43 ++++ src/common/native_clock.h | 32 +++ src/common/rdtsc.cpp | 60 ++++++ src/common/rdtsc.h | 37 ++++ src/common/timer.cpp | 108 ---------- src/common/timer.h | 43 ---- src/common/types.h | 10 +- src/common/uint128.h | 115 +++++++++++ src/core/PS4/GPU/gpu_memory.cpp | 2 +- src/core/PS4/HLE/Graphics/graphics_ctx.h | 3 +- src/core/file_sys/fs.h | 4 +- src/core/hle/kernel/Objects/event_queue.cpp | 32 +-- src/core/hle/kernel/Objects/event_queue.h | 1 + .../hle/kernel/Objects/physical_memory.cpp | 2 +- src/core/hle/kernel/event_queues.h | 2 +- src/core/hle/libraries/libc/libc_math.cpp | 16 +- src/core/hle/libraries/libc/libc_stdio.cpp | 2 +- .../hle/libraries/libkernel/libkernel.cpp | 11 + .../libraries/libkernel/time_management.cpp | 16 +- src/core/linker.cpp | 4 +- src/core/loader/elf.cpp | 2 +- src/core/virtual_memory.cpp | 12 +- src/emuTimer.cpp | 23 --- src/emuTimer.h | 10 - src/emulator.cpp | 34 +--- src/main.cpp | 2 - src/video_core/gpu_memory.cpp | 188 ++++++++++++++++++ src/video_core/gpu_memory.h | 86 ++++++++ src/video_core/tile_manager.cpp | 151 ++++++++++++++ src/video_core/tile_manager.h | 9 + third-party/CMakeLists.txt | 3 +- third-party/fmt | 2 +- third-party/spdlog | 2 +- third-party/vulkan | 2 +- 37 files changed, 818 insertions(+), 279 deletions(-) create mode 100644 src/common/native_clock.cpp create mode 100644 src/common/native_clock.h create mode 100644 src/common/rdtsc.cpp create mode 100644 src/common/rdtsc.h delete mode 100644 src/common/timer.cpp delete mode 100644 src/common/timer.h create mode 100644 src/common/uint128.h delete mode 100644 src/emuTimer.cpp delete mode 100644 src/emuTimer.h create mode 100644 src/video_core/gpu_memory.cpp create mode 100644 src/video_core/gpu_memory.h create mode 100644 src/video_core/tile_manager.cpp create mode 100644 src/video_core/tile_manager.h diff --git a/.gitmodules b/.gitmodules index 9cfbedd03..8a240d585 100644 --- a/.gitmodules +++ b/.gitmodules @@ -33,11 +33,10 @@ path = third-party/toml11 url = https://github.com/ToruNiina/toml11 branch = master -[submodule "third-party/vulkan"] - path = third-party/vulkan - url = https://github.com/shadps4/vulkan.git - branch = main [submodule "third-party/xxHash"] path = third-party/xxHash url = https://github.com/Cyan4973/xxHash.git branch = dev +[submodule "third-party/vulkan"] + path = third-party/vulkan + url = https://github.com/GPUCode/vulkan diff --git a/CMakeLists.txt b/CMakeLists.txt index 7db7e5b61..c3b2dca36 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -30,8 +30,8 @@ endfunction() add_subdirectory(third-party) include_directories(src) -set(LIBC_SOURCES src/core/hle/libraries/libc/Libc.cpp - src/core/hle/libraries/libc/Libc.h +set(LIBC_SOURCES src/core/hle/libraries/libc/libc.cpp + src/core/hle/libraries/libc/libc.h src/core/hle/libraries/libc/printf.h src/core/hle/libraries/libc/va_ctx.h src/core/hle/libraries/libc/libc_cxa.cpp @@ -77,12 +77,15 @@ add_executable(shadps4 src/common/fs_file.h src/common/log.cpp src/common/log.h + src/common/native_clock.cpp + src/common/native_clock.h + src/common/rdtsc.cpp + src/common/rdtsc.h src/common/singleton.h src/common/string_util.cpp src/common/string_util.h - src/common/timer.cpp - src/common/timer.h src/common/types.h + src/common/uint128.h src/common/version.h ${LIBC_SOURCES} ${USERSERVICE_SOURCES} @@ -143,8 +146,6 @@ add_executable(shadps4 src/core/PS4/HLE/Graphics/graphics_render.h src/core/PS4/GPU/tile_manager.cpp src/core/PS4/GPU/tile_manager.h - src/emuTimer.cpp - src/emuTimer.h src/core/hle/libraries/libkernel/time_management.cpp src/core/hle/libraries/libkernel/time_management.h "src/common/io_file.cpp" "src/common/io_file.h") @@ -161,6 +162,8 @@ add_custom_command(TARGET shadps4 POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different $ $) -add_custom_command(TARGET shadps4 POST_BUILD +if (WIN32) + add_custom_command(TARGET shadps4 POST_BUILD COMMAND ${CMAKE_COMMAND} -E copy_if_different "${PROJECT_SOURCE_DIR}/third-party/winpthread/bin/libwinpthread-1.dll" $) +endif() diff --git a/src/common/log.cpp b/src/common/log.cpp index 535d4bd0c..f4bb55f8d 100644 --- a/src/common/log.cpp +++ b/src/common/log.cpp @@ -109,7 +109,11 @@ int Init(bool use_stdout) { if (use_stdout) { sinks.push_back(std::make_shared()); } +#ifdef _WIN64 sinks.push_back(std::make_shared(L"shadps4.txt", true)); +#else + sinks.push_back(std::make_shared("shadps4.txt", true)); +#endif spdlog::set_default_logger(std::make_shared("shadps4 logger", begin(sinks), end(sinks))); auto f = std::make_unique("%^|%L|: %v%$", spdlog::pattern_time_type::local, std::string("")); // disable eol spdlog::set_formatter(std::move(f)); diff --git a/src/common/native_clock.cpp b/src/common/native_clock.cpp new file mode 100644 index 000000000..e722de0df --- /dev/null +++ b/src/common/native_clock.cpp @@ -0,0 +1,43 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include "common/uint128.h" +#include "common/native_clock.h" +#include "common/rdtsc.h" +#ifdef _WIN64 +#include +#else +#include +#endif + +namespace Common { + +NativeClock::NativeClock() + : rdtsc_frequency{EstimateRDTSCFrequency()}, ns_rdtsc_factor{GetFixedPoint64Factor(std::nano::den, + rdtsc_frequency)}, + us_rdtsc_factor{GetFixedPoint64Factor(std::micro::den, rdtsc_frequency)}, + ms_rdtsc_factor{GetFixedPoint64Factor(std::milli::den, rdtsc_frequency)} {} + +u64 NativeClock::GetTimeNS() const { + return MultiplyHigh(GetUptime(), ns_rdtsc_factor); +} + +u64 NativeClock::GetTimeUS() const { + return MultiplyHigh(GetUptime(), us_rdtsc_factor); +} + +u64 NativeClock::GetTimeMS() const { + return MultiplyHigh(GetUptime(), ms_rdtsc_factor); +} + +u64 NativeClock::GetUptime() const { + return FencedRDTSC(); +} + +u64 NativeClock::GetProcessTimeUS() const { + timespec ret; + clock_gettime(CLOCK_PROCESS_CPUTIME_ID, &ret); + return ret.tv_nsec / 1000 + ret.tv_sec * 1000000; +} + +} // namespace Common::X64 diff --git a/src/common/native_clock.h b/src/common/native_clock.h new file mode 100644 index 000000000..227c8d1ae --- /dev/null +++ b/src/common/native_clock.h @@ -0,0 +1,32 @@ +// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include +#include "common/types.h" + +namespace Common { + +class NativeClock final { +public: + explicit NativeClock(); + + u64 GetTscFrequency() const { + return rdtsc_frequency; + } + + u64 GetTimeNS() const; + u64 GetTimeUS() const; + u64 GetTimeMS() const; + u64 GetUptime() const; + u64 GetProcessTimeUS() const; + +private: + u64 rdtsc_frequency; + u64 ns_rdtsc_factor; + u64 us_rdtsc_factor; + u64 ms_rdtsc_factor; +}; + +} // namespace Common diff --git a/src/common/rdtsc.cpp b/src/common/rdtsc.cpp new file mode 100644 index 000000000..8d231a980 --- /dev/null +++ b/src/common/rdtsc.cpp @@ -0,0 +1,60 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#include +#include "common/rdtsc.h" +#include "common/uint128.h" + +#ifdef _WIN64 +#include +#endif + +namespace Common { + +static constexpr size_t SecondToNanoseconds = 1000000000ULL; + +template +static u64 RoundToNearest(u64 value) { + const auto mod = value % Nearest; + return mod >= (Nearest / 2) ? (value - mod + Nearest) : (value - mod); +} + +static u64 GetTimeNs() { +#ifdef _WIN64 + // GetSystemTimePreciseAsFileTime returns the file time in 100ns units. + static constexpr u64 Multiplier = 100; + // Convert Windows epoch to Unix epoch. + static constexpr u64 WindowsEpochToUnixEpoch = 0x19DB1DED53E8000LL; + FILETIME filetime; + GetSystemTimePreciseAsFileTime(&filetime); + return Multiplier * ((static_cast(filetime.dwHighDateTime) << 32) + + static_cast(filetime.dwLowDateTime) - WindowsEpochToUnixEpoch); +#elif defined(__APPLE__) + return clock_gettime_nsec_np(CLOCK_REALTIME); +#else + timespec ts; + clock_gettime(CLOCK_REALTIME, &ts); + return ts.tv_sec * SecondToNanoseconds + ts.tv_nsec; +#endif +} + +u64 EstimateRDTSCFrequency() { + // Discard the first result measuring the rdtsc. + FencedRDTSC(); + std::this_thread::sleep_for(std::chrono::milliseconds{1}); + FencedRDTSC(); + + // Get the current time. + const auto start_time = GetTimeNs(); + const u64 tsc_start = FencedRDTSC(); + // Wait for 100 milliseconds. + std::this_thread::sleep_for(std::chrono::milliseconds{100}); + const auto end_time = GetTimeNs(); + const u64 tsc_end = FencedRDTSC(); + // Calculate differences. + const u64 tsc_diff = tsc_end - tsc_start; + const u64 tsc_freq = MultiplyAndDivide64(tsc_diff, 1000000000ULL, end_time - start_time); + return RoundToNearest<100'000>(tsc_freq); +} + +} // namespace Common diff --git a/src/common/rdtsc.h b/src/common/rdtsc.h new file mode 100644 index 000000000..3180273e5 --- /dev/null +++ b/src/common/rdtsc.h @@ -0,0 +1,37 @@ +// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#ifdef _MSC_VER +#include +#endif + +#include "common/types.h" + +namespace Common { + +#ifdef _MSC_VER +__forceinline static u64 FencedRDTSC() { + _mm_lfence(); + _ReadWriteBarrier(); + const u64 result = __rdtsc(); + _mm_lfence(); + _ReadWriteBarrier(); + return result; +} +#else +static inline u64 FencedRDTSC() { + u64 eax; + u64 edx; + asm volatile("lfence\n\t" + "rdtsc\n\t" + "lfence\n\t" + : "=a"(eax), "=d"(edx)); + return (edx << 32) | eax; +} +#endif + +u64 EstimateRDTSCFrequency(); + +} // namespace Common diff --git a/src/common/timer.cpp b/src/common/timer.cpp deleted file mode 100644 index fa3d172ba..000000000 --- a/src/common/timer.cpp +++ /dev/null @@ -1,108 +0,0 @@ -#include "common/timer.h" - -#ifdef _WIN64 -#include -#endif - -namespace Common { - -Timer::Timer() { -#ifdef _WIN64 - LARGE_INTEGER f; - QueryPerformanceFrequency(&f); - m_Frequency = f.QuadPart; -#else -#error Unimplemented Timer constructor -#endif -} - -void Timer::Start() { -#ifdef _WIN64 - LARGE_INTEGER c; - QueryPerformanceCounter(&c); - m_StartTime = c.QuadPart; -#else -#error Unimplemented Timer::Start() -#endif - m_is_timer_paused = false; -} - -void Timer::Pause() { -#ifdef _WIN64 - LARGE_INTEGER c; - QueryPerformanceCounter(&c); - m_PauseTime = c.QuadPart; -#else -#error Unimplemented Timer::Pause() -#endif - m_is_timer_paused = true; -} - -void Timer::Resume() { - u64 current_time = 0; -#ifdef _WIN64 - LARGE_INTEGER c; - QueryPerformanceCounter(&c); - current_time = c.QuadPart; -#else -#error Unimplemented Timer::Resume() -#endif - m_StartTime += current_time - m_PauseTime; - m_is_timer_paused = false; -} - -double Timer::GetTimeMsec() const { - if (m_is_timer_paused) { - return 1000.0 * (static_cast(m_PauseTime - m_StartTime)) / static_cast(m_Frequency); - } - - u64 current_time = 0; -#ifdef _WIN64 - LARGE_INTEGER c; - QueryPerformanceCounter(&c); - current_time = c.QuadPart; -#else -#error Unimplemented Timer::GetTimeMsec() -#endif - return 1000.0 * (static_cast(current_time - m_StartTime)) / static_cast(m_Frequency); -} - -double Timer::GetTimeSec() const { - if (m_is_timer_paused) { - return (static_cast(m_PauseTime - m_StartTime)) / static_cast(m_Frequency); - } - - u64 current_time = 0; -#ifdef _WIN64 - LARGE_INTEGER c; - QueryPerformanceCounter(&c); - current_time = c.QuadPart; -#else -#error Unimplemented Timer::GetTimeSec() -#endif - return (static_cast(current_time - m_StartTime)) / static_cast(m_Frequency); -} - -u64 Timer::GetTicks() const { - if (m_is_timer_paused) { - return (m_PauseTime - m_StartTime); - } - - u64 current_time = 0; -#ifdef _WIN64 - LARGE_INTEGER c; - QueryPerformanceCounter(&c); - current_time = c.QuadPart; -#else -#error Unimplemented Timer::GetTicks() -#endif - return (current_time - m_StartTime); -} - -u64 Timer::getQueryPerformanceCounter() { - LARGE_INTEGER c; - QueryPerformanceCounter(&c); - return c.QuadPart; -} - -} // namespace Common diff --git a/src/common/timer.h b/src/common/timer.h deleted file mode 100644 index e390e7e68..000000000 --- a/src/common/timer.h +++ /dev/null @@ -1,43 +0,0 @@ -#pragma once - -#include "common/types.h" - -namespace Common { - -class Timer final { -public: - Timer(); - ~Timer() = default; - - void Start(); - void Pause(); - void Resume(); - - bool IsPaused() const { - return m_is_timer_paused; - } - - u64 GetFrequency() const { - return m_Frequency; - } - - double GetTimeMsec() const; - double GetTimeSec() const; - u64 GetTicks() const; - - [[nodiscard]] static u64 getQueryPerformanceCounter(); - -public: - Timer(const Timer&) = delete; - Timer& operator=(const Timer&) = delete; - Timer(Timer&&) = delete; - Timer& operator=(Timer&&) = delete; - -private: - bool m_is_timer_paused = true; - u64 m_Frequency{}; - u64 m_StartTime{}; - u64 m_PauseTime{}; -}; - -} // namespace Common diff --git a/src/common/types.h b/src/common/types.h index 9ddfede94..4d86ec25c 100644 --- a/src/common/types.h +++ b/src/common/types.h @@ -1,5 +1,6 @@ #pragma once +#include #include using s08 = std::int8_t; @@ -15,9 +16,12 @@ using u64 = std::uint64_t; using f32 = float; using f64 = double; +using u128 = std::array; +static_assert(sizeof(u128) == 16, "u128 must be 128 bits wide"); + #define PS4_SYSV_ABI __attribute__((sysv_abi)) // UDLs for memory size values -constexpr u64 operator""_KB(u64 x) { return 1024ULL * x; } -constexpr u64 operator""_MB(u64 x) { return 1024_KB * x; } -constexpr u64 operator""_GB(u64 x) { return 1024_MB * x; } +constexpr unsigned long long operator""_KB(unsigned long long x) { return 1024ULL * x; } +constexpr unsigned long long operator""_MB(unsigned long long x) { return 1024_KB * x; } +constexpr unsigned long long operator""_GB(unsigned long long x) { return 1024_MB * x; } diff --git a/src/common/uint128.h b/src/common/uint128.h new file mode 100644 index 000000000..c44357916 --- /dev/null +++ b/src/common/uint128.h @@ -0,0 +1,115 @@ +// SPDX-FileCopyrightText: Copyright 2019 yuzu Emulator Project +// SPDX-License-Identifier: GPL-2.0-or-later + +#pragma once + +#include + +#ifdef _MSC_VER +#ifndef __clang__ +#define HAS_INTRINSICS +#include +#pragma intrinsic(__umulh) +#pragma intrinsic(_umul128) +#pragma intrinsic(_udiv128) +#else +#endif +#else +#include +#endif + +#include "common/types.h" + +namespace Common { + +// This function multiplies 2 u64 values and divides it by a u64 value. +[[nodiscard]] static inline u64 MultiplyAndDivide64(u64 a, u64 b, u64 d) { +#ifdef HAS_INTRINSICS + u128 r{}; + r[0] = _umul128(a, b, &r[1]); + u64 remainder; + return _udiv128(r[1], r[0], d, &remainder); +#else + const u64 diva = a / d; + const u64 moda = a % d; + const u64 divb = b / d; + const u64 modb = b % d; + return diva * b + moda * divb + moda * modb / d; +#endif +} + +// This function multiplies 2 u64 values and produces a u128 value; +[[nodiscard]] static inline u128 Multiply64Into128(u64 a, u64 b) { + u128 result; +#ifdef HAS_INTRINSICS + result[0] = _umul128(a, b, &result[1]); +#else + unsigned __int128 tmp = a; + tmp *= b; + std::memcpy(&result, &tmp, sizeof(u128)); +#endif + return result; +} + +[[nodiscard]] static inline u64 GetFixedPoint64Factor(u64 numerator, u64 divisor) { +#ifdef __SIZEOF_INT128__ + const auto base = static_cast(numerator) << 64ULL; + return static_cast(base / divisor); +#elif defined(_M_X64) || defined(_M_ARM64) + std::array r = {0, numerator}; + u64 remainder; + return _udiv128(r[1], r[0], divisor, &remainder); +#else + // This one is bit more inaccurate. + return MultiplyAndDivide64(std::numeric_limits::max(), numerator, divisor); +#endif +} + +[[nodiscard]] static inline u64 MultiplyHigh(u64 a, u64 b) { +#ifdef __SIZEOF_INT128__ + return (static_cast(a) * static_cast(b)) >> 64; +#elif defined(_M_X64) || defined(_M_ARM64) + return __umulh(a, b); // MSVC +#else + // Generic fallback + const u64 a_lo = u32(a); + const u64 a_hi = a >> 32; + const u64 b_lo = u32(b); + const u64 b_hi = b >> 32; + + const u64 a_x_b_hi = a_hi * b_hi; + const u64 a_x_b_mid = a_hi * b_lo; + const u64 b_x_a_mid = b_hi * a_lo; + const u64 a_x_b_lo = a_lo * b_lo; + + const u64 carry_bit = (static_cast(static_cast(a_x_b_mid)) + + static_cast(static_cast(b_x_a_mid)) + (a_x_b_lo >> 32)) >> + 32; + + const u64 multhi = a_x_b_hi + (a_x_b_mid >> 32) + (b_x_a_mid >> 32) + carry_bit; + + return multhi; +#endif +} + +// This function divides a u128 by a u32 value and produces two u64 values: +// the result of division and the remainder +[[nodiscard]] static inline std::pair Divide128On32(u128 dividend, u32 divisor) { + u64 remainder = dividend[0] % divisor; + u64 accum = dividend[0] / divisor; + if (dividend[1] == 0) + return {accum, remainder}; + // We ignore dividend[1] / divisor as that overflows + const u64 first_segment = (dividend[1] % divisor) << 32; + accum += (first_segment / divisor) << 32; + const u64 second_segment = (first_segment % divisor) << 32; + accum += (second_segment / divisor); + remainder += second_segment % divisor; + if (remainder >= divisor) { + accum++; + remainder -= divisor; + } + return {accum, remainder}; +} + +} // namespace Common diff --git a/src/core/PS4/GPU/gpu_memory.cpp b/src/core/PS4/GPU/gpu_memory.cpp index c278f37ec..8f3086bc0 100644 --- a/src/core/PS4/GPU/gpu_memory.cpp +++ b/src/core/PS4/GPU/gpu_memory.cpp @@ -1,5 +1,5 @@ #include "gpu_memory.h" - +#include #include #include "common/singleton.h" diff --git a/src/core/PS4/HLE/Graphics/graphics_ctx.h b/src/core/PS4/HLE/Graphics/graphics_ctx.h index eb3550566..cd2b6a3c4 100644 --- a/src/core/PS4/HLE/Graphics/graphics_ctx.h +++ b/src/core/PS4/HLE/Graphics/graphics_ctx.h @@ -2,8 +2,9 @@ #include "common/types.h" #include -#include +#include #include +#include namespace HLE::Libs::Graphics { diff --git a/src/core/file_sys/fs.h b/src/core/file_sys/fs.h index 45bf718f7..8bfdbff9c 100644 --- a/src/core/file_sys/fs.h +++ b/src/core/file_sys/fs.h @@ -1,4 +1,6 @@ #pragma once + +#include #include #include #include @@ -52,4 +54,4 @@ class HandleTable { std::mutex m_mutex; }; -} // namespace Core::FileSys \ No newline at end of file +} // namespace Core::FileSys diff --git a/src/core/hle/kernel/Objects/event_queue.cpp b/src/core/hle/kernel/Objects/event_queue.cpp index 1ca2d6f13..8720daf62 100644 --- a/src/core/hle/kernel/Objects/event_queue.cpp +++ b/src/core/hle/kernel/Objects/event_queue.cpp @@ -1,6 +1,5 @@ #include "common/debug.h" -#include "common/timer.h" -#include "core/hle/kernel/objects/event_queue.h" +#include "core/hle/kernel/Objects/event_queue.h" namespace Core::Kernel { @@ -24,28 +23,19 @@ int EqueueInternal::addEvent(const EqueueEvent& event) { int EqueueInternal::waitForEvents(SceKernelEvent* ev, int num, u32 micros) { std::unique_lock lock{m_mutex}; + int ret = 0; - u32 timeElapsed = 0; - Common::Timer t; - t.Start(); + const auto predicate = [&] { + ret = getTriggeredEvents(ev, num); + return ret > 0; + }; - for (;;) { - int ret = getTriggeredEvents(ev, num); - - if (ret > 0 || (timeElapsed >= micros && micros != 0)) { - return ret; - } - - if (micros == 0) { - m_cond.wait(lock); - } else { - m_cond.wait_for(lock, std::chrono::microseconds(micros - timeElapsed)); - } - - timeElapsed = static_cast(t.GetTimeSec() * 1000000.0); + if (micros == 0) { + m_cond.wait(lock, predicate); + } else { + m_cond.wait_for(lock, std::chrono::microseconds(micros), predicate); } - - return 0; + return ret; } bool EqueueInternal::triggerEvent(u64 ident, s16 filter, void* trigger_data) { diff --git a/src/core/hle/kernel/Objects/event_queue.h b/src/core/hle/kernel/Objects/event_queue.h index 3217bed29..407ccee9b 100644 --- a/src/core/hle/kernel/Objects/event_queue.h +++ b/src/core/hle/kernel/Objects/event_queue.h @@ -3,6 +3,7 @@ #include #include #include +#include #include "common/types.h" namespace Core::Kernel { diff --git a/src/core/hle/kernel/Objects/physical_memory.cpp b/src/core/hle/kernel/Objects/physical_memory.cpp index a4bca4c8c..58900f812 100644 --- a/src/core/hle/kernel/Objects/physical_memory.cpp +++ b/src/core/hle/kernel/Objects/physical_memory.cpp @@ -1,4 +1,4 @@ -#include "core/hle/kernel/objects/physical_memory.h" +#include "core/hle/kernel/Objects/physical_memory.h" namespace Core::Kernel { diff --git a/src/core/hle/kernel/event_queues.h b/src/core/hle/kernel/event_queues.h index e26be3bc2..2f39f83ae 100644 --- a/src/core/hle/kernel/event_queues.h +++ b/src/core/hle/kernel/event_queues.h @@ -1,6 +1,6 @@ #pragma once -#include "core/hle/kernel/objects/event_queue.h" +#include "core/hle/kernel/Objects/event_queue.h" namespace Core::Kernel { diff --git a/src/core/hle/libraries/libc/libc_math.cpp b/src/core/hle/libraries/libc/libc_math.cpp index 541dfb1a2..4052b7c48 100644 --- a/src/core/hle/libraries/libc/libc_math.cpp +++ b/src/core/hle/libraries/libc/libc_math.cpp @@ -4,35 +4,35 @@ namespace Core::Libraries::LibC { float PS4_SYSV_ABI ps4_atan2f(float y, float x) { - return std::atan2f(y, x); + return atan2f(y, x); } float PS4_SYSV_ABI ps4_acosf(float num) { - return std::acosf(num); + return acosf(num); } float PS4_SYSV_ABI ps4_tanf(float num) { - return std::tanf(num); + return tanf(num); } float PS4_SYSV_ABI ps4_asinf(float num) { - return std::asinf(num); + return asinf(num); } double PS4_SYSV_ABI ps4_pow(double base, double exponent) { - return std::pow(base, exponent); + return pow(base, exponent); } double PS4_SYSV_ABI ps4__Sin(double x) { - return std::sin(x); + return sin(x); } float PS4_SYSV_ABI ps4__Fsin(float arg) { - return std::sinf(arg); + return sinf(arg); } double PS4_SYSV_ABI ps4_exp2(double arg) { - return std::exp2(arg); + return exp2(arg); } } // namespace Core::Libraries::LibC diff --git a/src/core/hle/libraries/libc/libc_stdio.cpp b/src/core/hle/libraries/libc/libc_stdio.cpp index b3b5dac28..aae854831 100644 --- a/src/core/hle/libraries/libc/libc_stdio.cpp +++ b/src/core/hle/libraries/libc/libc_stdio.cpp @@ -12,7 +12,7 @@ int PS4_SYSV_ABI ps4_printf(VA_ARGS) { } int PS4_SYSV_ABI ps4_fprintf(FILE* file, VA_ARGS) { - int fd = _fileno(file); + int fd = fileno(file); if (fd == 1 || fd == 2) { // output stdout and stderr to console VA_CTX(ctx); return printf_ctx(&ctx); diff --git a/src/core/hle/libraries/libkernel/libkernel.cpp b/src/core/hle/libraries/libkernel/libkernel.cpp index e0cb27bd7..9eadbcb8b 100644 --- a/src/core/hle/libraries/libkernel/libkernel.cpp +++ b/src/core/hle/libraries/libkernel/libkernel.cpp @@ -15,6 +15,8 @@ #ifdef _WIN64 #include #include +#else +#include #endif #include "thread_management.h" @@ -56,6 +58,7 @@ int* PS4_SYSV_ABI __Error() { return &libc_error; } #define PROT_WRITE 0x2 int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, off_t offset, void** res) { +#ifdef _WIN64 PRINT_FUNCTION_NAME(); if (prot > 3) // READ,WRITE or bitwise READ | WRITE supported { @@ -86,6 +89,14 @@ int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd, } *res = ret; return 0; +#else + void* result = mmap(addr, len, prot, flags, fd, offset); + if (result != MAP_FAILED) { + *res = result; + return 0; + } + std::abort(); +#endif } PS4_SYSV_ABI void* posix_mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset) { diff --git a/src/core/hle/libraries/libkernel/time_management.cpp b/src/core/hle/libraries/libkernel/time_management.cpp index a1b40ce8b..00861a1be 100644 --- a/src/core/hle/libraries/libkernel/time_management.cpp +++ b/src/core/hle/libraries/libkernel/time_management.cpp @@ -1,27 +1,31 @@ -#include "common/timer.h" +#include "common/native_clock.h" #include "core/hle/libraries/libkernel/time_management.h" #include "core/hle/libraries/libs.h" -#include "emuTimer.h" namespace Core::Libraries::LibKernel { +static u64 initial_ptc; +static std::unique_ptr clock; + u64 PS4_SYSV_ABI sceKernelGetProcessTime() { - return static_cast(Emulator::emuTimer::getTimeMsec() * 1000.0); // return time in microseconds + return clock->GetProcessTimeUS(); } u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounter() { - return Emulator::emuTimer::getTimeCounter(); + return clock->GetUptime() - initial_ptc; } u64 PS4_SYSV_ABI sceKernelGetProcessTimeCounterFrequency() { - return Emulator::emuTimer::getTimeFrequency(); + return clock->GetTscFrequency(); } u64 PS4_SYSV_ABI sceKernelReadTsc() { - return Common::Timer::getQueryPerformanceCounter(); + return clock->GetUptime(); } void timeSymbolsRegister(Loader::SymbolsResolver* sym) { + clock = std::make_unique(); + initial_ptc = clock->GetUptime(); LIB_FUNCTION("4J2sUJmuHZQ", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTime); LIB_FUNCTION("fgxnMeTNUtY", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTimeCounter); LIB_FUNCTION("BNowx2l588E", "libkernel", 1, "libkernel", 1, 1, sceKernelGetProcessTimeCounterFrequency); diff --git a/src/core/linker.cpp b/src/core/linker.cpp index cc35c884c..611d6b1b7 100644 --- a/src/core/linker.cpp +++ b/src/core/linker.cpp @@ -658,12 +658,12 @@ void Linker::Resolve(const std::string& name, int Symtype, Module* m, Loader::Sy } else { - __debugbreak();//den tha prepei na ftasoume edo + //__debugbreak();//den tha prepei na ftasoume edo } } else { - __debugbreak();//oute edo mallon + //__debugbreak();//oute edo mallon } } diff --git a/src/core/loader/elf.cpp b/src/core/loader/elf.cpp index 729d6b93d..b23f6c6f7 100644 --- a/src/core/loader/elf.cpp +++ b/src/core/loader/elf.cpp @@ -5,7 +5,7 @@ namespace Core::Loader { -constexpr bool log_file_loader = true; // disable it to disable logging +constexpr bool log_file_loader = false; // disable it to disable logging static std::string_view getProgramTypeName(program_type_es type) { switch (type) { diff --git a/src/core/virtual_memory.cpp b/src/core/virtual_memory.cpp index f730aff4a..cdff12c2a 100644 --- a/src/core/virtual_memory.cpp +++ b/src/core/virtual_memory.cpp @@ -79,7 +79,8 @@ bool memory_protect(u64 address, u64 size, MemoryMode mode, MemoryMode* old_mode } return true; #else -#error Unimplement memory_protect function + int ret = mprotect(reinterpret_cast(address), size, convertMemoryMode(mode)); + return true; #endif } @@ -117,6 +118,7 @@ bool memory_patch(u64 vaddr, u64 value) { static u64 AlignUp(u64 pos, u64 align) { return (align != 0 ? (pos + (align - 1)) & ~(align - 1) : pos); } u64 memory_alloc_aligned(u64 address, u64 size, MemoryMode mode, u64 alignment) { +#ifdef _WIN64 // try allocate aligned address inside user area MEM_ADDRESS_REQUIREMENTS req{}; MEM_EXTENDED_PARAMETER param{}; @@ -134,5 +136,13 @@ u64 memory_alloc_aligned(u64 address, u64 size, MemoryMode mode, u64 alignment) LOG_ERROR_IF(true, "VirtualAlloc2() failed: 0x{:X}\n", err); } return ptr; +#else + void* hint_address = reinterpret_cast(AlignUp(address, alignment)); + void* ptr = mmap(hint_address, size, convertMemoryMode(mode), MAP_ANON | MAP_PRIVATE, -1, 0); + if (ptr == MAP_FAILED) { + std::abort(); + } + return reinterpret_cast(ptr); +#endif } } // namespace VirtualMemory diff --git a/src/emuTimer.cpp b/src/emuTimer.cpp deleted file mode 100644 index b05c001be..000000000 --- a/src/emuTimer.cpp +++ /dev/null @@ -1,23 +0,0 @@ -#include "common/timer.h" - -namespace Emulator::emuTimer { - -static Common::Timer timer; - -void start() { - timer.Start(); -} - -double getTimeMsec() { - return timer.GetTimeMsec(); -} - -u64 getTimeCounter() { - return timer.GetTicks(); -} - -u64 getTimeFrequency() { - return timer.GetFrequency(); -} - -} // namespace Emulator::emuTimer diff --git a/src/emuTimer.h b/src/emuTimer.h deleted file mode 100644 index 26c207430..000000000 --- a/src/emuTimer.h +++ /dev/null @@ -1,10 +0,0 @@ -#pragma once - -#include "common/types.h" - -namespace Emulator::emuTimer { -void start(); -double getTimeMsec(); -u64 getTimeCounter(); -u64 getTimeFrequency(); -} // namespace Emulator::emuTimer diff --git a/src/emulator.cpp b/src/emulator.cpp index 51f13be61..e52cd0545 100644 --- a/src/emulator.cpp +++ b/src/emulator.cpp @@ -1,6 +1,5 @@ #include #include -#include "common/timer.h" #include "common/singleton.h" #include "common/version.h" #include "emulator.h" @@ -90,8 +89,6 @@ static void calculateFps(double game_time_s) { } } void emuRun() { - Common::Timer timer; - timer.Start(); auto window_ctx = Common::Singleton::Instance(); { // init window and wait until init finishes @@ -100,7 +97,7 @@ void emuRun() { Graphics::Vulkan::vulkanCreate(window_ctx); window_ctx->m_is_graphic_initialized = true; window_ctx->m_graphic_initialized_cond.notify_one(); - calculateFps(timer.GetTimeSec()); + calculateFps(0); // TODO: Proper fps } bool exit_loop = false; @@ -138,10 +135,6 @@ void emuRun() { continue; } if (m_game_is_paused) { - if (!timer.IsPaused()) { - timer.Pause(); - } - SDL_WaitEvent(&event); switch (event.type) { @@ -171,21 +164,13 @@ void emuRun() { continue; } exit_loop = m_emu_needs_exit; - if (m_game_is_paused) { - if (!timer.IsPaused()) { - timer.Pause(); - } - } else { - if (timer.IsPaused()) { - timer.Resume(); - } - + if (!m_game_is_paused) { if (!exit_loop) { update(); } if (!exit_loop) { if (HLE::Libs::Graphics::VideoOut::videoOutFlip(100000)) { // flip every 0.1 sec - calculateFps(timer.GetTimeSec()); + calculateFps(0); // TODO: Proper fps } } } @@ -215,7 +200,7 @@ void DrawBuffer(HLE::Libs::Graphics::VideoOutVulkanImage* image) { window_ctx->swapchain.current_index = static_cast(-1); auto result = vkAcquireNextImageKHR(window_ctx->m_graphic_ctx.m_device, window_ctx->swapchain.swapchain, UINT64_MAX, nullptr, - window_ctx->swapchain.present_complete_fence, &window_ctx->swapchain.current_index); + VK_NULL_HANDLE, &window_ctx->swapchain.current_index); if (result != VK_SUCCESS) { fmt::print("Can't aquireNextImage\n"); @@ -226,16 +211,6 @@ void DrawBuffer(HLE::Libs::Graphics::VideoOutVulkanImage* image) { std::exit(0); } - do { - result = vkWaitForFences(window_ctx->m_graphic_ctx.m_device, 1, &window_ctx->swapchain.present_complete_fence, VK_TRUE, 100000000); - } while (result == VK_TIMEOUT); - if (result != VK_SUCCESS) { - fmt::print("vkWaitForFences is not success\n"); - std::exit(0); - } - - vkResetFences(window_ctx->m_graphic_ctx.m_device, 1, &window_ctx->swapchain.present_complete_fence); - auto blt_src_image = image; auto blt_dst_image = window_ctx->swapchain; @@ -272,6 +247,7 @@ void DrawBuffer(HLE::Libs::Graphics::VideoOutVulkanImage* image) { buffer.end(); buffer.executeWithSemaphore(); + buffer.waitForFence(); // HACK: The whole vulkan backend needs a rewrite VkPresentInfoKHR present{}; present.sType = VK_STRUCTURE_TYPE_PRESENT_INFO_KHR; diff --git a/src/main.cpp b/src/main.cpp index b7723ae74..84b00ee9f 100644 --- a/src/main.cpp +++ b/src/main.cpp @@ -14,7 +14,6 @@ #include "core/PS4/HLE/Graphics/video_out.h" #include "core/hle/libraries/libs.h" #include "core/linker.h" -#include "emuTimer.h" #include "emulator.h" #include #include "core/file_sys/fs.h" @@ -31,7 +30,6 @@ int main(int argc, char* argv[]) { auto height = Config::getScreenHeight(); Emu::emuInit(width, height); HLE::Libs::Graphics::VideoOut::videoOutInit(width, height); - Emulator::emuTimer::start(); // Argument 1 is the path of self file to boot const char* const path = argv[1]; diff --git a/src/video_core/gpu_memory.cpp b/src/video_core/gpu_memory.cpp new file mode 100644 index 000000000..4b5cfe6dc --- /dev/null +++ b/src/video_core/gpu_memory.cpp @@ -0,0 +1,188 @@ +#include "gpu_memory.h" +#include +#include + +#include "common/singleton.h" + +void* GPU::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, void* todo /*CommandBuffer?*/, u64 virtual_addr, u64 size, + const GPUObject& info) { + auto* gpumemory = Common::Singleton::Instance(); + + return gpumemory->memoryCreateObj(submit_id, ctx, nullptr, &virtual_addr, &size, 1, info); +} + +void GPU::memorySetAllocArea(u64 virtual_addr, u64 size) { + auto* gpumemory = Common::Singleton::Instance(); + + std::scoped_lock lock{gpumemory->m_mutex}; + + MemoryHeap h; + h.allocated_virtual_addr = virtual_addr; + h.allocated_size = size; + + gpumemory->m_heaps.push_back(h); +} + +u64 GPU::calculate_hash(const u08* buf, u64 size) { return (size > 0 && buf != nullptr ? XXH3_64bits(buf, size) : 0); } + +bool GPU::vulkanAllocateMemory(HLE::Libs::Graphics::GraphicCtx* ctx, HLE::Libs::Graphics::VulkanMemory* mem) { + static std::atomic_uint64_t unique_id = 0; + + VkPhysicalDeviceMemoryProperties memory_properties{}; + vkGetPhysicalDeviceMemoryProperties(ctx->m_physical_device, &memory_properties); + + u32 index = 0; + for (; index < memory_properties.memoryTypeCount; index++) { + if ((mem->requirements.memoryTypeBits & (static_cast(1) << index)) != 0 && + (memory_properties.memoryTypes[index].propertyFlags & mem->property) == mem->property) { + break; + } + } + + mem->type = index; + mem->offset = 0; + + VkMemoryAllocateInfo alloc_info{}; + alloc_info.sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO; + alloc_info.pNext = nullptr; + alloc_info.allocationSize = mem->requirements.size; + alloc_info.memoryTypeIndex = index; + + mem->unique_id = ++unique_id; + + auto result = vkAllocateMemory(ctx->m_device, &alloc_info, nullptr, &mem->memory); + + if (result == VK_SUCCESS) { + return true; + } + return false; +} + +void GPU::flushGarlic(HLE::Libs::Graphics::GraphicCtx* ctx) { + auto* gpumemory = Common::Singleton::Instance(); + gpumemory->flushAllHeaps(ctx); +} + +int GPU::GPUMemory::getHeapId(u64 virtual_addr, u64 size) { + int index = 0; + for (const auto& heap : m_heaps) { + if ((virtual_addr >= heap.allocated_virtual_addr && virtual_addr < heap.allocated_virtual_addr + heap.allocated_size) || + ((virtual_addr + size - 1) >= heap.allocated_virtual_addr && + (virtual_addr + size - 1) < heap.allocated_virtual_addr + heap.allocated_size)) { + return index; + } + index++; + } + return -1; +} + +void* GPU::GPUMemory::memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, void* todo, const u64* virtual_addr, const u64* size, + int virtual_addr_num, const GPUObject& info) { + auto* gpumemory = Common::Singleton::Instance(); + + std::scoped_lock lock{gpumemory->m_mutex}; + + int heap_id = gpumemory->getHeapId(virtual_addr[0], size[0]); + + if (heap_id < 0) { + return nullptr; + } + auto& heap = m_heaps[heap_id]; + + ObjInfo objInfo = {}; + + // Copy parameters from info to obj + for (int i = 0; i < 8; i++) { + objInfo.obj_params[i] = info.obj_params[i]; + } + + objInfo.gpu_object.objectType = info.objectType; + objInfo.gpu_object.obj = nullptr; + + for (int h = 0; h < virtual_addr_num; h++) { + if (info.check_hash) { + objInfo.hash[h] = GPU::calculate_hash(reinterpret_cast(virtual_addr[h]), size[h]); + } else { + objInfo.hash[h] = 0; + } + } + objInfo.submit_id = submit_id; + objInfo.check_hash = info.check_hash; + + objInfo.gpu_object.obj = info.getCreateFunc()(ctx, objInfo.obj_params, virtual_addr, size, virtual_addr_num, &objInfo.mem); + + objInfo.update_func = info.getUpdateFunc(); + int index = static_cast(heap.objects.size()); + + HeapObject hobj{}; + hobj.block = createHeapBlock(virtual_addr, size, virtual_addr_num, heap_id, index); + hobj.info = objInfo; + hobj.free = false; + heap.objects.push_back(hobj); + + return objInfo.gpu_object.obj; +} + +GPU::HeapBlock GPU::GPUMemory::createHeapBlock(const u64* virtual_addr, const u64* size, int virtual_addr_num, int heap_id, int obj_id) { + auto& heap = m_heaps[heap_id]; + + GPU::HeapBlock heapBlock{}; + heapBlock.virtual_addr_num = virtual_addr_num; + for (int vi = 0; vi < virtual_addr_num; vi++) { + heapBlock.virtual_addr[vi] = virtual_addr[vi]; + heapBlock.size[vi] = size[vi]; + } + return heapBlock; +} + +void GPU::GPUMemory::update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, int heap_id, int obj_id) { + auto& heap = m_heaps[heap_id]; + + auto& heapObj = heap.objects[obj_id]; + auto& objInfo = heapObj.info; + bool need_update = false; + + if (submit_id > objInfo.submit_id) { + uint64_t hash[3] = {}; + + for (int i = 0; i < heapObj.block.virtual_addr_num; i++) { + if (objInfo.check_hash) { + hash[i] = GPU::calculate_hash(reinterpret_cast(heapObj.block.virtual_addr[i]), heapObj.block.size[i]); + } else { + hash[i] = 0; + } + } + + for (int i = 0; i < heapObj.block.virtual_addr_num; i++) { + if (objInfo.hash[i] != hash[i]) { + need_update = true; + objInfo.hash[i] = hash[i]; + } + } + + if (submit_id != UINT64_MAX) { + objInfo.submit_id = submit_id; + } + } + + if (need_update) { + objInfo.update_func(ctx, objInfo.obj_params, objInfo.gpu_object.obj, heapObj.block.virtual_addr, heapObj.block.size, + heapObj.block.virtual_addr_num); + } +} + +void GPU::GPUMemory::flushAllHeaps(HLE::Libs::Graphics::GraphicCtx* ctx) { + std::scoped_lock lock{m_mutex}; + + int heap_id = 0; + for (auto& heap : m_heaps) { + int index = 0; + for (auto& heapObj : heap.objects) { + if (!heapObj.free) { + update(UINT64_MAX, ctx, heap_id, index); + } + index++; + } + heap_id++; + } +} diff --git a/src/video_core/gpu_memory.h b/src/video_core/gpu_memory.h new file mode 100644 index 000000000..87095ec78 --- /dev/null +++ b/src/video_core/gpu_memory.h @@ -0,0 +1,86 @@ +#pragma once + +#include "common/types.h" +#include +#include + +namespace VideoCore { + +class GPUObject; + +enum class MemoryMode : u32 { + NoAccess = 0, + Read = 1, + Write = 2, + ReadWrite = 3, +}; + +enum class MemoryObjectType : u64 { + Invalid, + VideoOutBuffer, +}; + +struct GpuMemoryObject { + MemoryObjectType object_type = MemoryObjectType::Invalid; + void* obj = nullptr; +}; + +struct HeapBlock { + std::array virtual_address{}; + std::array size{}; + u32 virtual_addr_num = 0; +}; + +class GPUObject { +public: + GPUObject() = default; + virtual ~GPUObject() = default; + u64 obj_params[8] = {}; + bool check_hash = false; + bool isReadOnly = false; + MemoryObjectType objectType = MemoryObjectType::Invalid; +}; + +struct ObjInfo { + std::array obj_params{}; + GpuMemoryObject gpu_object; + std::array hash{}; + u64 submit_id = 0; + bool check_hash = false; +}; + +struct HeapObject { + HeapBlock block; + ObjInfo info; + bool free = true; +}; +struct MemoryHeap { + u64 allocated_virtual_addr = 0; + u64 allocated_size = 0; + std::vector objects; +}; + +class GPUMemory { +public: + GPUMemory() {} + virtual ~GPUMemory() {} + int getHeapId(u64 vaddr, u64 size); + void* memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, /*CommandBuffer* buffer*/ void* todo, const u64* virtual_addr, + const u64* size, int virtual_addr_num, const GPUObject& info); + HeapBlock createHeapBlock(const u64* virtual_addr, const u64* size, int virtual_addr_num, int heap_id, int obj_id); + void update(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, int heap_id, int obj_id); + void flushAllHeaps(HLE::Libs::Graphics::GraphicCtx* ctx); + +private: + std::mutex m_mutex; + std::vector m_heaps; +}; + +void memorySetAllocArea(u64 virtual_addr, u64 size); +void* memoryCreateObj(u64 submit_id, HLE::Libs::Graphics::GraphicCtx* ctx, /*CommandBuffer* buffer*/ void* todo, u64 virtual_addr, u64 size, + const GPUObject& info); +u64 calculate_hash(const u08* buf, u64 size); +bool vulkanAllocateMemory(HLE::Libs::Graphics::GraphicCtx* ctx, HLE::Libs::Graphics::VulkanMemory* mem); +void flushGarlic(HLE::Libs::Graphics::GraphicCtx* ctx); + +} // namespace VideoCore diff --git a/src/video_core/tile_manager.cpp b/src/video_core/tile_manager.cpp new file mode 100644 index 000000000..c0d4ed3b1 --- /dev/null +++ b/src/video_core/tile_manager.cpp @@ -0,0 +1,151 @@ +#include +#include +#include "video_core/tile_manager.h" + +namespace VideoCore { + +class TileManager32 { + public: + u32 m_macro_tile_height = 0; + u32 m_bank_height = 0; + u32 m_num_banks = 0; + u32 m_num_pipes = 0; + u32 m_padded_width = 0; + u32 m_padded_height = 0; + u32 m_pipe_bits = 0; + u32 m_bank_bits = 0; + + TileManager32(u32 width, u32 height, bool is_neo) { + m_macro_tile_height = (is_neo ? 128 : 64); + m_bank_height = is_neo ? 2 : 1; + m_num_banks = is_neo ? 8 : 16; + m_num_pipes = is_neo ? 16 : 8; + m_padded_width = width; + if (height == 1080) { + m_padded_height = is_neo ? 1152 : 1088; + } + if (height == 720) { + m_padded_height = 768; + } + m_pipe_bits = is_neo ? 4 : 3; + m_bank_bits = is_neo ? 3 : 4; + } + + static u32 GetElementIndex(u32 x, u32 y) { + u32 elem = 0; + elem |= ((x >> 0u) & 0x1u) << 0u; + elem |= ((x >> 1u) & 0x1u) << 1u; + elem |= ((y >> 0u) & 0x1u) << 2u; + elem |= ((x >> 2u) & 0x1u) << 3u; + elem |= ((y >> 1u) & 0x1u) << 4u; + elem |= ((y >> 2u) & 0x1u) << 5u; + + return elem; + } + + static u32 GetPipeIndex(u32 x, u32 y, bool is_neo) { + u32 pipe = 0; + + if (!is_neo) { + pipe |= (((x >> 3u) ^ (y >> 3u) ^ (x >> 4u)) & 0x1u) << 0u; + pipe |= (((x >> 4u) ^ (y >> 4u)) & 0x1u) << 1u; + pipe |= (((x >> 5u) ^ (y >> 5u)) & 0x1u) << 2u; + } else { + pipe |= (((x >> 3u) ^ (y >> 3u) ^ (x >> 4u)) & 0x1u) << 0u; + pipe |= (((x >> 4u) ^ (y >> 4u)) & 0x1u) << 1u; + pipe |= (((x >> 5u) ^ (y >> 5u)) & 0x1u) << 2u; + pipe |= (((x >> 6u) ^ (y >> 5u)) & 0x1u) << 3u; + } + + return pipe; + } + + static u32 GetBankIndex(u32 x, u32 y, u32 bank_width, u32 bank_height, u32 num_banks, u32 num_pipes) { + const u32 x_shift_offset = std::bit_width(bank_width * num_pipes); + const u32 y_shift_offset = std::bit_width(bank_height); + const u32 xs = x >> x_shift_offset; + const u32 ys = y >> y_shift_offset; + u32 bank = 0; + switch (num_banks) { + case 8: + bank |= (((xs >> 3u) ^ (ys >> 5u)) & 0x1u) << 0u; + bank |= (((xs >> 4u) ^ (ys >> 4u) ^ (ys >> 5u)) & 0x1u) << 1u; + bank |= (((xs >> 5u) ^ (ys >> 3u)) & 0x1u) << 2u; + break; + case 16: + bank |= (((xs >> 3u) ^ (ys >> 6u)) & 0x1u) << 0u; + bank |= (((xs >> 4u) ^ (ys >> 5u) ^ (ys >> 6u)) & 0x1u) << 1u; + bank |= (((xs >> 5u) ^ (ys >> 4u)) & 0x1u) << 2u; + bank |= (((xs >> 6u) ^ (ys >> 3u)) & 0x1u) << 3u; + break; + default:; + } + + return bank; + } + + u64 GetTiledOffset(u32 x, u32 y, bool is_neo) const { + u64 element_index = GetElementIndex(x, y); + + u32 xh = x; + u32 yh = y; + u64 pipe = GetPipeIndex(xh, yh, is_neo); + u64 bank = GetBankIndex(xh, yh, 1, m_bank_height, m_num_banks, m_num_pipes); + u32 tile_bytes = (8 * 8 * 32 + 7) / 8; + u64 element_offset = (element_index * 32); + u64 tile_split_slice = 0; + + if (tile_bytes > 512) { + tile_split_slice = element_offset / (static_cast(512) * 8); + element_offset %= (static_cast(512) * 8); + tile_bytes = 512; + } + + u64 macro_tile_bytes = (128 / 8) * (m_macro_tile_height / 8) * tile_bytes / (m_num_pipes * m_num_banks); + u64 macro_tiles_per_row = m_padded_width / 128; + u64 macro_tile_row_index = y / m_macro_tile_height; + u64 macro_tile_column_index = x / 128; + u64 macro_tile_index = (macro_tile_row_index * macro_tiles_per_row) + macro_tile_column_index; + u64 macro_tile_offset = macro_tile_index * macro_tile_bytes; + u64 macro_tiles_per_slice = macro_tiles_per_row * (m_padded_height / m_macro_tile_height); + u64 slice_bytes = macro_tiles_per_slice * macro_tile_bytes; + u64 slice_offset = tile_split_slice * slice_bytes; + u64 tile_row_index = (y / 8) % m_bank_height; + u64 tile_index = tile_row_index; + u64 tile_offset = tile_index * tile_bytes; + + u64 tile_split_slice_rotation = ((m_num_banks / 2) + 1) * tile_split_slice; + bank ^= tile_split_slice_rotation; + bank &= (m_num_banks - 1); + + u64 total_offset = (slice_offset + macro_tile_offset + tile_offset) * 8 + element_offset; + u64 bit_offset = total_offset & 0x7u; + total_offset /= 8; + + u64 pipe_interleave_offset = total_offset & 0xffu; + u64 offset = total_offset >> 8u; + u64 byte_offset = pipe_interleave_offset | (pipe << (8u)) | (bank << (8u + m_pipe_bits)) | (offset << (8u + m_pipe_bits + m_bank_bits)); + + return ((byte_offset << 3u) | bit_offset) / 8; + } +}; + +void ConvertTileToLinear(u08* dst, const u08* src,u32 width, u32 height, bool is_neo) { + const TileManager32 t{width, height, is_neo}; + for (u32 y = 0; y < height; y++) { + u32 x = 0; + u64 linear_offset = y * width * 4; + + for (; x + 1 < width; x += 2) { + auto tiled_offset = t.GetTiledOffset(x, y, is_neo); + std::memcpy(dst + linear_offset, src + tiled_offset, sizeof(u64)); + linear_offset += sizeof(u64); + } + if (x < width) { + auto tiled_offset = t.GetTiledOffset(x, y, is_neo); + std::memcpy(dst + linear_offset, src + tiled_offset, sizeof(u32)); + } + } +} + +} // namespace VideoCore diff --git a/src/video_core/tile_manager.h b/src/video_core/tile_manager.h new file mode 100644 index 000000000..b58b99c9f --- /dev/null +++ b/src/video_core/tile_manager.h @@ -0,0 +1,9 @@ +#pragma once + +#include "common/types.h" + +namespace VideoCore { + +void ConvertTileToLinear(void* dst, const void* src, u32 width, u32 height, bool neo); + +} // namespace VideoCore diff --git a/third-party/CMakeLists.txt b/third-party/CMakeLists.txt index 0e04aae49..d9bbe6973 100644 --- a/third-party/CMakeLists.txt +++ b/third-party/CMakeLists.txt @@ -30,7 +30,6 @@ add_subdirectory(toml11 EXCLUDE_FROM_ALL) # Vulkan add_subdirectory(vulkan EXCLUDE_FROM_ALL) -target_include_directories(vulkan-1 INTERFACE vulkan/include) # Winpthreads if (WIN32) @@ -66,6 +65,6 @@ target_include_directories(imgui PUBLIC imgui/include ) -target_link_libraries(imgui PRIVATE SDL3-shared ${CMAKE_DL_LIBS} Zydis winpthread discord-rpc) +target_link_libraries(imgui PRIVATE SDL3-shared ${CMAKE_DL_LIBS} Zydis discord-rpc) diff --git a/third-party/fmt b/third-party/fmt index 661b23ede..8e42eef49 160000 --- a/third-party/fmt +++ b/third-party/fmt @@ -1 +1 @@ -Subproject commit 661b23edeb52d400cf5812e7330f14f05c072fab +Subproject commit 8e42eef4950feb5d2b76574a9cd2591dfaae2449 diff --git a/third-party/spdlog b/third-party/spdlog index 76dfc7e7c..134f9194b 160000 --- a/third-party/spdlog +++ b/third-party/spdlog @@ -1 +1 @@ -Subproject commit 76dfc7e7c0d3c69d3cdaa3399b63545235ccbb02 +Subproject commit 134f9194bb93072b72b8cfa27ac3bb30a0fb5b57 diff --git a/third-party/vulkan b/third-party/vulkan index 8c9feb4f4..72b2e7407 160000 --- a/third-party/vulkan +++ b/third-party/vulkan @@ -1 +1 @@ -Subproject commit 8c9feb4f480b32f7c7421af546aa6ffb558bdd5e +Subproject commit 72b2e740754bc6b86b724fa5b2c90dca6f69462e From b62c44c9147c20f40bb95ee83c79887513ae7e56 Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 23 Feb 2024 14:10:44 +0200 Subject: [PATCH 2/3] ugly workaround :D --- CMakeLists.txt | 2 +- lib/clang_rt.builtins-x86_64.lib | Bin 0 -> 174020 bytes 2 files changed, 1 insertion(+), 1 deletion(-) create mode 100644 lib/clang_rt.builtins-x86_64.lib diff --git a/CMakeLists.txt b/CMakeLists.txt index c3b2dca36..c6ca6d4bc 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,7 +155,7 @@ create_target_directory_groups(shadps4) target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt spdlog::spdlog toml11::toml11) target_link_libraries(shadps4 PRIVATE discord-rpc imgui SDL3-shared vulkan-1 xxhash Zydis) if (WIN32) - target_link_libraries(shadps4 PRIVATE mincore winpthread) + target_link_libraries(shadps4 PRIVATE mincore winpthread ${PROJECT_SOURCE_DIR}/lib/clang_rt.builtins-x86_64.lib) endif() add_custom_command(TARGET shadps4 POST_BUILD diff --git a/lib/clang_rt.builtins-x86_64.lib b/lib/clang_rt.builtins-x86_64.lib new file mode 100644 index 0000000000000000000000000000000000000000..a04d968d627a8d995fdc697975e86b6fe7bc15bd GIT binary patch literal 174020 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 literal 0 HcmV?d00001 From 552d2da17a7df2a046799b7a52c231dd3853488a Mon Sep 17 00:00:00 2001 From: georgemoralis Date: Fri, 23 Feb 2024 14:33:01 +0200 Subject: [PATCH 3/3] should work without lib --- CMakeLists.txt | 2 +- lib/clang_rt.builtins-x86_64.lib | Bin 174020 -> 0 bytes 2 files changed, 1 insertion(+), 1 deletion(-) delete mode 100644 lib/clang_rt.builtins-x86_64.lib diff --git a/CMakeLists.txt b/CMakeLists.txt index c6ca6d4bc..9f1488340 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -155,7 +155,7 @@ create_target_directory_groups(shadps4) target_link_libraries(shadps4 PRIVATE magic_enum::magic_enum fmt::fmt spdlog::spdlog toml11::toml11) target_link_libraries(shadps4 PRIVATE discord-rpc imgui SDL3-shared vulkan-1 xxhash Zydis) if (WIN32) - target_link_libraries(shadps4 PRIVATE mincore winpthread ${PROJECT_SOURCE_DIR}/lib/clang_rt.builtins-x86_64.lib) + target_link_libraries(shadps4 PRIVATE mincore winpthread clang_rt.builtins-x86_64.lib) endif() add_custom_command(TARGET shadps4 POST_BUILD diff --git a/lib/clang_rt.builtins-x86_64.lib b/lib/clang_rt.builtins-x86_64.lib deleted file mode 100644 index a04d968d627a8d995fdc697975e86b6fe7bc15bd..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 174020 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