diff options
Diffstat (limited to '')
72 files changed, 1037 insertions, 2656 deletions
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index 61adbef28..478246b6f 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -67,8 +67,11 @@ else() -Werror=implicit-fallthrough -Werror=missing-declarations -Werror=reorder + -Werror=switch -Werror=uninitialized + -Werror=unused-function -Werror=unused-result + -Werror=unused-variable -Wextra -Wmissing-declarations -Wno-attributes @@ -127,7 +130,6 @@ add_subdirectory(tests) if (ENABLE_SDL2) add_subdirectory(yuzu_cmd) - add_subdirectory(yuzu_tester) endif() if (ENABLE_QT) diff --git a/src/audio_core/sink_context.h b/src/audio_core/sink_context.h index 05541becb..66ee4e8a0 100644 --- a/src/audio_core/sink_context.h +++ b/src/audio_core/sink_context.h @@ -40,17 +40,17 @@ public: SinkSampleFormat sample_format; std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input; bool in_use; - INSERT_UNION_PADDING_BYTES(5); + INSERT_PADDING_BYTES_NOINIT(5); }; static_assert(sizeof(CircularBufferIn) == 0x28, "SinkInfo::CircularBufferIn is in invalid size"); struct DeviceIn { std::array<u8, 255> device_name; - INSERT_UNION_PADDING_BYTES(1); + INSERT_PADDING_BYTES_NOINIT(1); s32_le input_count; std::array<u8, AudioCommon::MAX_CHANNEL_COUNT> input; - INSERT_UNION_PADDING_BYTES(1); + INSERT_PADDING_BYTES_NOINIT(1); bool down_matrix_enabled; DownmixCoefficients down_matrix_coef; }; diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 5d781cd77..9824c5564 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt @@ -108,7 +108,6 @@ add_library(common STATIC bit_util.h cityhash.cpp cityhash.h - color.h common_funcs.h common_paths.h common_types.h @@ -167,8 +166,6 @@ add_library(common STATIC threadsafe_queue.h time_zone.cpp time_zone.h - timer.cpp - timer.h tree.h uint128.cpp uint128.h diff --git a/src/common/alignment.h b/src/common/alignment.h index 5040043de..fb81f10d8 100644 --- a/src/common/alignment.h +++ b/src/common/alignment.h @@ -9,50 +9,45 @@ namespace Common { template <typename T> -[[nodiscard]] constexpr T AlignUp(T value, std::size_t size) { - static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); +requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignUp(T value, size_t size) { auto mod{static_cast<T>(value % size)}; value -= mod; return static_cast<T>(mod == T{0} ? value : value + size); } template <typename T> -[[nodiscard]] constexpr T AlignDown(T value, std::size_t size) { - static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); - return static_cast<T>(value - value % size); +requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignUpLog2(T value, size_t align_log2) { + return static_cast<T>((value + ((1ULL << align_log2) - 1)) >> align_log2 << align_log2); } template <typename T> -[[nodiscard]] constexpr T AlignBits(T value, std::size_t align) { - static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); - return static_cast<T>((value + ((1ULL << align) - 1)) >> align << align); +requires std::is_unsigned_v<T>[[nodiscard]] constexpr T AlignDown(T value, size_t size) { + return static_cast<T>(value - value % size); } template <typename T> -[[nodiscard]] constexpr bool Is4KBAligned(T value) { - static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); +requires std::is_unsigned_v<T>[[nodiscard]] constexpr bool Is4KBAligned(T value) { return (value & 0xFFF) == 0; } template <typename T> -[[nodiscard]] constexpr bool IsWordAligned(T value) { - static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); +requires std::is_unsigned_v<T>[[nodiscard]] constexpr bool IsWordAligned(T value) { return (value & 0b11) == 0; } template <typename T> -[[nodiscard]] constexpr bool IsAligned(T value, std::size_t alignment) { - using U = typename std::make_unsigned<T>::type; +requires std::is_integral_v<T>[[nodiscard]] constexpr bool IsAligned(T value, size_t alignment) { + using U = typename std::make_unsigned_t<T>; const U mask = static_cast<U>(alignment - 1); return (value & mask) == 0; } -template <typename T, std::size_t Align = 16> +template <typename T, size_t Align = 16> class AlignmentAllocator { public: using value_type = T; - using size_type = std::size_t; - using difference_type = std::ptrdiff_t; + using size_type = size_t; + using difference_type = ptrdiff_t; using propagate_on_container_copy_assignment = std::true_type; using propagate_on_container_move_assignment = std::true_type; diff --git a/src/common/bit_util.h b/src/common/bit_util.h index 29f59a9a3..685e7fc9b 100644 --- a/src/common/bit_util.h +++ b/src/common/bit_util.h @@ -22,82 +22,6 @@ template <typename T> } #ifdef _MSC_VER -[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) { - unsigned long leading_zero = 0; - - if (_BitScanReverse(&leading_zero, value) != 0) { - return 31 - leading_zero; - } - - return 32; -} - -[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) { - unsigned long leading_zero = 0; - - if (_BitScanReverse64(&leading_zero, value) != 0) { - return 63 - leading_zero; - } - - return 64; -} -#else -[[nodiscard]] inline u32 CountLeadingZeroes32(u32 value) { - if (value == 0) { - return 32; - } - - return static_cast<u32>(__builtin_clz(value)); -} - -[[nodiscard]] inline u32 CountLeadingZeroes64(u64 value) { - if (value == 0) { - return 64; - } - - return static_cast<u32>(__builtin_clzll(value)); -} -#endif - -#ifdef _MSC_VER -[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) { - unsigned long trailing_zero = 0; - - if (_BitScanForward(&trailing_zero, value) != 0) { - return trailing_zero; - } - - return 32; -} - -[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) { - unsigned long trailing_zero = 0; - - if (_BitScanForward64(&trailing_zero, value) != 0) { - return trailing_zero; - } - - return 64; -} -#else -[[nodiscard]] inline u32 CountTrailingZeroes32(u32 value) { - if (value == 0) { - return 32; - } - - return static_cast<u32>(__builtin_ctz(value)); -} - -[[nodiscard]] inline u32 CountTrailingZeroes64(u64 value) { - if (value == 0) { - return 64; - } - - return static_cast<u32>(__builtin_ctzll(value)); -} -#endif - -#ifdef _MSC_VER [[nodiscard]] inline u32 MostSignificantBit32(const u32 value) { unsigned long result; diff --git a/src/common/color.h b/src/common/color.h deleted file mode 100644 index bbcac858e..000000000 --- a/src/common/color.h +++ /dev/null @@ -1,271 +0,0 @@ -// Copyright 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <cstring> - -#include "common/common_types.h" -#include "common/swap.h" -#include "common/vector_math.h" - -namespace Common::Color { - -/// Convert a 1-bit color component to 8 bit -[[nodiscard]] constexpr u8 Convert1To8(u8 value) { - return value * 255; -} - -/// Convert a 4-bit color component to 8 bit -[[nodiscard]] constexpr u8 Convert4To8(u8 value) { - return (value << 4) | value; -} - -/// Convert a 5-bit color component to 8 bit -[[nodiscard]] constexpr u8 Convert5To8(u8 value) { - return (value << 3) | (value >> 2); -} - -/// Convert a 6-bit color component to 8 bit -[[nodiscard]] constexpr u8 Convert6To8(u8 value) { - return (value << 2) | (value >> 4); -} - -/// Convert a 8-bit color component to 1 bit -[[nodiscard]] constexpr u8 Convert8To1(u8 value) { - return value >> 7; -} - -/// Convert a 8-bit color component to 4 bit -[[nodiscard]] constexpr u8 Convert8To4(u8 value) { - return value >> 4; -} - -/// Convert a 8-bit color component to 5 bit -[[nodiscard]] constexpr u8 Convert8To5(u8 value) { - return value >> 3; -} - -/// Convert a 8-bit color component to 6 bit -[[nodiscard]] constexpr u8 Convert8To6(u8 value) { - return value >> 2; -} - -/** - * Decode a color stored in RGBA8 format - * @param bytes Pointer to encoded source color - * @return Result color decoded as Common::Vec4<u8> - */ -[[nodiscard]] inline Common::Vec4<u8> DecodeRGBA8(const u8* bytes) { - return {bytes[3], bytes[2], bytes[1], bytes[0]}; -} - -/** - * Decode a color stored in RGB8 format - * @param bytes Pointer to encoded source color - * @return Result color decoded as Common::Vec4<u8> - */ -[[nodiscard]] inline Common::Vec4<u8> DecodeRGB8(const u8* bytes) { - return {bytes[2], bytes[1], bytes[0], 255}; -} - -/** - * Decode a color stored in RG8 (aka HILO8) format - * @param bytes Pointer to encoded source color - * @return Result color decoded as Common::Vec4<u8> - */ -[[nodiscard]] inline Common::Vec4<u8> DecodeRG8(const u8* bytes) { - return {bytes[1], bytes[0], 0, 255}; -} - -/** - * Decode a color stored in RGB565 format - * @param bytes Pointer to encoded source color - * @return Result color decoded as Common::Vec4<u8> - */ -[[nodiscard]] inline Common::Vec4<u8> DecodeRGB565(const u8* bytes) { - u16_le pixel; - std::memcpy(&pixel, bytes, sizeof(pixel)); - return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F), - Convert5To8(pixel & 0x1F), 255}; -} - -/** - * Decode a color stored in RGB5A1 format - * @param bytes Pointer to encoded source color - * @return Result color decoded as Common::Vec4<u8> - */ -[[nodiscard]] inline Common::Vec4<u8> DecodeRGB5A1(const u8* bytes) { - u16_le pixel; - std::memcpy(&pixel, bytes, sizeof(pixel)); - return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F), - Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1)}; -} - -/** - * Decode a color stored in RGBA4 format - * @param bytes Pointer to encoded source color - * @return Result color decoded as Common::Vec4<u8> - */ -[[nodiscard]] inline Common::Vec4<u8> DecodeRGBA4(const u8* bytes) { - u16_le pixel; - std::memcpy(&pixel, bytes, sizeof(pixel)); - return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF), - Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF)}; -} - -/** - * Decode a depth value stored in D16 format - * @param bytes Pointer to encoded source value - * @return Depth value as an u32 - */ -[[nodiscard]] inline u32 DecodeD16(const u8* bytes) { - u16_le data; - std::memcpy(&data, bytes, sizeof(data)); - return data; -} - -/** - * Decode a depth value stored in D24 format - * @param bytes Pointer to encoded source value - * @return Depth value as an u32 - */ -[[nodiscard]] inline u32 DecodeD24(const u8* bytes) { - return (bytes[2] << 16) | (bytes[1] << 8) | bytes[0]; -} - -/** - * Decode a depth value and a stencil value stored in D24S8 format - * @param bytes Pointer to encoded source values - * @return Resulting values stored as a Common::Vec2 - */ -[[nodiscard]] inline Common::Vec2<u32> DecodeD24S8(const u8* bytes) { - return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]}; -} - -/** - * Encode a color as RGBA8 format - * @param color Source color to encode - * @param bytes Destination pointer to store encoded color - */ -inline void EncodeRGBA8(const Common::Vec4<u8>& color, u8* bytes) { - bytes[3] = color.r(); - bytes[2] = color.g(); - bytes[1] = color.b(); - bytes[0] = color.a(); -} - -/** - * Encode a color as RGB8 format - * @param color Source color to encode - * @param bytes Destination pointer to store encoded color - */ -inline void EncodeRGB8(const Common::Vec4<u8>& color, u8* bytes) { - bytes[2] = color.r(); - bytes[1] = color.g(); - bytes[0] = color.b(); -} - -/** - * Encode a color as RG8 (aka HILO8) format - * @param color Source color to encode - * @param bytes Destination pointer to store encoded color - */ -inline void EncodeRG8(const Common::Vec4<u8>& color, u8* bytes) { - bytes[1] = color.r(); - bytes[0] = color.g(); -} -/** - * Encode a color as RGB565 format - * @param color Source color to encode - * @param bytes Destination pointer to store encoded color - */ -inline void EncodeRGB565(const Common::Vec4<u8>& color, u8* bytes) { - const u16_le data = - (Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b()); - - std::memcpy(bytes, &data, sizeof(data)); -} - -/** - * Encode a color as RGB5A1 format - * @param color Source color to encode - * @param bytes Destination pointer to store encoded color - */ -inline void EncodeRGB5A1(const Common::Vec4<u8>& color, u8* bytes) { - const u16_le data = (Convert8To5(color.r()) << 11) | (Convert8To5(color.g()) << 6) | - (Convert8To5(color.b()) << 1) | Convert8To1(color.a()); - - std::memcpy(bytes, &data, sizeof(data)); -} - -/** - * Encode a color as RGBA4 format - * @param color Source color to encode - * @param bytes Destination pointer to store encoded color - */ -inline void EncodeRGBA4(const Common::Vec4<u8>& color, u8* bytes) { - const u16 data = (Convert8To4(color.r()) << 12) | (Convert8To4(color.g()) << 8) | - (Convert8To4(color.b()) << 4) | Convert8To4(color.a()); - - std::memcpy(bytes, &data, sizeof(data)); -} - -/** - * Encode a 16 bit depth value as D16 format - * @param value 16 bit source depth value to encode - * @param bytes Pointer where to store the encoded value - */ -inline void EncodeD16(u32 value, u8* bytes) { - const u16_le data = static_cast<u16>(value); - std::memcpy(bytes, &data, sizeof(data)); -} - -/** - * Encode a 24 bit depth value as D24 format - * @param value 24 bit source depth value to encode - * @param bytes Pointer where to store the encoded value - */ -inline void EncodeD24(u32 value, u8* bytes) { - bytes[0] = value & 0xFF; - bytes[1] = (value >> 8) & 0xFF; - bytes[2] = (value >> 16) & 0xFF; -} - -/** - * Encode a 24 bit depth and 8 bit stencil values as D24S8 format - * @param depth 24 bit source depth value to encode - * @param stencil 8 bit source stencil value to encode - * @param bytes Pointer where to store the encoded value - */ -inline void EncodeD24S8(u32 depth, u8 stencil, u8* bytes) { - bytes[0] = depth & 0xFF; - bytes[1] = (depth >> 8) & 0xFF; - bytes[2] = (depth >> 16) & 0xFF; - bytes[3] = stencil; -} - -/** - * Encode a 24 bit depth value as D24X8 format (32 bits per pixel with 8 bits unused) - * @param depth 24 bit source depth value to encode - * @param bytes Pointer where to store the encoded value - * @note unused bits will not be modified - */ -inline void EncodeD24X8(u32 depth, u8* bytes) { - bytes[0] = depth & 0xFF; - bytes[1] = (depth >> 8) & 0xFF; - bytes[2] = (depth >> 16) & 0xFF; -} - -/** - * Encode an 8 bit stencil value as X24S8 format (32 bits per pixel with 24 bits unused) - * @param stencil 8 bit source stencil value to encode - * @param bytes Pointer where to store the encoded value - * @note unused bits will not be modified - */ -inline void EncodeX24S8(u8 stencil, u8* bytes) { - bytes[3] = stencil; -} - -} // namespace Common::Color diff --git a/src/common/common_funcs.h b/src/common/common_funcs.h index c90978f9c..75f3027fb 100644 --- a/src/common/common_funcs.h +++ b/src/common/common_funcs.h @@ -24,10 +24,10 @@ #define INSERT_PADDING_WORDS(num_words) \ std::array<u32, num_words> CONCAT2(pad, __LINE__) {} -/// These are similar to the INSERT_PADDING_* macros, but are needed for padding unions. This is -/// because unions can only be initialized by one member. -#define INSERT_UNION_PADDING_BYTES(num_bytes) std::array<u8, num_bytes> CONCAT2(pad, __LINE__) -#define INSERT_UNION_PADDING_WORDS(num_words) std::array<u32, num_words> CONCAT2(pad, __LINE__) +/// These are similar to the INSERT_PADDING_* macros but do not zero-initialize the contents. +/// This keeps the structure trivial to construct. +#define INSERT_PADDING_BYTES_NOINIT(num_bytes) std::array<u8, num_bytes> CONCAT2(pad, __LINE__) +#define INSERT_PADDING_WORDS_NOINIT(num_words) std::array<u32, num_words> CONCAT2(pad, __LINE__) #ifndef _MSC_VER diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 631f64d05..2d4d2e9e7 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp @@ -145,10 +145,18 @@ void ColorConsoleBackend::Write(const Entry& entry) { PrintColoredMessage(entry); } -// _SH_DENYWR allows read only access to the file for other programs. -// It is #defined to 0 on other platforms -FileBackend::FileBackend(const std::string& filename) - : file(filename, "w", _SH_DENYWR), bytes_written(0) {} +FileBackend::FileBackend(const std::string& filename) : bytes_written(0) { + if (Common::FS::Exists(filename + ".old.txt")) { + Common::FS::Delete(filename + ".old.txt"); + } + if (Common::FS::Exists(filename)) { + Common::FS::Rename(filename, filename + ".old.txt"); + } + + // _SH_DENYWR allows read only access to the file for other programs. + // It is #defined to 0 on other platforms + file = Common::FS::IOFile(filename, "w", _SH_DENYWR); +} void FileBackend::Write(const Entry& entry) { // prevent logs from going over the maximum size (in case its spamming and the user doesn't diff --git a/src/common/timer.cpp b/src/common/timer.cpp deleted file mode 100644 index d17dc2a50..000000000 --- a/src/common/timer.cpp +++ /dev/null @@ -1,159 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <ctime> -#include <fmt/format.h> -#include "common/common_types.h" -#include "common/string_util.h" -#include "common/timer.h" - -namespace Common { - -std::chrono::milliseconds Timer::GetTimeMs() { - return std::chrono::duration_cast<std::chrono::milliseconds>( - std::chrono::system_clock::now().time_since_epoch()); -} - -// -------------------------------------------- -// Initiate, Start, Stop, and Update the time -// -------------------------------------------- - -// Set initial values for the class -Timer::Timer() : m_LastTime(0), m_StartTime(0), m_Running(false) { - Update(); -} - -// Write the starting time -void Timer::Start() { - m_StartTime = GetTimeMs(); - m_Running = true; -} - -// Stop the timer -void Timer::Stop() { - // Write the final time - m_LastTime = GetTimeMs(); - m_Running = false; -} - -// Update the last time variable -void Timer::Update() { - m_LastTime = GetTimeMs(); - // TODO(ector) - QPF -} - -// ------------------------------------- -// Get time difference and elapsed time -// ------------------------------------- - -// Get the number of milliseconds since the last Update() -std::chrono::milliseconds Timer::GetTimeDifference() { - return GetTimeMs() - m_LastTime; -} - -// Add the time difference since the last Update() to the starting time. -// This is used to compensate for a paused game. -void Timer::AddTimeDifference() { - m_StartTime += GetTimeDifference(); -} - -// Get the time elapsed since the Start() -std::chrono::milliseconds Timer::GetTimeElapsed() { - // If we have not started yet, return 1 (because then I don't - // have to change the FPS calculation in CoreRerecording.cpp . - if (m_StartTime.count() == 0) - return std::chrono::milliseconds(1); - - // Return the final timer time if the timer is stopped - if (!m_Running) - return (m_LastTime - m_StartTime); - - return (GetTimeMs() - m_StartTime); -} - -// Get the formatted time elapsed since the Start() -std::string Timer::GetTimeElapsedFormatted() const { - // If we have not started yet, return zero - if (m_StartTime.count() == 0) - return "00:00:00:000"; - - // The number of milliseconds since the start. - // Use a different value if the timer is stopped. - std::chrono::milliseconds Milliseconds; - if (m_Running) - Milliseconds = GetTimeMs() - m_StartTime; - else - Milliseconds = m_LastTime - m_StartTime; - // Seconds - std::chrono::seconds Seconds = std::chrono::duration_cast<std::chrono::seconds>(Milliseconds); - // Minutes - std::chrono::minutes Minutes = std::chrono::duration_cast<std::chrono::minutes>(Milliseconds); - // Hours - std::chrono::hours Hours = std::chrono::duration_cast<std::chrono::hours>(Milliseconds); - - std::string TmpStr = fmt::format("{:02}:{:02}:{:02}:{:03}", Hours.count(), Minutes.count() % 60, - Seconds.count() % 60, Milliseconds.count() % 1000); - return TmpStr; -} - -// Get the number of seconds since January 1 1970 -std::chrono::seconds Timer::GetTimeSinceJan1970() { - return std::chrono::duration_cast<std::chrono::seconds>(GetTimeMs()); -} - -std::chrono::seconds Timer::GetLocalTimeSinceJan1970() { - time_t sysTime, tzDiff, tzDST; - struct tm* gmTime; - - time(&sysTime); - - // Account for DST where needed - gmTime = localtime(&sysTime); - if (gmTime->tm_isdst == 1) - tzDST = 3600; - else - tzDST = 0; - - // Lazy way to get local time in sec - gmTime = gmtime(&sysTime); - tzDiff = sysTime - mktime(gmTime); - - return std::chrono::seconds(sysTime + tzDiff + tzDST); -} - -// Return the current time formatted as Minutes:Seconds:Milliseconds -// in the form 00:00:000. -std::string Timer::GetTimeFormatted() { - time_t sysTime; - struct tm* gmTime; - char tmp[13]; - - time(&sysTime); - gmTime = localtime(&sysTime); - - strftime(tmp, 6, "%M:%S", gmTime); - - u64 milliseconds = static_cast<u64>(GetTimeMs().count()) % 1000; - return fmt::format("{}:{:03}", tmp, milliseconds); -} - -// Returns a timestamp with decimals for precise time comparisons -// ---------------- -double Timer::GetDoubleTime() { - // Get continuous timestamp - auto tmp_seconds = static_cast<u64>(GetTimeSinceJan1970().count()); - const auto ms = static_cast<double>(static_cast<u64>(GetTimeMs().count()) % 1000); - - // Remove a few years. We only really want enough seconds to make - // sure that we are detecting actual actions, perhaps 60 seconds is - // enough really, but I leave a year of seconds anyway, in case the - // user's clock is incorrect or something like that. - tmp_seconds = tmp_seconds - (38 * 365 * 24 * 60 * 60); - - // Make a smaller integer that fits in the double - const auto seconds = static_cast<u32>(tmp_seconds); - return seconds + ms; -} - -} // Namespace Common diff --git a/src/common/timer.h b/src/common/timer.h deleted file mode 100644 index 8894a143d..000000000 --- a/src/common/timer.h +++ /dev/null @@ -1,41 +0,0 @@ -// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <chrono> -#include <string> -#include "common/common_types.h" - -namespace Common { -class Timer { -public: - Timer(); - - void Start(); - void Stop(); - void Update(); - - // The time difference is always returned in milliseconds, regardless of alternative internal - // representation - [[nodiscard]] std::chrono::milliseconds GetTimeDifference(); - void AddTimeDifference(); - - [[nodiscard]] static std::chrono::seconds GetTimeSinceJan1970(); - [[nodiscard]] static std::chrono::seconds GetLocalTimeSinceJan1970(); - [[nodiscard]] static double GetDoubleTime(); - - [[nodiscard]] static std::string GetTimeFormatted(); - [[nodiscard]] std::string GetTimeElapsedFormatted() const; - [[nodiscard]] std::chrono::milliseconds GetTimeElapsed(); - - [[nodiscard]] static std::chrono::milliseconds GetTimeMs(); - -private: - std::chrono::milliseconds m_LastTime; - std::chrono::milliseconds m_StartTime; - bool m_Running; -}; - -} // Namespace Common diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index 1b8ad476e..99310dc50 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt @@ -643,9 +643,7 @@ else() -Werror=conversion -Werror=ignored-qualifiers -Werror=implicit-fallthrough - -Werror=reorder -Werror=sign-compare - -Werror=unused-variable $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-variable> diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index a6c0337fa..d12218fc2 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp @@ -43,17 +43,17 @@ static_assert(sizeof(IVFCLevel) == 0x18, "IVFCLevel has incorrect size."); struct IVFCHeader { u32_le magic; u32_le magic_number; - INSERT_UNION_PADDING_BYTES(8); + INSERT_PADDING_BYTES_NOINIT(8); std::array<IVFCLevel, 6> levels; - INSERT_UNION_PADDING_BYTES(64); + INSERT_PADDING_BYTES_NOINIT(64); }; static_assert(sizeof(IVFCHeader) == 0xE0, "IVFCHeader has incorrect size."); struct NCASectionHeaderBlock { - INSERT_UNION_PADDING_BYTES(3); + INSERT_PADDING_BYTES_NOINIT(3); NCASectionFilesystemType filesystem_type; NCASectionCryptoType crypto_type; - INSERT_UNION_PADDING_BYTES(3); + INSERT_PADDING_BYTES_NOINIT(3); }; static_assert(sizeof(NCASectionHeaderBlock) == 0x8, "NCASectionHeaderBlock has incorrect size."); @@ -61,7 +61,7 @@ struct NCASectionRaw { NCASectionHeaderBlock header; std::array<u8, 0x138> block_data; std::array<u8, 0x8> section_ctr; - INSERT_UNION_PADDING_BYTES(0xB8); + INSERT_PADDING_BYTES_NOINIT(0xB8); }; static_assert(sizeof(NCASectionRaw) == 0x200, "NCASectionRaw has incorrect size."); @@ -69,19 +69,19 @@ struct PFS0Superblock { NCASectionHeaderBlock header_block; std::array<u8, 0x20> hash; u32_le size; - INSERT_UNION_PADDING_BYTES(4); + INSERT_PADDING_BYTES_NOINIT(4); u64_le hash_table_offset; u64_le hash_table_size; u64_le pfs0_header_offset; u64_le pfs0_size; - INSERT_UNION_PADDING_BYTES(0x1B0); + INSERT_PADDING_BYTES_NOINIT(0x1B0); }; static_assert(sizeof(PFS0Superblock) == 0x200, "PFS0Superblock has incorrect size."); struct RomFSSuperblock { NCASectionHeaderBlock header_block; IVFCHeader ivfc; - INSERT_UNION_PADDING_BYTES(0x118); + INSERT_PADDING_BYTES_NOINIT(0x118); }; static_assert(sizeof(RomFSSuperblock) == 0x200, "RomFSSuperblock has incorrect size."); @@ -89,19 +89,19 @@ struct BKTRHeader { u64_le offset; u64_le size; u32_le magic; - INSERT_UNION_PADDING_BYTES(0x4); + INSERT_PADDING_BYTES_NOINIT(0x4); u32_le number_entries; - INSERT_UNION_PADDING_BYTES(0x4); + INSERT_PADDING_BYTES_NOINIT(0x4); }; static_assert(sizeof(BKTRHeader) == 0x20, "BKTRHeader has incorrect size."); struct BKTRSuperblock { NCASectionHeaderBlock header_block; IVFCHeader ivfc; - INSERT_UNION_PADDING_BYTES(0x18); + INSERT_PADDING_BYTES_NOINIT(0x18); BKTRHeader relocation; BKTRHeader subsection; - INSERT_UNION_PADDING_BYTES(0xC0); + INSERT_PADDING_BYTES_NOINIT(0xC0); }; static_assert(sizeof(BKTRSuperblock) == 0x200, "BKTRSuperblock has incorrect size."); diff --git a/src/core/hle/ipc.h b/src/core/hle/ipc.h index 7ce313190..79bcf5762 100644 --- a/src/core/hle/ipc.h +++ b/src/core/hle/ipc.h @@ -160,7 +160,7 @@ struct DomainMessageHeader { // Used when responding to an IPC request, Server -> Client. struct { u32_le num_objects; - INSERT_UNION_PADDING_WORDS(3); + INSERT_PADDING_WORDS_NOINIT(3); }; // Used when performing an IPC request, Client -> Server. @@ -171,7 +171,7 @@ struct DomainMessageHeader { BitField<16, 16, u32> size; }; u32_le object_id; - INSERT_UNION_PADDING_WORDS(2); + INSERT_PADDING_WORDS_NOINIT(2); }; std::array<u32, 4> raw{}; diff --git a/src/core/hle/kernel/k_priority_queue.h b/src/core/hle/kernel/k_priority_queue.h index 99fb8fe93..0dc929040 100644 --- a/src/core/hle/kernel/k_priority_queue.h +++ b/src/core/hle/kernel/k_priority_queue.h @@ -8,11 +8,11 @@ #pragma once #include <array> +#include <bit> #include <concepts> #include "common/assert.h" #include "common/bit_set.h" -#include "common/bit_util.h" #include "common/common_types.h" #include "common/concepts.h" @@ -268,7 +268,7 @@ private: } constexpr s32 GetNextCore(u64& affinity) { - const s32 core = Common::CountTrailingZeroes64(affinity); + const s32 core = std::countr_zero(affinity); ClearAffinityBit(affinity, core); return core; } diff --git a/src/core/hle/kernel/k_scheduler.cpp b/src/core/hle/kernel/k_scheduler.cpp index 42f0ea483..12b5619fb 100644 --- a/src/core/hle/kernel/k_scheduler.cpp +++ b/src/core/hle/kernel/k_scheduler.cpp @@ -5,6 +5,8 @@ // This file references various implementation details from Atmosphere, an open-source firmware for // the Nintendo Switch. Copyright 2018-2020 Atmosphere-NX. +#include <bit> + #include "common/assert.h" #include "common/bit_util.h" #include "common/fiber.h" @@ -31,12 +33,12 @@ static void IncrementScheduledCount(Kernel::Thread* thread) { void KScheduler::RescheduleCores(KernelCore& kernel, u64 cores_pending_reschedule, Core::EmuThreadHandle global_thread) { - u32 current_core = global_thread.host_handle; + const u32 current_core = global_thread.host_handle; bool must_context_switch = global_thread.guest_handle != InvalidHandle && (current_core < Core::Hardware::NUM_CPU_CORES); while (cores_pending_reschedule != 0) { - u32 core = Common::CountTrailingZeroes64(cores_pending_reschedule); + const auto core = static_cast<u32>(std::countr_zero(cores_pending_reschedule)); ASSERT(core < Core::Hardware::NUM_CPU_CORES); if (!must_context_switch || core != current_core) { auto& phys_core = kernel.PhysicalCore(core); @@ -109,7 +111,7 @@ u64 KScheduler::UpdateHighestPriorityThreadsImpl(KernelCore& kernel) { // Idle cores are bad. We're going to try to migrate threads to each idle core in turn. while (idle_cores != 0) { - u32 core_id = Common::CountTrailingZeroes64(idle_cores); + const auto core_id = static_cast<u32>(std::countr_zero(idle_cores)); if (Thread* suggested = priority_queue.GetSuggestedFront(core_id); suggested != nullptr) { s32 migration_candidates[Core::Hardware::NUM_CPU_CORES]; size_t num_candidates = 0; diff --git a/src/core/hle/kernel/memory/page_heap.h b/src/core/hle/kernel/memory/page_heap.h index 22b0de860..131093284 100644 --- a/src/core/hle/kernel/memory/page_heap.h +++ b/src/core/hle/kernel/memory/page_heap.h @@ -8,11 +8,11 @@ #pragma once #include <array> +#include <bit> #include <vector> #include "common/alignment.h" #include "common/assert.h" -#include "common/bit_util.h" #include "common/common_funcs.h" #include "common/common_types.h" #include "core/hle/kernel/memory/memory_types.h" @@ -105,7 +105,7 @@ private: ASSERT(depth == 0); return -1; } - offset = offset * 64 + Common::CountTrailingZeroes64(v); + offset = offset * 64 + static_cast<u32>(std::countr_zero(v)); ++depth; } while (depth < static_cast<s32>(used_depths)); diff --git a/src/core/hle/kernel/process_capability.cpp b/src/core/hle/kernel/process_capability.cpp index 0f128c586..0566311b6 100644 --- a/src/core/hle/kernel/process_capability.cpp +++ b/src/core/hle/kernel/process_capability.cpp @@ -2,6 +2,8 @@ // Licensed under GPLv2 or any later version // Refer to the license.txt file included. +#include <bit> + #include "common/bit_util.h" #include "common/logging/log.h" #include "core/hle/kernel/errors.h" @@ -60,7 +62,7 @@ constexpr CapabilityType GetCapabilityType(u32 value) { u32 GetFlagBitOffset(CapabilityType type) { const auto value = static_cast<u32>(type); - return static_cast<u32>(Common::BitSize<u32>() - Common::CountLeadingZeroes32(value)); + return static_cast<u32>(Common::BitSize<u32>() - static_cast<u32>(std::countl_zero(value))); } } // Anonymous namespace diff --git a/src/core/hle/service/am/applets/error.cpp b/src/core/hle/service/am/applets/error.cpp index d85505082..0c8b632e8 100644 --- a/src/core/hle/service/am/applets/error.cpp +++ b/src/core/hle/service/am/applets/error.cpp @@ -20,9 +20,9 @@ namespace Service::AM::Applets { struct ShowError { u8 mode; bool jump; - INSERT_UNION_PADDING_BYTES(4); + INSERT_PADDING_BYTES_NOINIT(4); bool use_64bit_error_code; - INSERT_UNION_PADDING_BYTES(1); + INSERT_PADDING_BYTES_NOINIT(1); u64 error_code_64; u32 error_code_32; }; @@ -32,7 +32,7 @@ static_assert(sizeof(ShowError) == 0x14, "ShowError has incorrect size."); struct ShowErrorRecord { u8 mode; bool jump; - INSERT_UNION_PADDING_BYTES(6); + INSERT_PADDING_BYTES_NOINIT(6); u64 error_code_64; u64 posix_time; }; @@ -41,7 +41,7 @@ static_assert(sizeof(ShowErrorRecord) == 0x18, "ShowErrorRecord has incorrect si struct SystemErrorArg { u8 mode; bool jump; - INSERT_UNION_PADDING_BYTES(6); + INSERT_PADDING_BYTES_NOINIT(6); u64 error_code_64; std::array<char, 8> language_code; std::array<char, 0x800> main_text; @@ -52,7 +52,7 @@ static_assert(sizeof(SystemErrorArg) == 0x1018, "SystemErrorArg has incorrect si struct ApplicationErrorArg { u8 mode; bool jump; - INSERT_UNION_PADDING_BYTES(6); + INSERT_PADDING_BYTES_NOINIT(6); u32 error_code; std::array<char, 8> language_code; std::array<char, 0x800> main_text; diff --git a/src/tests/CMakeLists.txt b/src/tests/CMakeLists.txt index 8a606b448..33fa89583 100644 --- a/src/tests/CMakeLists.txt +++ b/src/tests/CMakeLists.txt @@ -1,6 +1,5 @@ add_executable(tests common/bit_field.cpp - common/bit_utils.cpp common/fibers.cpp common/param_package.cpp common/ring_buffer.cpp diff --git a/src/tests/common/bit_utils.cpp b/src/tests/common/bit_utils.cpp deleted file mode 100644 index 479b5995a..000000000 --- a/src/tests/common/bit_utils.cpp +++ /dev/null @@ -1,23 +0,0 @@ -// Copyright 2017 Citra Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <catch2/catch.hpp> -#include <math.h> -#include "common/bit_util.h" - -namespace Common { - -TEST_CASE("BitUtils::CountTrailingZeroes", "[common]") { - REQUIRE(Common::CountTrailingZeroes32(0) == 32); - REQUIRE(Common::CountTrailingZeroes64(0) == 64); - REQUIRE(Common::CountTrailingZeroes32(9) == 0); - REQUIRE(Common::CountTrailingZeroes32(8) == 3); - REQUIRE(Common::CountTrailingZeroes32(0x801000) == 12); - REQUIRE(Common::CountTrailingZeroes64(9) == 0); - REQUIRE(Common::CountTrailingZeroes64(8) == 3); - REQUIRE(Common::CountTrailingZeroes64(0x801000) == 12); - REQUIRE(Common::CountTrailingZeroes64(0x801000000000UL) == 36); -} - -} // namespace Common diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index f7b9d7f86..7a20d3a79 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt @@ -135,8 +135,6 @@ add_library(video_core STATIC renderer_vulkan/vk_graphics_pipeline.h renderer_vulkan/vk_master_semaphore.cpp renderer_vulkan/vk_master_semaphore.h - renderer_vulkan/vk_memory_manager.cpp - renderer_vulkan/vk_memory_manager.h renderer_vulkan/vk_pipeline_cache.cpp renderer_vulkan/vk_pipeline_cache.h renderer_vulkan/vk_query_cache.cpp @@ -259,6 +257,8 @@ add_library(video_core STATIC vulkan_common/vulkan_instance.h vulkan_common/vulkan_library.cpp vulkan_common/vulkan_library.h + vulkan_common/vulkan_memory_allocator.cpp + vulkan_common/vulkan_memory_allocator.h vulkan_common/vulkan_surface.cpp vulkan_common/vulkan_surface.h vulkan_common/vulkan_wrapper.cpp @@ -312,9 +312,7 @@ else() -Werror=pessimizing-move -Werror=redundant-move -Werror=shadow - -Werror=switch -Werror=type-limits - -Werror=unused-variable $<$<CXX_COMPILER_ID:GNU>:-Werror=class-memaccess> $<$<CXX_COMPILER_ID:GNU>:-Werror=unused-but-set-parameter> diff --git a/src/video_core/cdma_pusher.cpp b/src/video_core/cdma_pusher.cpp index 94679d5d1..33b3c060b 100644 --- a/src/video_core/cdma_pusher.cpp +++ b/src/video_core/cdma_pusher.cpp @@ -18,10 +18,10 @@ // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. // +#include <bit> #include "command_classes/host1x.h" #include "command_classes/nvdec.h" #include "command_classes/vic.h" -#include "common/bit_util.h" #include "video_core/cdma_pusher.h" #include "video_core/command_classes/nvdec_common.h" #include "video_core/engines/maxwell_3d.h" @@ -56,7 +56,7 @@ void CDmaPusher::Step() { for (const u32 value : values) { if (mask != 0) { - const u32 lbs = Common::CountTrailingZeroes32(mask); + const auto lbs = static_cast<u32>(std::countr_zero(mask)); mask &= ~(1U << lbs); ExecuteCommand(static_cast<u32>(offset + lbs), value); continue; diff --git a/src/video_core/cdma_pusher.h b/src/video_core/cdma_pusher.h index 8ca70b6dd..e5f212c1a 100644 --- a/src/video_core/cdma_pusher.h +++ b/src/video_core/cdma_pusher.h @@ -126,7 +126,7 @@ private: s32 count{}; s32 offset{}; - s32 mask{}; + u32 mask{}; bool incrementing{}; // Queue of command lists to be processed diff --git a/src/video_core/command_classes/codecs/h264.cpp b/src/video_core/command_classes/codecs/h264.cpp index 65bbeac78..fea6aed98 100644 --- a/src/video_core/command_classes/codecs/h264.cpp +++ b/src/video_core/command_classes/codecs/h264.cpp @@ -19,7 +19,7 @@ // #include <array> -#include "common/bit_util.h" +#include <bit> #include "video_core/command_classes/codecs/h264.h" #include "video_core/gpu.h" #include "video_core/memory_manager.h" @@ -266,7 +266,7 @@ void H264BitWriter::WriteExpGolombCodedInt(s32 value) { } void H264BitWriter::WriteExpGolombCodedUInt(u32 value) { - const s32 size = 32 - Common::CountLeadingZeroes32(static_cast<s32>(value + 1)); + const s32 size = 32 - std::countl_zero(value + 1); WriteBits(1, size); value -= (1U << (size - 1)) - 1; diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index 81522988e..0de3280a2 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h @@ -171,30 +171,30 @@ public: static constexpr std::size_t NUM_REGS = 0x258; struct { u32 object; - INSERT_UNION_PADDING_WORDS(0x3F); + INSERT_PADDING_WORDS_NOINIT(0x3F); u32 no_operation; NotifyType notify; - INSERT_UNION_PADDING_WORDS(0x2); + INSERT_PADDING_WORDS_NOINIT(0x2); u32 wait_for_idle; - INSERT_UNION_PADDING_WORDS(0xB); + INSERT_PADDING_WORDS_NOINIT(0xB); u32 pm_trigger; - INSERT_UNION_PADDING_WORDS(0xF); + INSERT_PADDING_WORDS_NOINIT(0xF); u32 context_dma_notify; u32 dst_context_dma; u32 src_context_dma; u32 semaphore_context_dma; - INSERT_UNION_PADDING_WORDS(0x1C); + INSERT_PADDING_WORDS_NOINIT(0x1C); Surface dst; CpuIndexWrap pixels_from_cpu_index_wrap; u32 kind2d_check_enable; Surface src; SectorPromotion pixels_from_memory_sector_promotion; - INSERT_UNION_PADDING_WORDS(0x1); + INSERT_PADDING_WORDS_NOINIT(0x1); NumTpcs num_tpcs; u32 render_enable_addr_upper; u32 render_enable_addr_lower; RenderEnableMode render_enable_mode; - INSERT_UNION_PADDING_WORDS(0x4); + INSERT_PADDING_WORDS_NOINIT(0x4); u32 clip_x0; u32 clip_y0; u32 clip_width; @@ -212,7 +212,7 @@ public: BitField<8, 6, u32> y; } pattern_offset; BitField<0, 2, PatternSelect> pattern_select; - INSERT_UNION_PADDING_WORDS(0xC); + INSERT_PADDING_WORDS_NOINIT(0xC); struct { BitField<0, 3, MonochromePatternColorFormat> color_format; BitField<0, 1, MonochromePatternFormat> format; @@ -227,15 +227,15 @@ public: std::array<u32, 0x20> X1R5G5B5; std::array<u32, 0x10> Y8; } color_pattern; - INSERT_UNION_PADDING_WORDS(0x10); + INSERT_PADDING_WORDS_NOINIT(0x10); struct { u32 prim_mode; u32 prim_color_format; u32 prim_color; u32 line_tie_break_bits; - INSERT_UNION_PADDING_WORDS(0x14); + INSERT_PADDING_WORDS_NOINIT(0x14); u32 prim_point_xy; - INSERT_UNION_PADDING_WORDS(0x7); + INSERT_PADDING_WORDS_NOINIT(0x7); std::array<Point, 0x40> prim_point; } render_solid; struct { @@ -247,7 +247,7 @@ public: u32 color0; u32 color1; u32 mono_opacity; - INSERT_UNION_PADDING_WORDS(0x6); + INSERT_PADDING_WORDS_NOINIT(0x6); u32 src_width; u32 src_height; u32 dx_du_frac; @@ -260,9 +260,9 @@ public: u32 dst_y0_int; u32 data; } pixels_from_cpu; - INSERT_UNION_PADDING_WORDS(0x3); + INSERT_PADDING_WORDS_NOINIT(0x3); u32 big_endian_control; - INSERT_UNION_PADDING_WORDS(0x3); + INSERT_PADDING_WORDS_NOINIT(0x3); struct { BitField<0, 3, u32> block_shape; BitField<0, 5, u32> corral_size; @@ -271,7 +271,7 @@ public: BitField<0, 1, Origin> origin; BitField<4, 1, Filter> filter; } sample_mode; - INSERT_UNION_PADDING_WORDS(0x8); + INSERT_PADDING_WORDS_NOINIT(0x8); s32 dst_x0; s32 dst_y0; s32 dst_width; diff --git a/src/video_core/engines/kepler_compute.h b/src/video_core/engines/kepler_compute.h index 51a041202..9f0a7b76d 100644 --- a/src/video_core/engines/kepler_compute.h +++ b/src/video_core/engines/kepler_compute.h @@ -55,7 +55,7 @@ public: union { struct { - INSERT_UNION_PADDING_WORDS(0x60); + INSERT_PADDING_WORDS_NOINIT(0x60); Upload::Registers upload; @@ -67,7 +67,7 @@ public: u32 data_upload; - INSERT_UNION_PADDING_WORDS(0x3F); + INSERT_PADDING_WORDS_NOINIT(0x3F); struct { u32 address; @@ -76,11 +76,11 @@ public: } } launch_desc_loc; - INSERT_UNION_PADDING_WORDS(0x1); + INSERT_PADDING_WORDS_NOINIT(0x1); u32 launch; - INSERT_UNION_PADDING_WORDS(0x4A7); + INSERT_PADDING_WORDS_NOINIT(0x4A7); struct { u32 address_high; @@ -92,7 +92,7 @@ public: } } tsc; - INSERT_UNION_PADDING_WORDS(0x3); + INSERT_PADDING_WORDS_NOINIT(0x3); struct { u32 address_high; @@ -104,7 +104,7 @@ public: } } tic; - INSERT_UNION_PADDING_WORDS(0x22); + INSERT_PADDING_WORDS_NOINIT(0x22); struct { u32 address_high; @@ -115,11 +115,11 @@ public: } } code_loc; - INSERT_UNION_PADDING_WORDS(0x3FE); + INSERT_PADDING_WORDS_NOINIT(0x3FE); u32 tex_cb_index; - INSERT_UNION_PADDING_WORDS(0x374); + INSERT_PADDING_WORDS_NOINIT(0x374); }; std::array<u32, NUM_REGS> reg_array; }; diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h index 62483589e..19808a5c6 100644 --- a/src/video_core/engines/kepler_memory.h +++ b/src/video_core/engines/kepler_memory.h @@ -50,7 +50,7 @@ public: union { struct { - INSERT_UNION_PADDING_WORDS(0x60); + INSERT_PADDING_WORDS_NOINIT(0x60); Upload::Registers upload; @@ -62,7 +62,7 @@ public: u32 data; - INSERT_UNION_PADDING_WORDS(0x11); + INSERT_PADDING_WORDS_NOINIT(0x11); }; std::array<u32, NUM_REGS> reg_array; }; diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index bf9e07c9b..326b32228 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h @@ -536,7 +536,7 @@ public: Equation equation_a; Factor factor_source_a; Factor factor_dest_a; - INSERT_UNION_PADDING_WORDS(1); + INSERT_PADDING_WORDS_NOINIT(1); }; enum class TessellationPrimitive : u32 { @@ -608,7 +608,7 @@ public: }; u32 layer_stride; u32 base_layer; - INSERT_UNION_PADDING_WORDS(7); + INSERT_PADDING_WORDS_NOINIT(7); GPUVAddr Address() const { return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | @@ -640,7 +640,7 @@ public: BitField<8, 3, ViewportSwizzle> z; BitField<12, 3, ViewportSwizzle> w; } swizzle; - INSERT_UNION_PADDING_WORDS(1); + INSERT_PADDING_WORDS_NOINIT(1); Common::Rectangle<f32> GetRect() const { return { @@ -700,7 +700,7 @@ public: u32 address_low; s32 buffer_size; s32 buffer_offset; - INSERT_UNION_PADDING_WORDS(3); + INSERT_PADDING_WORDS_NOINIT(3); GPUVAddr Address() const { return static_cast<GPUVAddr>((static_cast<GPUVAddr>(address_high) << 32) | @@ -713,7 +713,7 @@ public: u32 stream; u32 varying_count; u32 stride; - INSERT_UNION_PADDING_WORDS(1); + INSERT_PADDING_WORDS_NOINIT(1); }; static_assert(sizeof(TransformFeedbackLayout) == 16); @@ -731,7 +731,7 @@ public: union { struct { - INSERT_UNION_PADDING_WORDS(0x44); + INSERT_PADDING_WORDS_NOINIT(0x44); u32 wait_for_idle; @@ -744,7 +744,7 @@ public: ShadowRamControl shadow_ram_control; - INSERT_UNION_PADDING_WORDS(0x16); + INSERT_PADDING_WORDS_NOINIT(0x16); Upload::Registers upload; struct { @@ -755,11 +755,11 @@ public: u32 data_upload; - INSERT_UNION_PADDING_WORDS(0x16); + INSERT_PADDING_WORDS_NOINIT(0x16); u32 force_early_fragment_tests; - INSERT_UNION_PADDING_WORDS(0x2D); + INSERT_PADDING_WORDS_NOINIT(0x2D); struct { union { @@ -769,7 +769,7 @@ public: }; } sync_info; - INSERT_UNION_PADDING_WORDS(0x15); + INSERT_PADDING_WORDS_NOINIT(0x15); union { BitField<0, 2, TessellationPrimitive> prim; @@ -781,21 +781,21 @@ public: std::array<f32, 4> tess_level_outer; std::array<f32, 2> tess_level_inner; - INSERT_UNION_PADDING_WORDS(0x10); + INSERT_PADDING_WORDS_NOINIT(0x10); u32 rasterize_enable; std::array<TransformFeedbackBinding, NumTransformFeedbackBuffers> tfb_bindings; - INSERT_UNION_PADDING_WORDS(0xC0); + INSERT_PADDING_WORDS_NOINIT(0xC0); std::array<TransformFeedbackLayout, NumTransformFeedbackBuffers> tfb_layouts; - INSERT_UNION_PADDING_WORDS(0x1); + INSERT_PADDING_WORDS_NOINIT(0x1); u32 tfb_enabled; - INSERT_UNION_PADDING_WORDS(0x2E); + INSERT_PADDING_WORDS_NOINIT(0x2E); std::array<RenderTargetConfig, NumRenderTargets> rt; @@ -803,7 +803,7 @@ public: std::array<ViewPort, NumViewports> viewports; - INSERT_UNION_PADDING_WORDS(0x1D); + INSERT_PADDING_WORDS_NOINIT(0x1D); struct { u32 first; @@ -815,16 +815,16 @@ public: float clear_color[4]; float clear_depth; - INSERT_UNION_PADDING_WORDS(0x3); + INSERT_PADDING_WORDS_NOINIT(0x3); s32 clear_stencil; - INSERT_UNION_PADDING_WORDS(0x2); + INSERT_PADDING_WORDS_NOINIT(0x2); PolygonMode polygon_mode_front; PolygonMode polygon_mode_back; - INSERT_UNION_PADDING_WORDS(0x3); + INSERT_PADDING_WORDS_NOINIT(0x3); u32 polygon_offset_point_enable; u32 polygon_offset_line_enable; @@ -832,47 +832,47 @@ public: u32 patch_vertices; - INSERT_UNION_PADDING_WORDS(0x4); + INSERT_PADDING_WORDS_NOINIT(0x4); u32 fragment_barrier; - INSERT_UNION_PADDING_WORDS(0x7); + INSERT_PADDING_WORDS_NOINIT(0x7); std::array<ScissorTest, NumViewports> scissor_test; - INSERT_UNION_PADDING_WORDS(0x15); + INSERT_PADDING_WORDS_NOINIT(0x15); s32 stencil_back_func_ref; u32 stencil_back_mask; u32 stencil_back_func_mask; - INSERT_UNION_PADDING_WORDS(0x5); + INSERT_PADDING_WORDS_NOINIT(0x5); u32 invalidate_texture_data_cache; - INSERT_UNION_PADDING_WORDS(0x1); + INSERT_PADDING_WORDS_NOINIT(0x1); u32 tiled_cache_barrier; - INSERT_UNION_PADDING_WORDS(0x4); + INSERT_PADDING_WORDS_NOINIT(0x4); u32 color_mask_common; - INSERT_UNION_PADDING_WORDS(0x2); + INSERT_PADDING_WORDS_NOINIT(0x2); f32 depth_bounds[2]; - INSERT_UNION_PADDING_WORDS(0x2); + INSERT_PADDING_WORDS_NOINIT(0x2); u32 rt_separate_frag_data; - INSERT_UNION_PADDING_WORDS(0x1); + INSERT_PADDING_WORDS_NOINIT(0x1); u32 multisample_raster_enable; u32 multisample_raster_samples; std::array<u32, 4> multisample_sample_mask; - INSERT_UNION_PADDING_WORDS(0x5); + INSERT_PADDING_WORDS_NOINIT(0x5); struct { u32 address_high; @@ -898,7 +898,7 @@ public: }; } render_area; - INSERT_UNION_PADDING_WORDS(0x3F); + INSERT_PADDING_WORDS_NOINIT(0x3F); union { BitField<0, 4, u32> stencil; @@ -907,24 +907,24 @@ public: BitField<12, 4, u32> viewport; } clear_flags; - INSERT_UNION_PADDING_WORDS(0x10); + INSERT_PADDING_WORDS_NOINIT(0x10); u32 fill_rectangle; - INSERT_UNION_PADDING_WORDS(0x8); + INSERT_PADDING_WORDS_NOINIT(0x8); std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format; std::array<MsaaSampleLocation, 4> multisample_sample_locations; - INSERT_UNION_PADDING_WORDS(0x2); + INSERT_PADDING_WORDS_NOINIT(0x2); union { BitField<0, 1, u32> enable; BitField<4, 3, u32> target; } multisample_coverage_to_color; - INSERT_UNION_PADDING_WORDS(0x8); + INSERT_PADDING_WORDS_NOINIT(0x8); struct { union { @@ -947,7 +947,7 @@ public: } } rt_control; - INSERT_UNION_PADDING_WORDS(0x2); + INSERT_PADDING_WORDS_NOINIT(0x2); u32 zeta_width; u32 zeta_height; @@ -958,11 +958,11 @@ public: SamplerIndex sampler_index; - INSERT_UNION_PADDING_WORDS(0x25); + INSERT_PADDING_WORDS_NOINIT(0x25); u32 depth_test_enable; - INSERT_UNION_PADDING_WORDS(0x5); + INSERT_PADDING_WORDS_NOINIT(0x5); u32 independent_blend_enable; @@ -970,7 +970,7 @@ public: u32 alpha_test_enabled; - INSERT_UNION_PADDING_WORDS(0x6); + INSERT_PADDING_WORDS_NOINIT(0x6); u32 d3d_cull_mode; @@ -985,7 +985,7 @@ public: float a; } blend_color; - INSERT_UNION_PADDING_WORDS(0x4); + INSERT_PADDING_WORDS_NOINIT(0x4); struct { u32 separate_alpha; @@ -994,7 +994,7 @@ public: Blend::Factor factor_dest_rgb; Blend::Equation equation_a; Blend::Factor factor_source_a; - INSERT_UNION_PADDING_WORDS(1); + INSERT_PADDING_WORDS_NOINIT(1); Blend::Factor factor_dest_a; u32 enable_common; @@ -1010,7 +1010,7 @@ public: u32 stencil_front_func_mask; u32 stencil_front_mask; - INSERT_UNION_PADDING_WORDS(0x2); + INSERT_PADDING_WORDS_NOINIT(0x2); u32 frag_color_clamp; @@ -1022,17 +1022,17 @@ public: float line_width_smooth; float line_width_aliased; - INSERT_UNION_PADDING_WORDS(0x1B); + INSERT_PADDING_WORDS_NOINIT(0x1B); u32 invalidate_sampler_cache_no_wfi; u32 invalidate_texture_header_cache_no_wfi; - INSERT_UNION_PADDING_WORDS(0x2); + INSERT_PADDING_WORDS_NOINIT(0x2); u32 vb_element_base; u32 vb_base_instance; - INSERT_UNION_PADDING_WORDS(0x35); + INSERT_PADDING_WORDS_NOINIT(0x35); u32 clip_distance_enabled; @@ -1040,11 +1040,11 @@ public: float point_size; - INSERT_UNION_PADDING_WORDS(0x1); + INSERT_PADDING_WORDS_NOINIT(0x1); u32 point_sprite_enable; - INSERT_UNION_PADDING_WORDS(0x3); + INSERT_PADDING_WORDS_NOINIT(0x3); CounterReset counter_reset; @@ -1057,7 +1057,7 @@ public: BitField<4, 1, u32> alpha_to_one; } multisample_control; - INSERT_UNION_PADDING_WORDS(0x4); + INSERT_PADDING_WORDS_NOINIT(0x4); struct { u32 address_high; @@ -1081,7 +1081,7 @@ public: } } tsc; - INSERT_UNION_PADDING_WORDS(0x1); + INSERT_PADDING_WORDS_NOINIT(0x1); float polygon_offset_factor; @@ -1098,7 +1098,7 @@ public: } } tic; - INSERT_UNION_PADDING_WORDS(0x5); + INSERT_PADDING_WORDS_NOINIT(0x5); u32 stencil_two_side_enable; StencilOp stencil_back_op_fail; @@ -1106,17 +1106,17 @@ public: StencilOp stencil_back_op_zpass; ComparisonOp stencil_back_func_func; - INSERT_UNION_PADDING_WORDS(0x4); + INSERT_PADDING_WORDS_NOINIT(0x4); u32 framebuffer_srgb; float polygon_offset_units; - INSERT_UNION_PADDING_WORDS(0x4); + INSERT_PADDING_WORDS_NOINIT(0x4); Tegra::Texture::MsaaMode multisample_mode; - INSERT_UNION_PADDING_WORDS(0xC); + INSERT_PADDING_WORDS_NOINIT(0xC); union { BitField<2, 1, u32> coord_origin; @@ -1132,7 +1132,7 @@ public: (static_cast<GPUVAddr>(code_address_high) << 32) | code_address_low); } } code_address; - INSERT_UNION_PADDING_WORDS(1); + INSERT_PADDING_WORDS_NOINIT(1); struct { u32 vertex_end_gl; @@ -1144,14 +1144,14 @@ public: }; } draw; - INSERT_UNION_PADDING_WORDS(0xA); + INSERT_PADDING_WORDS_NOINIT(0xA); struct { u32 enabled; u32 index; } primitive_restart; - INSERT_UNION_PADDING_WORDS(0x5F); + INSERT_PADDING_WORDS_NOINIT(0x5F); struct { u32 start_addr_high; @@ -1192,9 +1192,9 @@ public: } } index_array; - INSERT_UNION_PADDING_WORDS(0x7); + INSERT_PADDING_WORDS_NOINIT(0x7); - INSERT_UNION_PADDING_WORDS(0x1F); + INSERT_PADDING_WORDS_NOINIT(0x1F); float polygon_offset_clamp; @@ -1208,14 +1208,14 @@ public: } } instanced_arrays; - INSERT_UNION_PADDING_WORDS(0x4); + INSERT_PADDING_WORDS_NOINIT(0x4); union { BitField<0, 1, u32> enable; BitField<4, 8, u32> unk4; } vp_point_size; - INSERT_UNION_PADDING_WORDS(1); + INSERT_PADDING_WORDS_NOINIT(1); u32 cull_test_enabled; FrontFace front_face; @@ -1223,11 +1223,11 @@ public: u32 pixel_center_integer; - INSERT_UNION_PADDING_WORDS(0x1); + INSERT_PADDING_WORDS_NOINIT(0x1); u32 viewport_transform_enabled; - INSERT_UNION_PADDING_WORDS(0x3); + INSERT_PADDING_WORDS_NOINIT(0x3); union { BitField<0, 1, u32> depth_range_0_1; @@ -1236,18 +1236,18 @@ public: BitField<11, 1, u32> depth_clamp_disabled; } view_volume_clip_control; - INSERT_UNION_PADDING_WORDS(0x1F); + INSERT_PADDING_WORDS_NOINIT(0x1F); u32 depth_bounds_enable; - INSERT_UNION_PADDING_WORDS(1); + INSERT_PADDING_WORDS_NOINIT(1); struct { u32 enable; LogicOperation operation; } logic_op; - INSERT_UNION_PADDING_WORDS(0x1); + INSERT_PADDING_WORDS_NOINIT(0x1); union { u32 raw; @@ -1260,9 +1260,9 @@ public: BitField<6, 4, u32> RT; BitField<10, 11, u32> layer; } clear_buffers; - INSERT_UNION_PADDING_WORDS(0xB); + INSERT_PADDING_WORDS_NOINIT(0xB); std::array<ColorMask, NumRenderTargets> color_mask; - INSERT_UNION_PADDING_WORDS(0x38); + INSERT_PADDING_WORDS_NOINIT(0x38); struct { u32 query_address_high; @@ -1284,7 +1284,7 @@ public: } } query; - INSERT_UNION_PADDING_WORDS(0x3C); + INSERT_PADDING_WORDS_NOINIT(0x3C); struct { union { @@ -1325,10 +1325,10 @@ public: BitField<4, 4, ShaderProgram> program; }; u32 offset; - INSERT_UNION_PADDING_WORDS(14); + INSERT_PADDING_WORDS_NOINIT(14); } shader_config[MaxShaderProgram]; - INSERT_UNION_PADDING_WORDS(0x60); + INSERT_PADDING_WORDS_NOINIT(0x60); u32 firmware[0x20]; @@ -1345,7 +1345,7 @@ public: } } const_buffer; - INSERT_UNION_PADDING_WORDS(0x10); + INSERT_PADDING_WORDS_NOINIT(0x10); struct { union { @@ -1353,18 +1353,18 @@ public: BitField<0, 1, u32> valid; BitField<4, 5, u32> index; }; - INSERT_UNION_PADDING_WORDS(7); + INSERT_PADDING_WORDS_NOINIT(7); } cb_bind[MaxShaderStage]; - INSERT_UNION_PADDING_WORDS(0x56); + INSERT_PADDING_WORDS_NOINIT(0x56); u32 tex_cb_index; - INSERT_UNION_PADDING_WORDS(0x7D); + INSERT_PADDING_WORDS_NOINIT(0x7D); std::array<std::array<u8, 128>, NumTransformFeedbackBuffers> tfb_varying_locs; - INSERT_UNION_PADDING_WORDS(0x298); + INSERT_PADDING_WORDS_NOINIT(0x298); struct { /// Compressed address of a buffer that holds information about bound SSBOs. @@ -1376,14 +1376,14 @@ public: } } ssbo_info; - INSERT_UNION_PADDING_WORDS(0x11); + INSERT_PADDING_WORDS_NOINIT(0x11); struct { u32 address[MaxShaderStage]; u32 size[MaxShaderStage]; } tex_info_buffers; - INSERT_UNION_PADDING_WORDS(0xCC); + INSERT_PADDING_WORDS_NOINIT(0xCC); }; std::array<u32, NUM_REGS> reg_array; }; diff --git a/src/video_core/engines/shader_header.h b/src/video_core/engines/shader_header.h index ceec05459..e0d7b89c5 100644 --- a/src/video_core/engines/shader_header.h +++ b/src/video_core/engines/shader_header.h @@ -68,10 +68,10 @@ struct Header { union { struct { - INSERT_UNION_PADDING_BYTES(3); // ImapSystemValuesA - INSERT_UNION_PADDING_BYTES(1); // ImapSystemValuesB - INSERT_UNION_PADDING_BYTES(16); // ImapGenericVector[32] - INSERT_UNION_PADDING_BYTES(2); // ImapColor + INSERT_PADDING_BYTES_NOINIT(3); // ImapSystemValuesA + INSERT_PADDING_BYTES_NOINIT(1); // ImapSystemValuesB + INSERT_PADDING_BYTES_NOINIT(16); // ImapGenericVector[32] + INSERT_PADDING_BYTES_NOINIT(2); // ImapColor union { BitField<0, 8, u16> clip_distances; BitField<8, 1, u16> point_sprite_s; @@ -82,20 +82,20 @@ struct Header { BitField<14, 1, u16> instance_id; BitField<15, 1, u16> vertex_id; }; - INSERT_UNION_PADDING_BYTES(5); // ImapFixedFncTexture[10] - INSERT_UNION_PADDING_BYTES(1); // ImapReserved - INSERT_UNION_PADDING_BYTES(3); // OmapSystemValuesA - INSERT_UNION_PADDING_BYTES(1); // OmapSystemValuesB - INSERT_UNION_PADDING_BYTES(16); // OmapGenericVector[32] - INSERT_UNION_PADDING_BYTES(2); // OmapColor - INSERT_UNION_PADDING_BYTES(2); // OmapSystemValuesC - INSERT_UNION_PADDING_BYTES(5); // OmapFixedFncTexture[10] - INSERT_UNION_PADDING_BYTES(1); // OmapReserved + INSERT_PADDING_BYTES_NOINIT(5); // ImapFixedFncTexture[10] + INSERT_PADDING_BYTES_NOINIT(1); // ImapReserved + INSERT_PADDING_BYTES_NOINIT(3); // OmapSystemValuesA + INSERT_PADDING_BYTES_NOINIT(1); // OmapSystemValuesB + INSERT_PADDING_BYTES_NOINIT(16); // OmapGenericVector[32] + INSERT_PADDING_BYTES_NOINIT(2); // OmapColor + INSERT_PADDING_BYTES_NOINIT(2); // OmapSystemValuesC + INSERT_PADDING_BYTES_NOINIT(5); // OmapFixedFncTexture[10] + INSERT_PADDING_BYTES_NOINIT(1); // OmapReserved } vtg; struct { - INSERT_UNION_PADDING_BYTES(3); // ImapSystemValuesA - INSERT_UNION_PADDING_BYTES(1); // ImapSystemValuesB + INSERT_PADDING_BYTES_NOINIT(3); // ImapSystemValuesA + INSERT_PADDING_BYTES_NOINIT(1); // ImapSystemValuesB union { BitField<0, 2, PixelImap> x; @@ -105,10 +105,10 @@ struct Header { u8 raw; } imap_generic_vector[32]; - INSERT_UNION_PADDING_BYTES(2); // ImapColor - INSERT_UNION_PADDING_BYTES(2); // ImapSystemValuesC - INSERT_UNION_PADDING_BYTES(10); // ImapFixedFncTexture[10] - INSERT_UNION_PADDING_BYTES(2); // ImapReserved + INSERT_PADDING_BYTES_NOINIT(2); // ImapColor + INSERT_PADDING_BYTES_NOINIT(2); // ImapSystemValuesC + INSERT_PADDING_BYTES_NOINIT(10); // ImapFixedFncTexture[10] + INSERT_PADDING_BYTES_NOINIT(2); // ImapReserved struct { u32 target; diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index d81e38680..b4ce6b154 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h @@ -270,7 +270,7 @@ public: union { struct { - INSERT_UNION_PADDING_WORDS(0x4); + INSERT_PADDING_WORDS_NOINIT(0x4); struct { u32 address_high; u32 address_low; @@ -283,18 +283,18 @@ public: u32 semaphore_sequence; u32 semaphore_trigger; - INSERT_UNION_PADDING_WORDS(0xC); + INSERT_PADDING_WORDS_NOINIT(0xC); // The pusher and the puller share the reference counter, the pusher only has read // access u32 reference_count; - INSERT_UNION_PADDING_WORDS(0x5); + INSERT_PADDING_WORDS_NOINIT(0x5); u32 semaphore_acquire; u32 semaphore_release; u32 fence_value; FenceAction fence_action; - INSERT_UNION_PADDING_WORDS(0xE2); + INSERT_PADDING_WORDS_NOINIT(0xE2); // Puller state u32 acquire_mode; diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.cpp b/src/video_core/renderer_vulkan/renderer_vulkan.cpp index d7437e185..61796e33a 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.cpp +++ b/src/video_core/renderer_vulkan/renderer_vulkan.cpp @@ -23,7 +23,6 @@ #include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/vk_blit_screen.h" #include "video_core/renderer_vulkan/vk_master_semaphore.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_state_tracker.h" @@ -32,6 +31,7 @@ #include "video_core/vulkan_common/vulkan_device.h" #include "video_core/vulkan_common/vulkan_instance.h" #include "video_core/vulkan_common/vulkan_library.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_surface.h" #include "video_core/vulkan_common/vulkan_wrapper.h" @@ -137,7 +137,7 @@ bool RendererVulkan::Init() try { InitializeDevice(); Report(); - memory_manager = std::make_unique<VKMemoryManager>(*device); + memory_allocator = std::make_unique<MemoryAllocator>(*device); state_tracker = std::make_unique<StateTracker>(gpu); @@ -149,11 +149,11 @@ bool RendererVulkan::Init() try { rasterizer = std::make_unique<RasterizerVulkan>(render_window, gpu, gpu.MemoryManager(), cpu_memory, screen_info, *device, - *memory_manager, *state_tracker, *scheduler); + *memory_allocator, *state_tracker, *scheduler); blit_screen = std::make_unique<VKBlitScreen>(cpu_memory, render_window, *rasterizer, *device, - *memory_manager, *swapchain, *scheduler, screen_info); + *memory_allocator, *swapchain, *scheduler, screen_info); return true; } catch (const vk::Exception& exception) { @@ -172,7 +172,7 @@ void RendererVulkan::ShutDown() { blit_screen.reset(); scheduler.reset(); swapchain.reset(); - memory_manager.reset(); + memory_allocator.reset(); device.reset(); } diff --git a/src/video_core/renderer_vulkan/renderer_vulkan.h b/src/video_core/renderer_vulkan/renderer_vulkan.h index 5575ffc54..daf55b9b4 100644 --- a/src/video_core/renderer_vulkan/renderer_vulkan.h +++ b/src/video_core/renderer_vulkan/renderer_vulkan.h @@ -29,8 +29,8 @@ namespace Vulkan { class Device; class StateTracker; +class MemoryAllocator; class VKBlitScreen; -class VKMemoryManager; class VKSwapchain; class VKScheduler; @@ -75,7 +75,7 @@ private: vk::DebugUtilsMessenger debug_callback; std::unique_ptr<Device> device; - std::unique_ptr<VKMemoryManager> memory_manager; + std::unique_ptr<MemoryAllocator> memory_allocator; std::unique_ptr<StateTracker> state_tracker; std::unique_ptr<VKScheduler> scheduler; std::unique_ptr<VKSwapchain> swapchain; diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.cpp b/src/video_core/renderer_vulkan/vk_blit_screen.cpp index 5e184eb42..3e3b895e0 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.cpp +++ b/src/video_core/renderer_vulkan/vk_blit_screen.cpp @@ -22,13 +22,13 @@ #include "video_core/renderer_vulkan/renderer_vulkan.h" #include "video_core/renderer_vulkan/vk_blit_screen.h" #include "video_core/renderer_vulkan/vk_master_semaphore.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_shader_util.h" #include "video_core/renderer_vulkan/vk_swapchain.h" #include "video_core/surface.h" #include "video_core/textures/decoders.h" #include "video_core/vulkan_common/vulkan_device.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { @@ -115,10 +115,10 @@ struct VKBlitScreen::BufferData { VKBlitScreen::VKBlitScreen(Core::Memory::Memory& cpu_memory_, Core::Frontend::EmuWindow& render_window_, VideoCore::RasterizerInterface& rasterizer_, const Device& device_, - VKMemoryManager& memory_manager_, VKSwapchain& swapchain_, + MemoryAllocator& memory_allocator_, VKSwapchain& swapchain_, VKScheduler& scheduler_, const VKScreenInfo& screen_info_) : cpu_memory{cpu_memory_}, render_window{render_window_}, rasterizer{rasterizer_}, - device{device_}, memory_manager{memory_manager_}, swapchain{swapchain_}, + device{device_}, memory_allocator{memory_allocator_}, swapchain{swapchain_}, scheduler{scheduler_}, image_count{swapchain.GetImageCount()}, screen_info{screen_info_} { resource_ticks.resize(image_count); @@ -150,8 +150,8 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool SetUniformData(data, framebuffer); SetVertexData(data, framebuffer); - auto map = buffer_commit->Map(); - std::memcpy(map.Address(), &data, sizeof(data)); + const std::span<u8> map = buffer_commit.Map(); + std::memcpy(map.data(), &data, sizeof(data)); if (!use_accelerated) { const u64 image_offset = GetRawImageOffset(framebuffer, image_index); @@ -165,8 +165,8 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool constexpr u32 block_height_log2 = 4; const u32 bytes_per_pixel = GetBytesPerPixel(framebuffer); Tegra::Texture::UnswizzleTexture( - std::span(map.Address() + image_offset, size_bytes), std::span(host_ptr, size_bytes), - bytes_per_pixel, framebuffer.width, framebuffer.height, 1, block_height_log2, 0); + map.subspan(image_offset, size_bytes), std::span(host_ptr, size_bytes), bytes_per_pixel, + framebuffer.width, framebuffer.height, 1, block_height_log2, 0); const VkBufferImageCopy copy{ .bufferOffset = image_offset, @@ -224,8 +224,6 @@ VkSemaphore VKBlitScreen::Draw(const Tegra::FramebufferConfig& framebuffer, bool VK_PIPELINE_STAGE_FRAGMENT_SHADER_BIT, 0, write_barrier); }); } - map.Release(); - scheduler.Record([renderpass = *renderpass, framebuffer = *framebuffers[image_index], descriptor_set = descriptor_sets[image_index], buffer = *buffer, size = swapchain.GetSize(), pipeline = *pipeline, @@ -642,7 +640,7 @@ void VKBlitScreen::ReleaseRawImages() { raw_images.clear(); raw_buffer_commits.clear(); buffer.reset(); - buffer_commit.reset(); + buffer_commit = MemoryCommit{}; } void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuffer) { @@ -659,7 +657,7 @@ void VKBlitScreen::CreateStagingBuffer(const Tegra::FramebufferConfig& framebuff }; buffer = device.GetLogical().CreateBuffer(ci); - buffer_commit = memory_manager.Commit(buffer, true); + buffer_commit = memory_allocator.Commit(buffer, MemoryUsage::Upload); } void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) { @@ -690,7 +688,7 @@ void VKBlitScreen::CreateRawImages(const Tegra::FramebufferConfig& framebuffer) .pQueueFamilyIndices = nullptr, .initialLayout = VK_IMAGE_LAYOUT_UNDEFINED, }); - raw_buffer_commits[i] = memory_manager.Commit(raw_images[i], false); + raw_buffer_commits[i] = memory_allocator.Commit(raw_images[i], MemoryUsage::DeviceLocal); raw_image_views[i] = device.GetLogical().CreateImageView(VkImageViewCreateInfo{ .sType = VK_STRUCTURE_TYPE_IMAGE_VIEW_CREATE_INFO, .pNext = nullptr, diff --git a/src/video_core/renderer_vulkan/vk_blit_screen.h b/src/video_core/renderer_vulkan/vk_blit_screen.h index 69ed61770..b52576957 100644 --- a/src/video_core/renderer_vulkan/vk_blit_screen.h +++ b/src/video_core/renderer_vulkan/vk_blit_screen.h @@ -6,7 +6,7 @@ #include <memory> -#include "video_core/renderer_vulkan/vk_memory_manager.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Core { @@ -43,7 +43,7 @@ public: explicit VKBlitScreen(Core::Memory::Memory& cpu_memory, Core::Frontend::EmuWindow& render_window, VideoCore::RasterizerInterface& rasterizer, const Device& device, - VKMemoryManager& memory_manager, VKSwapchain& swapchain, + MemoryAllocator& memory_allocator, VKSwapchain& swapchain, VKScheduler& scheduler, const VKScreenInfo& screen_info); ~VKBlitScreen(); @@ -86,7 +86,7 @@ private: Core::Frontend::EmuWindow& render_window; VideoCore::RasterizerInterface& rasterizer; const Device& device; - VKMemoryManager& memory_manager; + MemoryAllocator& memory_allocator; VKSwapchain& swapchain; VKScheduler& scheduler; const std::size_t image_count; @@ -104,14 +104,14 @@ private: vk::Sampler sampler; vk::Buffer buffer; - VKMemoryCommit buffer_commit; + MemoryCommit buffer_commit; std::vector<u64> resource_ticks; std::vector<vk::Semaphore> semaphores; std::vector<vk::Image> raw_images; std::vector<vk::ImageView> raw_image_views; - std::vector<VKMemoryCommit> raw_buffer_commits; + std::vector<MemoryCommit> raw_buffer_commits; u32 raw_width = 0; u32 raw_height = 0; }; diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp index 4d517c547..d8ad40a0f 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.cpp @@ -34,17 +34,13 @@ constexpr VkAccessFlags UPLOAD_ACCESS_BARRIERS = constexpr VkAccessFlags TRANSFORM_FEEDBACK_WRITE_ACCESS = VK_ACCESS_TRANSFORM_FEEDBACK_WRITE_BIT_EXT | VK_ACCESS_TRANSFORM_FEEDBACK_COUNTER_WRITE_BIT_EXT; -std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const Device& device, VKScheduler& scheduler) { - return std::make_unique<VKStreamBuffer>(device, scheduler); -} - } // Anonymous namespace -Buffer::Buffer(const Device& device_, VKMemoryManager& memory_manager, VKScheduler& scheduler_, - VKStagingBufferPool& staging_pool_, VAddr cpu_addr_, std::size_t size_) +Buffer::Buffer(const Device& device_, MemoryAllocator& memory_allocator, VKScheduler& scheduler_, + StagingBufferPool& staging_pool_, VAddr cpu_addr_, std::size_t size_) : BufferBlock{cpu_addr_, size_}, device{device_}, scheduler{scheduler_}, staging_pool{ staging_pool_} { - const VkBufferCreateInfo ci{ + buffer = device.GetLogical().CreateBuffer(VkBufferCreateInfo{ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -53,22 +49,20 @@ Buffer::Buffer(const Device& device_, VKMemoryManager& memory_manager, VKSchedul .sharingMode = VK_SHARING_MODE_EXCLUSIVE, .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, - }; - - buffer.handle = device.GetLogical().CreateBuffer(ci); - buffer.commit = memory_manager.Commit(buffer.handle, false); + }); + commit = memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); } Buffer::~Buffer() = default; void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { - const auto& staging = staging_pool.GetUnusedBuffer(data_size, true); - std::memcpy(staging.commit->Map(data_size), data, data_size); + const auto& staging = staging_pool.Request(data_size, MemoryUsage::Upload); + std::memcpy(staging.mapped_span.data(), data, data_size); scheduler.RequestOutsideRenderPassOperationContext(); const VkBuffer handle = Handle(); - scheduler.Record([staging = *staging.handle, handle, offset, data_size, + scheduler.Record([staging = staging.buffer, handle, offset, data_size, &device = device](vk::CommandBuffer cmdbuf) { const VkBufferMemoryBarrier read_barrier{ .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, @@ -104,12 +98,12 @@ void Buffer::Upload(std::size_t offset, std::size_t data_size, const u8* data) { } void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { - const auto& staging = staging_pool.GetUnusedBuffer(data_size, true); + auto staging = staging_pool.Request(data_size, MemoryUsage::Download); scheduler.RequestOutsideRenderPassOperationContext(); const VkBuffer handle = Handle(); scheduler.Record( - [staging = *staging.handle, handle, offset, data_size](vk::CommandBuffer cmdbuf) { + [staging = staging.buffer, handle, offset, data_size](vk::CommandBuffer cmdbuf) { const VkBufferMemoryBarrier barrier{ .sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER, .pNext = nullptr, @@ -130,7 +124,7 @@ void Buffer::Download(std::size_t offset, std::size_t data_size, u8* data) { }); scheduler.Finish(); - std::memcpy(data, staging.commit->Map(data_size), data_size); + std::memcpy(data, staging.mapped_span.data(), data_size); } void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst_offset, @@ -168,29 +162,29 @@ void Buffer::CopyFrom(const Buffer& src, std::size_t src_offset, std::size_t dst VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer_, Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, - const Device& device_, VKMemoryManager& memory_manager_, + const Device& device_, MemoryAllocator& memory_allocator_, VKScheduler& scheduler_, VKStreamBuffer& stream_buffer_, - VKStagingBufferPool& staging_pool_) + StagingBufferPool& staging_pool_) : VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer>{rasterizer_, gpu_memory_, cpu_memory_, stream_buffer_}, - device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_}, staging_pool{ - staging_pool_} {} + device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_}, + staging_pool{staging_pool_} {} VKBufferCache::~VKBufferCache() = default; std::shared_ptr<Buffer> VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) { - return std::make_shared<Buffer>(device, memory_manager, scheduler, staging_pool, cpu_addr, + return std::make_shared<Buffer>(device, memory_allocator, scheduler, staging_pool, cpu_addr, size); } VKBufferCache::BufferInfo VKBufferCache::GetEmptyBuffer(std::size_t size) { size = std::max(size, std::size_t(4)); - const auto& empty = staging_pool.GetUnusedBuffer(size, false); + const auto& empty = staging_pool.Request(size, MemoryUsage::DeviceLocal); scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([size, buffer = *empty.handle](vk::CommandBuffer cmdbuf) { + scheduler.Record([size, buffer = empty.buffer](vk::CommandBuffer cmdbuf) { cmdbuf.FillBuffer(buffer, 0, size, 0); }); - return {*empty.handle, 0, 0}; + return {empty.buffer, 0, 0}; } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_buffer_cache.h b/src/video_core/renderer_vulkan/vk_buffer_cache.h index 1c39aed34..41d577510 100644 --- a/src/video_core/renderer_vulkan/vk_buffer_cache.h +++ b/src/video_core/renderer_vulkan/vk_buffer_cache.h @@ -8,21 +8,20 @@ #include "common/common_types.h" #include "video_core/buffer_cache/buffer_cache.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_stream_buffer.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { class Device; -class VKMemoryManager; class VKScheduler; class Buffer final : public VideoCommon::BufferBlock { public: - explicit Buffer(const Device& device, VKMemoryManager& memory_manager, VKScheduler& scheduler, - VKStagingBufferPool& staging_pool, VAddr cpu_addr_, std::size_t size_); + explicit Buffer(const Device& device, MemoryAllocator& memory_allocator, VKScheduler& scheduler, + StagingBufferPool& staging_pool, VAddr cpu_addr_, std::size_t size_); ~Buffer(); void Upload(std::size_t offset, std::size_t data_size, const u8* data); @@ -33,7 +32,7 @@ public: std::size_t copy_size); VkBuffer Handle() const { - return *buffer.handle; + return *buffer; } u64 Address() const { @@ -43,18 +42,19 @@ public: private: const Device& device; VKScheduler& scheduler; - VKStagingBufferPool& staging_pool; + StagingBufferPool& staging_pool; - VKBuffer buffer; + vk::Buffer buffer; + MemoryCommit commit; }; class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> { public: explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Tegra::MemoryManager& gpu_memory, Core::Memory::Memory& cpu_memory, - const Device& device, VKMemoryManager& memory_manager, + const Device& device, MemoryAllocator& memory_allocator, VKScheduler& scheduler, VKStreamBuffer& stream_buffer, - VKStagingBufferPool& staging_pool); + StagingBufferPool& staging_pool); ~VKBufferCache(); BufferInfo GetEmptyBuffer(std::size_t size) override; @@ -64,9 +64,9 @@ protected: private: const Device& device; - VKMemoryManager& memory_manager; + MemoryAllocator& memory_allocator; VKScheduler& scheduler; - VKStagingBufferPool& staging_pool; + StagingBufferPool& staging_pool; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.cpp b/src/video_core/renderer_vulkan/vk_compute_pass.cpp index 02a6d54b7..5eb6a54be 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.cpp +++ b/src/video_core/renderer_vulkan/vk_compute_pass.cpp @@ -164,7 +164,7 @@ VkDescriptorSet VKComputePass::CommitDescriptorSet( QuadArrayPass::QuadArrayPass(const Device& device_, VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, - VKStagingBufferPool& staging_buffer_pool_, + StagingBufferPool& staging_buffer_pool_, VKUpdateDescriptorQueue& update_descriptor_queue_) : VKComputePass(device_, descriptor_pool_, BuildQuadArrayPassDescriptorSetLayoutBinding(), BuildQuadArrayPassDescriptorUpdateTemplateEntry(), @@ -177,18 +177,18 @@ QuadArrayPass::~QuadArrayPass() = default; std::pair<VkBuffer, VkDeviceSize> QuadArrayPass::Assemble(u32 num_vertices, u32 first) { const u32 num_triangle_vertices = (num_vertices / 4) * 6; const std::size_t staging_size = num_triangle_vertices * sizeof(u32); - auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); + const auto staging_ref = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); update_descriptor_queue.Acquire(); - update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); + update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); scheduler.RequestOutsideRenderPassOperationContext(); ASSERT(num_vertices % 4 == 0); const u32 num_quads = num_vertices / 4; - scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, num_quads, - first, set](vk::CommandBuffer cmdbuf) { + scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging_ref.buffer, + num_quads, first, set](vk::CommandBuffer cmdbuf) { constexpr u32 dispatch_size = 1024; cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); cmdbuf.BindDescriptorSets(VK_PIPELINE_BIND_POINT_COMPUTE, layout, 0, set, {}); @@ -208,11 +208,11 @@ std::pair<VkBuffer, VkDeviceSize> QuadArrayPass::Assemble(u32 num_vertices, u32 cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, {barrier}, {}); }); - return {*buffer.handle, 0}; + return {staging_ref.buffer, 0}; } Uint8Pass::Uint8Pass(const Device& device, VKScheduler& scheduler_, - VKDescriptorPool& descriptor_pool, VKStagingBufferPool& staging_buffer_pool_, + VKDescriptorPool& descriptor_pool, StagingBufferPool& staging_buffer_pool_, VKUpdateDescriptorQueue& update_descriptor_queue_) : VKComputePass(device, descriptor_pool, BuildInputOutputDescriptorSetBindings(), BuildInputOutputDescriptorUpdateTemplate(), {}, VULKAN_UINT8_COMP_SPV), @@ -224,15 +224,15 @@ Uint8Pass::~Uint8Pass() = default; std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buffer, u64 src_offset) { const u32 staging_size = static_cast<u32>(num_vertices * sizeof(u16)); - auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); + const auto staging_ref = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); update_descriptor_queue.Acquire(); update_descriptor_queue.AddBuffer(src_buffer, src_offset, num_vertices); - update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); + update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set, + scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging_ref.buffer, set, num_vertices](vk::CommandBuffer cmdbuf) { constexpr u32 dispatch_size = 1024; cmdbuf.BindPipeline(VK_PIPELINE_BIND_POINT_COMPUTE, pipeline); @@ -252,12 +252,12 @@ std::pair<VkBuffer, u64> Uint8Pass::Assemble(u32 num_vertices, VkBuffer src_buff cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {}); }); - return {*buffer.handle, 0}; + return {staging_ref.buffer, 0}; } QuadIndexedPass::QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, - VKStagingBufferPool& staging_buffer_pool_, + StagingBufferPool& staging_buffer_pool_, VKUpdateDescriptorQueue& update_descriptor_queue_) : VKComputePass(device_, descriptor_pool_, BuildInputOutputDescriptorSetBindings(), BuildInputOutputDescriptorUpdateTemplate(), @@ -286,15 +286,15 @@ std::pair<VkBuffer, u64> QuadIndexedPass::Assemble( const u32 num_tri_vertices = (num_vertices / 4) * 6; const std::size_t staging_size = num_tri_vertices * sizeof(u32); - auto& buffer = staging_buffer_pool.GetUnusedBuffer(staging_size, false); + const auto staging_ref = staging_buffer_pool.Request(staging_size, MemoryUsage::DeviceLocal); update_descriptor_queue.Acquire(); update_descriptor_queue.AddBuffer(src_buffer, src_offset, input_size); - update_descriptor_queue.AddBuffer(*buffer.handle, 0, staging_size); + update_descriptor_queue.AddBuffer(staging_ref.buffer, 0, staging_size); const VkDescriptorSet set = CommitDescriptorSet(update_descriptor_queue); scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = *buffer.handle, set, + scheduler.Record([layout = *layout, pipeline = *pipeline, buffer = staging_ref.buffer, set, num_tri_vertices, base_vertex, index_shift](vk::CommandBuffer cmdbuf) { static constexpr u32 dispatch_size = 1024; const std::array push_constants = {base_vertex, index_shift}; @@ -317,7 +317,7 @@ std::pair<VkBuffer, u64> QuadIndexedPass::Assemble( cmdbuf.PipelineBarrier(VK_PIPELINE_STAGE_COMPUTE_SHADER_BIT, VK_PIPELINE_STAGE_VERTEX_INPUT_BIT, 0, {}, barrier, {}); }); - return {*buffer.handle, 0}; + return {staging_ref.buffer, 0}; } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_compute_pass.h b/src/video_core/renderer_vulkan/vk_compute_pass.h index 7ddb09afb..f5c6f5f17 100644 --- a/src/video_core/renderer_vulkan/vk_compute_pass.h +++ b/src/video_core/renderer_vulkan/vk_compute_pass.h @@ -16,8 +16,8 @@ namespace Vulkan { class Device; +class StagingBufferPool; class VKScheduler; -class VKStagingBufferPool; class VKUpdateDescriptorQueue; class VKComputePass { @@ -45,7 +45,7 @@ class QuadArrayPass final : public VKComputePass { public: explicit QuadArrayPass(const Device& device_, VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, - VKStagingBufferPool& staging_buffer_pool_, + StagingBufferPool& staging_buffer_pool_, VKUpdateDescriptorQueue& update_descriptor_queue_); ~QuadArrayPass(); @@ -53,15 +53,14 @@ public: private: VKScheduler& scheduler; - VKStagingBufferPool& staging_buffer_pool; + StagingBufferPool& staging_buffer_pool; VKUpdateDescriptorQueue& update_descriptor_queue; }; class Uint8Pass final : public VKComputePass { public: explicit Uint8Pass(const Device& device_, VKScheduler& scheduler_, - VKDescriptorPool& descriptor_pool_, - VKStagingBufferPool& staging_buffer_pool_, + VKDescriptorPool& descriptor_pool_, StagingBufferPool& staging_buffer_pool_, VKUpdateDescriptorQueue& update_descriptor_queue_); ~Uint8Pass(); @@ -69,7 +68,7 @@ public: private: VKScheduler& scheduler; - VKStagingBufferPool& staging_buffer_pool; + StagingBufferPool& staging_buffer_pool; VKUpdateDescriptorQueue& update_descriptor_queue; }; @@ -77,7 +76,7 @@ class QuadIndexedPass final : public VKComputePass { public: explicit QuadIndexedPass(const Device& device_, VKScheduler& scheduler_, VKDescriptorPool& descriptor_pool_, - VKStagingBufferPool& staging_buffer_pool_, + StagingBufferPool& staging_buffer_pool_, VKUpdateDescriptorQueue& update_descriptor_queue_); ~QuadIndexedPass(); @@ -87,7 +86,7 @@ public: private: VKScheduler& scheduler; - VKStagingBufferPool& staging_buffer_pool; + StagingBufferPool& staging_buffer_pool; VKUpdateDescriptorQueue& update_descriptor_queue; }; diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.cpp b/src/video_core/renderer_vulkan/vk_fence_manager.cpp index 4c5bc0aa1..6cd00884d 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.cpp +++ b/src/video_core/renderer_vulkan/vk_fence_manager.cpp @@ -3,7 +3,6 @@ // Refer to the license.txt file included. #include <memory> -#include <thread> #include "video_core/renderer_vulkan/vk_buffer_cache.h" #include "video_core/renderer_vulkan/vk_fence_manager.h" @@ -14,13 +13,11 @@ namespace Vulkan { -InnerFence::InnerFence(const Device& device_, VKScheduler& scheduler_, u32 payload_, - bool is_stubbed_) - : FenceBase{payload_, is_stubbed_}, device{device_}, scheduler{scheduler_} {} +InnerFence::InnerFence(VKScheduler& scheduler_, u32 payload_, bool is_stubbed_) + : FenceBase{payload_, is_stubbed_}, scheduler{scheduler_} {} -InnerFence::InnerFence(const Device& device_, VKScheduler& scheduler_, GPUVAddr address_, - u32 payload_, bool is_stubbed_) - : FenceBase{address_, payload_, is_stubbed_}, device{device_}, scheduler{scheduler_} {} +InnerFence::InnerFence(VKScheduler& scheduler_, GPUVAddr address_, u32 payload_, bool is_stubbed_) + : FenceBase{address_, payload_, is_stubbed_}, scheduler{scheduler_} {} InnerFence::~InnerFence() = default; @@ -28,63 +25,38 @@ void InnerFence::Queue() { if (is_stubbed) { return; } - ASSERT(!event); - - event = device.GetLogical().CreateEvent(); - ticks = scheduler.CurrentTick(); - - scheduler.RequestOutsideRenderPassOperationContext(); - scheduler.Record([event = *event](vk::CommandBuffer cmdbuf) { - cmdbuf.SetEvent(event, VK_PIPELINE_STAGE_ALL_COMMANDS_BIT); - }); + // Get the current tick so we can wait for it + wait_tick = scheduler.CurrentTick(); + scheduler.Flush(); } bool InnerFence::IsSignaled() const { if (is_stubbed) { return true; } - ASSERT(event); - return IsEventSignalled(); + return scheduler.IsFree(wait_tick); } void InnerFence::Wait() { if (is_stubbed) { return; } - ASSERT(event); - - if (ticks >= scheduler.CurrentTick()) { - scheduler.Flush(); - } - while (!IsEventSignalled()) { - std::this_thread::yield(); - } -} - -bool InnerFence::IsEventSignalled() const { - switch (const VkResult result = event.GetStatus()) { - case VK_EVENT_SET: - return true; - case VK_EVENT_RESET: - return false; - default: - throw vk::Exception(result); - } + scheduler.Wait(wait_tick); } VKFenceManager::VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, Tegra::MemoryManager& memory_manager_, TextureCache& texture_cache_, VKBufferCache& buffer_cache_, VKQueryCache& query_cache_, - const Device& device_, VKScheduler& scheduler_) + VKScheduler& scheduler_) : GenericFenceManager{rasterizer_, gpu_, texture_cache_, buffer_cache_, query_cache_}, - device{device_}, scheduler{scheduler_} {} + scheduler{scheduler_} {} Fence VKFenceManager::CreateFence(u32 value, bool is_stubbed) { - return std::make_shared<InnerFence>(device, scheduler, value, is_stubbed); + return std::make_shared<InnerFence>(scheduler, value, is_stubbed); } Fence VKFenceManager::CreateFence(GPUVAddr addr, u32 value, bool is_stubbed) { - return std::make_shared<InnerFence>(device, scheduler, addr, value, is_stubbed); + return std::make_shared<InnerFence>(scheduler, addr, value, is_stubbed); } void VKFenceManager::QueueFence(Fence& fence) { diff --git a/src/video_core/renderer_vulkan/vk_fence_manager.h b/src/video_core/renderer_vulkan/vk_fence_manager.h index 6b51e4587..9c5e5aa8f 100644 --- a/src/video_core/renderer_vulkan/vk_fence_manager.h +++ b/src/video_core/renderer_vulkan/vk_fence_manager.h @@ -28,10 +28,8 @@ class VKScheduler; class InnerFence : public VideoCommon::FenceBase { public: - explicit InnerFence(const Device& device_, VKScheduler& scheduler_, u32 payload_, - bool is_stubbed_); - explicit InnerFence(const Device& device_, VKScheduler& scheduler_, GPUVAddr address_, - u32 payload_, bool is_stubbed_); + explicit InnerFence(VKScheduler& scheduler_, u32 payload_, bool is_stubbed_); + explicit InnerFence(VKScheduler& scheduler_, GPUVAddr address_, u32 payload_, bool is_stubbed_); ~InnerFence(); void Queue(); @@ -41,12 +39,8 @@ public: void Wait(); private: - bool IsEventSignalled() const; - - const Device& device; VKScheduler& scheduler; - vk::Event event; - u64 ticks = 0; + u64 wait_tick = 0; }; using Fence = std::shared_ptr<InnerFence>; @@ -58,7 +52,7 @@ public: explicit VKFenceManager(VideoCore::RasterizerInterface& rasterizer_, Tegra::GPU& gpu_, Tegra::MemoryManager& memory_manager_, TextureCache& texture_cache_, VKBufferCache& buffer_cache_, VKQueryCache& query_cache_, - const Device& device_, VKScheduler& scheduler_); + VKScheduler& scheduler_); protected: Fence CreateFence(u32 value, bool is_stubbed) override; @@ -68,7 +62,6 @@ protected: void WaitFence(Fence& fence) override; private: - const Device& device; VKScheduler& scheduler; }; diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.cpp b/src/video_core/renderer_vulkan/vk_memory_manager.cpp deleted file mode 100644 index a6abd0eee..000000000 --- a/src/video_core/renderer_vulkan/vk_memory_manager.cpp +++ /dev/null @@ -1,230 +0,0 @@ -// Copyright 2018 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <algorithm> -#include <optional> -#include <tuple> -#include <vector> - -#include "common/alignment.h" -#include "common/assert.h" -#include "common/common_types.h" -#include "common/logging/log.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" -#include "video_core/vulkan_common/vulkan_device.h" -#include "video_core/vulkan_common/vulkan_wrapper.h" - -namespace Vulkan { - -namespace { - -u64 GetAllocationChunkSize(u64 required_size) { - static constexpr u64 sizes[] = {16ULL << 20, 32ULL << 20, 64ULL << 20, 128ULL << 20}; - auto it = std::lower_bound(std::begin(sizes), std::end(sizes), required_size); - return it != std::end(sizes) ? *it : Common::AlignUp(required_size, 256ULL << 20); -} - -} // Anonymous namespace - -class VKMemoryAllocation final { -public: - explicit VKMemoryAllocation(const Device& device_, vk::DeviceMemory memory_, - VkMemoryPropertyFlags properties_, u64 allocation_size_, u32 type_) - : device{device_}, memory{std::move(memory_)}, properties{properties_}, - allocation_size{allocation_size_}, shifted_type{ShiftType(type_)} {} - - VKMemoryCommit Commit(VkDeviceSize commit_size, VkDeviceSize alignment) { - auto found = TryFindFreeSection(free_iterator, allocation_size, - static_cast<u64>(commit_size), static_cast<u64>(alignment)); - if (!found) { - found = TryFindFreeSection(0, free_iterator, static_cast<u64>(commit_size), - static_cast<u64>(alignment)); - if (!found) { - // Signal out of memory, it'll try to do more allocations. - return nullptr; - } - } - auto commit = std::make_unique<VKMemoryCommitImpl>(device, this, memory, *found, - *found + commit_size); - commits.push_back(commit.get()); - - // Last commit's address is highly probable to be free. - free_iterator = *found + commit_size; - - return commit; - } - - void Free(const VKMemoryCommitImpl* commit) { - ASSERT(commit); - - const auto it = std::find(std::begin(commits), std::end(commits), commit); - if (it == commits.end()) { - UNREACHABLE_MSG("Freeing unallocated commit!"); - return; - } - commits.erase(it); - } - - /// Returns whether this allocation is compatible with the arguments. - bool IsCompatible(VkMemoryPropertyFlags wanted_properties, u32 type_mask) const { - return (wanted_properties & properties) && (type_mask & shifted_type) != 0; - } - -private: - static constexpr u32 ShiftType(u32 type) { - return 1U << type; - } - - /// A memory allocator, it may return a free region between "start" and "end" with the solicited - /// requirements. - std::optional<u64> TryFindFreeSection(u64 start, u64 end, u64 size, u64 alignment) const { - u64 iterator = Common::AlignUp(start, alignment); - while (iterator + size <= end) { - const u64 try_left = iterator; - const u64 try_right = try_left + size; - - bool overlap = false; - for (const auto& commit : commits) { - const auto [commit_left, commit_right] = commit->interval; - if (try_left < commit_right && commit_left < try_right) { - // There's an overlap, continue the search where the overlapping commit ends. - iterator = Common::AlignUp(commit_right, alignment); - overlap = true; - break; - } - } - if (!overlap) { - // A free address has been found. - return try_left; - } - } - - // No free regions where found, return an empty optional. - return std::nullopt; - } - - const Device& device; ///< Vulkan device. - const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. - const VkMemoryPropertyFlags properties; ///< Vulkan properties. - const u64 allocation_size; ///< Size of this allocation. - const u32 shifted_type; ///< Stored Vulkan type of this allocation, shifted. - - /// Hints where the next free region is likely going to be. - u64 free_iterator{}; - - /// Stores all commits done from this allocation. - std::vector<const VKMemoryCommitImpl*> commits; -}; - -VKMemoryManager::VKMemoryManager(const Device& device_) - : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()} {} - -VKMemoryManager::~VKMemoryManager() = default; - -VKMemoryCommit VKMemoryManager::Commit(const VkMemoryRequirements& requirements, - bool host_visible) { - const u64 chunk_size = GetAllocationChunkSize(requirements.size); - - // When a host visible commit is asked, search for host visible and coherent, otherwise search - // for a fast device local type. - const VkMemoryPropertyFlags wanted_properties = - host_visible ? VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT - : VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; - - if (auto commit = TryAllocCommit(requirements, wanted_properties)) { - return commit; - } - - // Commit has failed, allocate more memory. - if (!AllocMemory(wanted_properties, requirements.memoryTypeBits, chunk_size)) { - // TODO(Rodrigo): Handle these situations in some way like flushing to guest memory. - // Allocation has failed, panic. - UNREACHABLE_MSG("Ran out of VRAM!"); - return {}; - } - - // Commit again, this time it won't fail since there's a fresh allocation above. If it does, - // there's a bug. - auto commit = TryAllocCommit(requirements, wanted_properties); - ASSERT(commit); - return commit; -} - -VKMemoryCommit VKMemoryManager::Commit(const vk::Buffer& buffer, bool host_visible) { - auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), host_visible); - buffer.BindMemory(commit->GetMemory(), commit->GetOffset()); - return commit; -} - -VKMemoryCommit VKMemoryManager::Commit(const vk::Image& image, bool host_visible) { - auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), host_visible); - image.BindMemory(commit->GetMemory(), commit->GetOffset()); - return commit; -} - -bool VKMemoryManager::AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, - u64 size) { - const u32 type = [&] { - for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { - const auto flags = properties.memoryTypes[type_index].propertyFlags; - if ((type_mask & (1U << type_index)) && (flags & wanted_properties)) { - // The type matches in type and in the wanted properties. - return type_index; - } - } - UNREACHABLE_MSG("Couldn't find a compatible memory type!"); - return 0U; - }(); - - // Try to allocate found type. - vk::DeviceMemory memory = device.GetLogical().TryAllocateMemory({ - .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, - .pNext = nullptr, - .allocationSize = size, - .memoryTypeIndex = type, - }); - if (!memory) { - LOG_CRITICAL(Render_Vulkan, "Device allocation failed!"); - return false; - } - - allocations.push_back(std::make_unique<VKMemoryAllocation>(device, std::move(memory), - wanted_properties, size, type)); - return true; -} - -VKMemoryCommit VKMemoryManager::TryAllocCommit(const VkMemoryRequirements& requirements, - VkMemoryPropertyFlags wanted_properties) { - for (auto& allocation : allocations) { - if (!allocation->IsCompatible(wanted_properties, requirements.memoryTypeBits)) { - continue; - } - if (auto commit = allocation->Commit(requirements.size, requirements.alignment)) { - return commit; - } - } - return {}; -} - -VKMemoryCommitImpl::VKMemoryCommitImpl(const Device& device_, VKMemoryAllocation* allocation_, - const vk::DeviceMemory& memory_, u64 begin_, u64 end_) - : device{device_}, memory{memory_}, interval{begin_, end_}, allocation{allocation_} {} - -VKMemoryCommitImpl::~VKMemoryCommitImpl() { - allocation->Free(this); -} - -MemoryMap VKMemoryCommitImpl::Map(u64 size, u64 offset_) const { - return MemoryMap(this, std::span<u8>(memory.Map(interval.first + offset_, size), size)); -} - -void VKMemoryCommitImpl::Unmap() const { - memory.Unmap(); -} - -MemoryMap VKMemoryCommitImpl::Map() const { - return Map(interval.second - interval.first); -} - -} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_memory_manager.h b/src/video_core/renderer_vulkan/vk_memory_manager.h deleted file mode 100644 index 2452bca4e..000000000 --- a/src/video_core/renderer_vulkan/vk_memory_manager.h +++ /dev/null @@ -1,132 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <span> -#include <utility> -#include <vector> -#include "common/common_types.h" -#include "video_core/vulkan_common/vulkan_wrapper.h" - -namespace Vulkan { - -class Device; -class MemoryMap; -class VKMemoryAllocation; -class VKMemoryCommitImpl; - -using VKMemoryCommit = std::unique_ptr<VKMemoryCommitImpl>; - -class VKMemoryManager final { -public: - explicit VKMemoryManager(const Device& device_); - VKMemoryManager(const VKMemoryManager&) = delete; - ~VKMemoryManager(); - - /** - * Commits a memory with the specified requeriments. - * @param requirements Requirements returned from a Vulkan call. - * @param host_visible Signals the allocator that it *must* use host visible and coherent - * memory. When passing false, it will try to allocate device local memory. - * @returns A memory commit. - */ - VKMemoryCommit Commit(const VkMemoryRequirements& requirements, bool host_visible); - - /// Commits memory required by the buffer and binds it. - VKMemoryCommit Commit(const vk::Buffer& buffer, bool host_visible); - - /// Commits memory required by the image and binds it. - VKMemoryCommit Commit(const vk::Image& image, bool host_visible); - -private: - /// Allocates a chunk of memory. - bool AllocMemory(VkMemoryPropertyFlags wanted_properties, u32 type_mask, u64 size); - - /// Tries to allocate a memory commit. - VKMemoryCommit TryAllocCommit(const VkMemoryRequirements& requirements, - VkMemoryPropertyFlags wanted_properties); - - const Device& device; ///< Device handler. - const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. - std::vector<std::unique_ptr<VKMemoryAllocation>> allocations; ///< Current allocations. -}; - -class VKMemoryCommitImpl final { - friend VKMemoryAllocation; - friend MemoryMap; - -public: - explicit VKMemoryCommitImpl(const Device& device_, VKMemoryAllocation* allocation_, - const vk::DeviceMemory& memory_, u64 begin_, u64 end_); - ~VKMemoryCommitImpl(); - - /// Maps a memory region and returns a pointer to it. - /// It's illegal to have more than one memory map at the same time. - MemoryMap Map(u64 size, u64 offset = 0) const; - - /// Maps the whole commit and returns a pointer to it. - /// It's illegal to have more than one memory map at the same time. - MemoryMap Map() const; - - /// Returns the Vulkan memory handler. - VkDeviceMemory GetMemory() const { - return *memory; - } - - /// Returns the start position of the commit relative to the allocation. - VkDeviceSize GetOffset() const { - return static_cast<VkDeviceSize>(interval.first); - } - -private: - /// Unmaps memory. - void Unmap() const; - - const Device& device; ///< Vulkan device. - const vk::DeviceMemory& memory; ///< Vulkan device memory handler. - std::pair<u64, u64> interval{}; ///< Interval where the commit exists. - VKMemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. -}; - -/// Holds ownership of a memory map. -class MemoryMap final { -public: - explicit MemoryMap(const VKMemoryCommitImpl* commit_, std::span<u8> span_) - : commit{commit_}, span{span_} {} - - ~MemoryMap() { - if (commit) { - commit->Unmap(); - } - } - - /// Prematurely releases the memory map. - void Release() { - commit->Unmap(); - commit = nullptr; - } - - /// Returns a span to the memory map. - [[nodiscard]] std::span<u8> Span() const noexcept { - return span; - } - - /// Returns the address of the memory map. - [[nodiscard]] u8* Address() const noexcept { - return span.data(); - } - - /// Returns the address of the memory map; - [[nodiscard]] operator u8*() const noexcept { - return span.data(); - } - -private: - const VKMemoryCommitImpl* commit{}; ///< Mapped memory commit. - std::span<u8> span; ///< Address to the mapped memory. -}; - -} // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.cpp b/src/video_core/renderer_vulkan/vk_rasterizer.cpp index 93fbea510..f0a111829 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.cpp +++ b/src/video_core/renderer_vulkan/vk_rasterizer.cpp @@ -409,27 +409,26 @@ void RasterizerVulkan::DrawParameters::Draw(vk::CommandBuffer cmdbuf) const { RasterizerVulkan::RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_, - const Device& device_, VKMemoryManager& memory_manager_, + const Device& device_, MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, VKScheduler& scheduler_) : RasterizerAccelerated{cpu_memory_}, gpu{gpu_}, gpu_memory{gpu_memory_}, maxwell3d{gpu.Maxwell3D()}, kepler_compute{gpu.KeplerCompute()}, - screen_info{screen_info_}, device{device_}, memory_manager{memory_manager_}, + screen_info{screen_info_}, device{device_}, memory_allocator{memory_allocator_}, state_tracker{state_tracker_}, scheduler{scheduler_}, stream_buffer(device, scheduler), - staging_pool(device, memory_manager, scheduler), descriptor_pool(device, scheduler), + staging_pool(device, memory_allocator, scheduler), descriptor_pool(device, scheduler), update_descriptor_queue(device, scheduler), blit_image(device, scheduler, state_tracker, descriptor_pool), quad_array_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), quad_indexed_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), uint8_pass(device, scheduler, descriptor_pool, staging_pool, update_descriptor_queue), - texture_cache_runtime{device, scheduler, memory_manager, staging_pool, blit_image}, + texture_cache_runtime{device, scheduler, memory_allocator, staging_pool, blit_image}, texture_cache(texture_cache_runtime, *this, maxwell3d, kepler_compute, gpu_memory), pipeline_cache(*this, gpu, maxwell3d, kepler_compute, gpu_memory, device, scheduler, descriptor_pool, update_descriptor_queue), - buffer_cache(*this, gpu_memory, cpu_memory_, device, memory_manager, scheduler, stream_buffer, - staging_pool), + buffer_cache(*this, gpu_memory, cpu_memory_, device, memory_allocator, scheduler, + stream_buffer, staging_pool), query_cache{*this, maxwell3d, gpu_memory, device, scheduler}, - fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, device, - scheduler), + fence_manager(*this, gpu, gpu_memory, texture_cache, buffer_cache, query_cache, scheduler), wfi_event(device.GetLogical().CreateEvent()), async_shaders(emu_window_) { scheduler.SetQueryCache(query_cache); if (device.UseAsynchronousShaders()) { @@ -1446,7 +1445,7 @@ VkBuffer RasterizerVulkan::DefaultBuffer() { .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, }); - default_buffer_commit = memory_manager.Commit(default_buffer, false); + default_buffer_commit = memory_allocator.Commit(default_buffer, MemoryUsage::DeviceLocal); scheduler.RequestOutsideRenderPassOperationContext(); scheduler.Record([buffer = *default_buffer](vk::CommandBuffer cmdbuf) { diff --git a/src/video_core/renderer_vulkan/vk_rasterizer.h b/src/video_core/renderer_vulkan/vk_rasterizer.h index 4695718e9..8e261b9bd 100644 --- a/src/video_core/renderer_vulkan/vk_rasterizer.h +++ b/src/video_core/renderer_vulkan/vk_rasterizer.h @@ -21,7 +21,6 @@ #include "video_core/renderer_vulkan/vk_compute_pass.h" #include "video_core/renderer_vulkan/vk_descriptor_pool.h" #include "video_core/renderer_vulkan/vk_fence_manager.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_pipeline_cache.h" #include "video_core/renderer_vulkan/vk_query_cache.h" #include "video_core/renderer_vulkan/vk_scheduler.h" @@ -30,6 +29,7 @@ #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/renderer_vulkan/vk_update_descriptor.h" #include "video_core/shader/async_shaders.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Core { @@ -56,7 +56,7 @@ public: explicit RasterizerVulkan(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, Tegra::MemoryManager& gpu_memory_, Core::Memory::Memory& cpu_memory_, VKScreenInfo& screen_info_, const Device& device_, - VKMemoryManager& memory_manager_, StateTracker& state_tracker_, + MemoryAllocator& memory_allocator_, StateTracker& state_tracker_, VKScheduler& scheduler_); ~RasterizerVulkan() override; @@ -213,12 +213,12 @@ private: VKScreenInfo& screen_info; const Device& device; - VKMemoryManager& memory_manager; + MemoryAllocator& memory_allocator; StateTracker& state_tracker; VKScheduler& scheduler; VKStreamBuffer stream_buffer; - VKStagingBufferPool staging_pool; + StagingBufferPool staging_pool; VKDescriptorPool descriptor_pool; VKUpdateDescriptorQueue update_descriptor_queue; BlitImageHelper blit_image; @@ -234,7 +234,7 @@ private: VKFenceManager fence_manager; vk::Buffer default_buffer; - VKMemoryCommit default_buffer_commit; + MemoryCommit default_buffer_commit; vk::Event wfi_event; VideoCommon::Shader::AsyncShaders async_shaders; diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp index 1e0b8b922..97fd41cc1 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.cpp @@ -3,10 +3,12 @@ // Refer to the license.txt file included. #include <algorithm> -#include <unordered_map> #include <utility> #include <vector> +#include <fmt/format.h> + +#include "common/assert.h" #include "common/bit_util.h" #include "common/common_types.h" #include "video_core/renderer_vulkan/vk_scheduler.h" @@ -16,45 +18,51 @@ namespace Vulkan { -VKStagingBufferPool::StagingBuffer::StagingBuffer(std::unique_ptr<VKBuffer> buffer_) - : buffer{std::move(buffer_)} {} - -VKStagingBufferPool::VKStagingBufferPool(const Device& device_, VKMemoryManager& memory_manager_, - VKScheduler& scheduler_) - : device{device_}, memory_manager{memory_manager_}, scheduler{scheduler_} {} +StagingBufferPool::StagingBufferPool(const Device& device_, MemoryAllocator& memory_allocator_, + VKScheduler& scheduler_) + : device{device_}, memory_allocator{memory_allocator_}, scheduler{scheduler_} {} -VKStagingBufferPool::~VKStagingBufferPool() = default; +StagingBufferPool::~StagingBufferPool() = default; -VKBuffer& VKStagingBufferPool::GetUnusedBuffer(std::size_t size, bool host_visible) { - if (const auto buffer = TryGetReservedBuffer(size, host_visible)) { - return *buffer; +StagingBufferRef StagingBufferPool::Request(size_t size, MemoryUsage usage) { + if (const std::optional<StagingBufferRef> ref = TryGetReservedBuffer(size, usage)) { + return *ref; } - return CreateStagingBuffer(size, host_visible); + return CreateStagingBuffer(size, usage); } -void VKStagingBufferPool::TickFrame() { - current_delete_level = (current_delete_level + 1) % NumLevels; +void StagingBufferPool::TickFrame() { + current_delete_level = (current_delete_level + 1) % NUM_LEVELS; - ReleaseCache(true); - ReleaseCache(false); + ReleaseCache(MemoryUsage::DeviceLocal); + ReleaseCache(MemoryUsage::Upload); + ReleaseCache(MemoryUsage::Download); } -VKBuffer* VKStagingBufferPool::TryGetReservedBuffer(std::size_t size, bool host_visible) { - for (StagingBuffer& entry : GetCache(host_visible)[Common::Log2Ceil64(size)].entries) { - if (!scheduler.IsFree(entry.tick)) { - continue; +std::optional<StagingBufferRef> StagingBufferPool::TryGetReservedBuffer(size_t size, + MemoryUsage usage) { + StagingBuffers& cache_level = GetCache(usage)[Common::Log2Ceil64(size)]; + + const auto is_free = [this](const StagingBuffer& entry) { + return scheduler.IsFree(entry.tick); + }; + auto& entries = cache_level.entries; + const auto hint_it = entries.begin() + cache_level.iterate_index; + auto it = std::find_if(entries.begin() + cache_level.iterate_index, entries.end(), is_free); + if (it == entries.end()) { + it = std::find_if(entries.begin(), hint_it, is_free); + if (it == hint_it) { + return std::nullopt; } - entry.tick = scheduler.CurrentTick(); - return &*entry.buffer; } - return nullptr; + cache_level.iterate_index = std::distance(entries.begin(), it) + 1; + it->tick = scheduler.CurrentTick(); + return it->Ref(); } -VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_visible) { +StagingBufferRef StagingBufferPool::CreateStagingBuffer(size_t size, MemoryUsage usage) { const u32 log2 = Common::Log2Ceil64(size); - - auto buffer = std::make_unique<VKBuffer>(); - buffer->handle = device.GetLogical().CreateBuffer({ + vk::Buffer buffer = device.GetLogical().CreateBuffer({ .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .pNext = nullptr, .flags = 0, @@ -66,49 +74,63 @@ VKBuffer& VKStagingBufferPool::CreateStagingBuffer(std::size_t size, bool host_v .queueFamilyIndexCount = 0, .pQueueFamilyIndices = nullptr, }); - buffer->commit = memory_manager.Commit(buffer->handle, host_visible); - - std::vector<StagingBuffer>& entries = GetCache(host_visible)[log2].entries; - StagingBuffer& entry = entries.emplace_back(std::move(buffer)); - entry.tick = scheduler.CurrentTick(); - return *entry.buffer; -} - -VKStagingBufferPool::StagingBuffersCache& VKStagingBufferPool::GetCache(bool host_visible) { - return host_visible ? host_staging_buffers : device_staging_buffers; + if (device.HasDebuggingToolAttached()) { + ++buffer_index; + buffer.SetObjectNameEXT(fmt::format("Staging Buffer {}", buffer_index).c_str()); + } + MemoryCommit commit = memory_allocator.Commit(buffer, usage); + const std::span<u8> mapped_span = IsHostVisible(usage) ? commit.Map() : std::span<u8>{}; + + StagingBuffer& entry = GetCache(usage)[log2].entries.emplace_back(StagingBuffer{ + .buffer = std::move(buffer), + .commit = std::move(commit), + .mapped_span = mapped_span, + .tick = scheduler.CurrentTick(), + }); + return entry.Ref(); } -void VKStagingBufferPool::ReleaseCache(bool host_visible) { - auto& cache = GetCache(host_visible); - const u64 size = ReleaseLevel(cache, current_delete_level); - if (size == 0) { - return; +StagingBufferPool::StagingBuffersCache& StagingBufferPool::GetCache(MemoryUsage usage) { + switch (usage) { + case MemoryUsage::DeviceLocal: + return device_local_cache; + case MemoryUsage::Upload: + return upload_cache; + case MemoryUsage::Download: + return download_cache; + default: + UNREACHABLE_MSG("Invalid memory usage={}", usage); + return upload_cache; } } -u64 VKStagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, std::size_t log2) { - static constexpr std::size_t deletions_per_tick = 16; +void StagingBufferPool::ReleaseCache(MemoryUsage usage) { + ReleaseLevel(GetCache(usage), current_delete_level); +} +void StagingBufferPool::ReleaseLevel(StagingBuffersCache& cache, size_t log2) { + constexpr size_t deletions_per_tick = 16; auto& staging = cache[log2]; auto& entries = staging.entries; - const std::size_t old_size = entries.size(); + const size_t old_size = entries.size(); const auto is_deleteable = [this](const StagingBuffer& entry) { return scheduler.IsFree(entry.tick); }; - const std::size_t begin_offset = staging.delete_index; - const std::size_t end_offset = std::min(begin_offset + deletions_per_tick, old_size); - const auto begin = std::begin(entries) + begin_offset; - const auto end = std::begin(entries) + end_offset; + const size_t begin_offset = staging.delete_index; + const size_t end_offset = std::min(begin_offset + deletions_per_tick, old_size); + const auto begin = entries.begin() + begin_offset; + const auto end = entries.begin() + end_offset; entries.erase(std::remove_if(begin, end, is_deleteable), end); - const std::size_t new_size = entries.size(); + const size_t new_size = entries.size(); staging.delete_index += deletions_per_tick; if (staging.delete_index >= new_size) { staging.delete_index = 0; } - - return (1ULL << log2) * (old_size - new_size); + if (staging.iterate_index > new_size) { + staging.iterate_index = 0; + } } } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h index 90dadcbbe..d42918a47 100644 --- a/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h +++ b/src/video_core/renderer_vulkan/vk_staging_buffer_pool.h @@ -9,7 +9,7 @@ #include "common/common_types.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { @@ -17,55 +17,65 @@ namespace Vulkan { class Device; class VKScheduler; -struct VKBuffer final { - vk::Buffer handle; - VKMemoryCommit commit; +struct StagingBufferRef { + VkBuffer buffer; + std::span<u8> mapped_span; }; -class VKStagingBufferPool final { +class StagingBufferPool { public: - explicit VKStagingBufferPool(const Device& device, VKMemoryManager& memory_manager, - VKScheduler& scheduler); - ~VKStagingBufferPool(); + explicit StagingBufferPool(const Device& device, MemoryAllocator& memory_allocator, + VKScheduler& scheduler); + ~StagingBufferPool(); - VKBuffer& GetUnusedBuffer(std::size_t size, bool host_visible); + StagingBufferRef Request(size_t size, MemoryUsage usage); void TickFrame(); private: - struct StagingBuffer final { - explicit StagingBuffer(std::unique_ptr<VKBuffer> buffer); - - std::unique_ptr<VKBuffer> buffer; + struct StagingBuffer { + vk::Buffer buffer; + MemoryCommit commit; + std::span<u8> mapped_span; u64 tick = 0; + + StagingBufferRef Ref() const noexcept { + return { + .buffer = *buffer, + .mapped_span = mapped_span, + }; + } }; - struct StagingBuffers final { + struct StagingBuffers { std::vector<StagingBuffer> entries; - std::size_t delete_index = 0; + size_t delete_index = 0; + size_t iterate_index = 0; }; - static constexpr std::size_t NumLevels = sizeof(std::size_t) * CHAR_BIT; - using StagingBuffersCache = std::array<StagingBuffers, NumLevels>; + static constexpr size_t NUM_LEVELS = sizeof(size_t) * CHAR_BIT; + using StagingBuffersCache = std::array<StagingBuffers, NUM_LEVELS>; - VKBuffer* TryGetReservedBuffer(std::size_t size, bool host_visible); + std::optional<StagingBufferRef> TryGetReservedBuffer(size_t size, MemoryUsage usage); - VKBuffer& CreateStagingBuffer(std::size_t size, bool host_visible); + StagingBufferRef CreateStagingBuffer(size_t size, MemoryUsage usage); - StagingBuffersCache& GetCache(bool host_visible); + StagingBuffersCache& GetCache(MemoryUsage usage); - void ReleaseCache(bool host_visible); + void ReleaseCache(MemoryUsage usage); - u64 ReleaseLevel(StagingBuffersCache& cache, std::size_t log2); + void ReleaseLevel(StagingBuffersCache& cache, size_t log2); const Device& device; - VKMemoryManager& memory_manager; + MemoryAllocator& memory_allocator; VKScheduler& scheduler; - StagingBuffersCache host_staging_buffers; - StagingBuffersCache device_staging_buffers; + StagingBuffersCache device_local_cache; + StagingBuffersCache upload_cache; + StagingBuffersCache download_cache; - std::size_t current_delete_level = 0; + size_t current_delete_level = 0; + u64 buffer_index = 0; }; } // namespace Vulkan diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.cpp b/src/video_core/renderer_vulkan/vk_texture_cache.cpp index bd11de012..ab14922d7 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.cpp +++ b/src/video_core/renderer_vulkan/vk_texture_cache.cpp @@ -10,12 +10,12 @@ #include "video_core/engines/fermi_2d.h" #include "video_core/renderer_vulkan/blit_image.h" #include "video_core/renderer_vulkan/maxwell_to_vk.h" -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/renderer_vulkan/vk_rasterizer.h" #include "video_core/renderer_vulkan/vk_scheduler.h" #include "video_core/renderer_vulkan/vk_staging_buffer_pool.h" #include "video_core/renderer_vulkan/vk_texture_cache.h" #include "video_core/vulkan_common/vulkan_device.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { @@ -554,10 +554,18 @@ void TextureCacheRuntime::Finish() { } ImageBufferMap TextureCacheRuntime::MapUploadBuffer(size_t size) { - const auto& buffer = staging_buffer_pool.GetUnusedBuffer(size, true); - return ImageBufferMap{ - .handle = *buffer.handle, - .map = buffer.commit->Map(size), + const auto staging_ref = staging_buffer_pool.Request(size, MemoryUsage::Upload); + return { + .handle = staging_ref.buffer, + .span = staging_ref.mapped_span, + }; +} + +ImageBufferMap TextureCacheRuntime::MapDownloadBuffer(size_t size) { + const auto staging_ref = staging_buffer_pool.Request(size, MemoryUsage::Download); + return { + .handle = staging_ref.buffer, + .span = staging_ref.mapped_span, }; } @@ -788,9 +796,9 @@ Image::Image(TextureCacheRuntime& runtime, const ImageInfo& info_, GPUVAddr gpu_ image(MakeImage(runtime.device, info)), buffer(MakeBuffer(runtime.device, info)), aspect_mask(ImageAspectMask(info.format)) { if (image) { - commit = runtime.memory_manager.Commit(image, false); + commit = runtime.memory_allocator.Commit(image, MemoryUsage::DeviceLocal); } else { - commit = runtime.memory_manager.Commit(buffer, false); + commit = runtime.memory_allocator.Commit(buffer, MemoryUsage::DeviceLocal); } if (IsPixelFormatASTC(info.format) && !runtime.device.IsOptimalAstcSupported()) { flags |= VideoCommon::ImageFlagBits::Converted; diff --git a/src/video_core/renderer_vulkan/vk_texture_cache.h b/src/video_core/renderer_vulkan/vk_texture_cache.h index 92a7aad8b..a55d405d1 100644 --- a/src/video_core/renderer_vulkan/vk_texture_cache.h +++ b/src/video_core/renderer_vulkan/vk_texture_cache.h @@ -7,8 +7,8 @@ #include <compare> #include <span> -#include "video_core/renderer_vulkan/vk_memory_manager.h" #include "video_core/texture_cache/texture_cache.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" #include "video_core/vulkan_common/vulkan_wrapper.h" namespace Vulkan { @@ -19,14 +19,13 @@ using VideoCommon::Offset2D; using VideoCommon::RenderTargets; using VideoCore::Surface::PixelFormat; -class VKScheduler; -class VKStagingBufferPool; - class BlitImageHelper; class Device; class Image; class ImageView; class Framebuffer; +class StagingBufferPool; +class VKScheduler; struct RenderPassKey { constexpr auto operator<=>(const RenderPassKey&) const noexcept = default; @@ -60,18 +59,18 @@ struct ImageBufferMap { } [[nodiscard]] std::span<u8> Span() const noexcept { - return map.Span(); + return span; } VkBuffer handle; - MemoryMap map; + std::span<u8> span; }; struct TextureCacheRuntime { const Device& device; VKScheduler& scheduler; - VKMemoryManager& memory_manager; - VKStagingBufferPool& staging_buffer_pool; + MemoryAllocator& memory_allocator; + StagingBufferPool& staging_buffer_pool; BlitImageHelper& blit_image_helper; std::unordered_map<RenderPassKey, vk::RenderPass> renderpass_cache; @@ -79,10 +78,7 @@ struct TextureCacheRuntime { [[nodiscard]] ImageBufferMap MapUploadBuffer(size_t size); - [[nodiscard]] ImageBufferMap MapDownloadBuffer(size_t size) { - // TODO: Have a special function for this - return MapUploadBuffer(size); - } + [[nodiscard]] ImageBufferMap MapDownloadBuffer(size_t size); void BlitImage(Framebuffer* dst_framebuffer, ImageView& dst, ImageView& src, const std::array<Offset2D, 2>& dst_region, @@ -141,7 +137,7 @@ private: VKScheduler* scheduler; vk::Image image; vk::Buffer buffer; - VKMemoryCommit commit; + MemoryCommit commit; VkImageAspectFlags aspect_mask = 0; bool initialized = false; }; diff --git a/src/video_core/texture_cache/accelerated_swizzle.cpp b/src/video_core/texture_cache/accelerated_swizzle.cpp index a4fc1184b..15585caeb 100644 --- a/src/video_core/texture_cache/accelerated_swizzle.cpp +++ b/src/video_core/texture_cache/accelerated_swizzle.cpp @@ -27,7 +27,7 @@ BlockLinearSwizzle2DParams MakeBlockLinearSwizzle2DParams(const SwizzleParameter const Extent3D num_tiles = swizzle.num_tiles; const u32 bytes_per_block = BytesPerBlock(info.format); const u32 stride_alignment = CalculateLevelStrideAlignment(info, swizzle.level); - const u32 stride = Common::AlignBits(num_tiles.width, stride_alignment) * bytes_per_block; + const u32 stride = Common::AlignUpLog2(num_tiles.width, stride_alignment) * bytes_per_block; const u32 gobs_in_x = Common::DivCeilLog2(stride, GOB_SIZE_X_SHIFT); return BlockLinearSwizzle2DParams{ .origin{0, 0, 0}, @@ -47,7 +47,7 @@ BlockLinearSwizzle3DParams MakeBlockLinearSwizzle3DParams(const SwizzleParameter const Extent3D num_tiles = swizzle.num_tiles; const u32 bytes_per_block = BytesPerBlock(info.format); const u32 stride_alignment = CalculateLevelStrideAlignment(info, swizzle.level); - const u32 stride = Common::AlignBits(num_tiles.width, stride_alignment) * bytes_per_block; + const u32 stride = Common::AlignUpLog2(num_tiles.width, stride_alignment) * bytes_per_block; const u32 gobs_in_x = (stride + GOB_SIZE_X - 1) >> GOB_SIZE_X_SHIFT; const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block.height + block.depth); diff --git a/src/video_core/texture_cache/util.cpp b/src/video_core/texture_cache/util.cpp index 279932778..ce8fcfe0a 100644 --- a/src/video_core/texture_cache/util.cpp +++ b/src/video_core/texture_cache/util.cpp @@ -279,7 +279,7 @@ template <u32 GOB_EXTENT> const bool is_small = IsSmallerThanGobSize(blocks, gob, info.block.depth); const u32 alignment = is_small ? 0 : info.tile_width_spacing; return Extent2D{ - .width = Common::AlignBits(gobs.width, alignment), + .width = Common::AlignUpLog2(gobs.width, alignment), .height = gobs.height, }; } @@ -352,7 +352,7 @@ template <u32 GOB_EXTENT> // https://github.com/Ryujinx/Ryujinx/blob/1c9aba6de1520aea5480c032e0ff5664ac1bb36f/Ryujinx.Graphics.Texture/SizeCalculator.cs#L134 if (tile_width_spacing > 0) { const u32 alignment_log2 = GOB_SIZE_SHIFT + tile_width_spacing + block.height + block.depth; - return Common::AlignBits(size_bytes, alignment_log2); + return Common::AlignUpLog2(size_bytes, alignment_log2); } const u32 aligned_height = Common::AlignUp(size.height, tile_size_y); while (block.height != 0 && aligned_height <= (1U << (block.height - 1)) * GOB_SIZE_Y) { @@ -528,9 +528,9 @@ template <u32 GOB_EXTENT> const u32 alignment = StrideAlignment(num_tiles, info.block, bpp_log2, info.tile_width_spacing); const Extent3D mip_block = AdjustMipBlockSize(num_tiles, info.block, 0); return Extent3D{ - .width = Common::AlignBits(num_tiles.width, alignment), - .height = Common::AlignBits(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height), - .depth = Common::AlignBits(num_tiles.depth, GOB_SIZE_Z_SHIFT + mip_block.depth), + .width = Common::AlignUpLog2(num_tiles.width, alignment), + .height = Common::AlignUpLog2(num_tiles.height, GOB_SIZE_Y_SHIFT + mip_block.height), + .depth = Common::AlignUpLog2(num_tiles.depth, GOB_SIZE_Z_SHIFT + mip_block.depth), }; } diff --git a/src/video_core/textures/astc.cpp b/src/video_core/textures/astc.cpp index acd5bdd78..3625b666c 100644 --- a/src/video_core/textures/astc.cpp +++ b/src/video_core/textures/astc.cpp @@ -42,21 +42,24 @@ constexpr u32 Popcnt(u32 n) { class InputBitStream { public: - constexpr explicit InputBitStream(const u8* ptr, std::size_t start_offset = 0) - : cur_byte{ptr}, next_bit{start_offset % 8} {} + constexpr explicit InputBitStream(std::span<const u8> data, size_t start_offset = 0) + : cur_byte{data.data()}, total_bits{data.size()}, next_bit{start_offset % 8} {} - constexpr std::size_t GetBitsRead() const { + constexpr size_t GetBitsRead() const { return bits_read; } constexpr bool ReadBit() { - const bool bit = (*cur_byte >> next_bit++) & 1; + if (bits_read >= total_bits * 8) { + return 0; + } + const bool bit = ((*cur_byte >> next_bit) & 1) != 0; + ++next_bit; while (next_bit >= 8) { next_bit -= 8; - cur_byte++; + ++cur_byte; } - - bits_read++; + ++bits_read; return bit; } @@ -79,8 +82,9 @@ public: private: const u8* cur_byte; - std::size_t next_bit = 0; - std::size_t bits_read = 0; + size_t total_bits = 0; + size_t next_bit = 0; + size_t bits_read = 0; }; class OutputBitStream { @@ -193,15 +197,15 @@ struct IntegerEncodedValue { }; }; using IntegerEncodedVector = boost::container::static_vector< - IntegerEncodedValue, 64, + IntegerEncodedValue, 256, boost::container::static_vector_options< boost::container::inplace_alignment<alignof(IntegerEncodedValue)>, boost::container::throw_on_overflow<false>>::type>; static void DecodeTritBlock(InputBitStream& bits, IntegerEncodedVector& result, u32 nBitsPerValue) { // Implement the algorithm in section C.2.12 - u32 m[5]; - u32 t[5]; + std::array<u32, 5> m; + std::array<u32, 5> t; u32 T; // Read the trit encoded block according to @@ -866,7 +870,7 @@ public: } }; -static void DecodeColorValues(u32* out, u8* data, const u32* modes, const u32 nPartitions, +static void DecodeColorValues(u32* out, std::span<u8> data, const u32* modes, const u32 nPartitions, const u32 nBitsForColorData) { // First figure out how many color values we have u32 nValues = 0; @@ -898,7 +902,7 @@ static void DecodeColorValues(u32* out, u8* data, const u32* modes, const u32 nP // We now have enough to decode our integer sequence. IntegerEncodedVector decodedColorValues; - InputBitStream colorStream(data); + InputBitStream colorStream(data, 0); DecodeIntegerSequence(decodedColorValues, colorStream, range, nValues); // Once we have the decoded values, we need to dequantize them to the 0-255 range @@ -1441,7 +1445,7 @@ static void ComputeEndpos32s(Pixel& ep1, Pixel& ep2, const u32*& colorValues, static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth, const u32 blockHeight, std::span<u32, 12 * 12> outBuf) { - InputBitStream strm(inBuf.data()); + InputBitStream strm(inBuf); TexelWeightParams weightParams = DecodeBlockInfo(strm); // Was there an error? @@ -1619,15 +1623,16 @@ static void DecompressBlock(std::span<const u8, 16> inBuf, const u32 blockWidth, // Make sure that higher non-texel bits are set to zero const u32 clearByteStart = (weightParams.GetPackedBitSize() >> 3) + 1; - if (clearByteStart > 0) { + if (clearByteStart > 0 && clearByteStart <= texelWeightData.size()) { texelWeightData[clearByteStart - 1] &= static_cast<u8>((1 << (weightParams.GetPackedBitSize() % 8)) - 1); + std::memset(texelWeightData.data() + clearByteStart, 0, + std::min(16U - clearByteStart, 16U)); } - std::memset(texelWeightData.data() + clearByteStart, 0, std::min(16U - clearByteStart, 16U)); IntegerEncodedVector texelWeightValues; - InputBitStream weightStream(texelWeightData.data()); + InputBitStream weightStream(texelWeightData); DecodeIntegerSequence(texelWeightValues, weightStream, weightParams.m_MaxWeight, weightParams.GetNumWeightValues()); diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 9f5181318..62685a183 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp @@ -49,7 +49,7 @@ void Swizzle(std::span<u8> output, std::span<const u8> input, u32 bytes_per_pixe // We can configure here a custom pitch // As it's not exposed 'width * bpp' will be the expected pitch. const u32 pitch = width * bytes_per_pixel; - const u32 stride = Common::AlignBits(width, stride_alignment) * bytes_per_pixel; + const u32 stride = Common::AlignUpLog2(width, stride_alignment) * bytes_per_pixel; const u32 gobs_in_x = Common::DivCeilLog2(stride, GOB_SIZE_X_SHIFT); const u32 block_size = gobs_in_x << (GOB_SIZE_SHIFT + block_height + block_depth); @@ -217,9 +217,9 @@ void SwizzleKepler(const u32 width, const u32 height, const u32 dst_x, const u32 std::size_t CalculateSize(bool tiled, u32 bytes_per_pixel, u32 width, u32 height, u32 depth, u32 block_height, u32 block_depth) { if (tiled) { - const u32 aligned_width = Common::AlignBits(width * bytes_per_pixel, GOB_SIZE_X_SHIFT); - const u32 aligned_height = Common::AlignBits(height, GOB_SIZE_Y_SHIFT + block_height); - const u32 aligned_depth = Common::AlignBits(depth, GOB_SIZE_Z_SHIFT + block_depth); + const u32 aligned_width = Common::AlignUpLog2(width * bytes_per_pixel, GOB_SIZE_X_SHIFT); + const u32 aligned_height = Common::AlignUpLog2(height, GOB_SIZE_Y_SHIFT + block_height); + const u32 aligned_depth = Common::AlignUpLog2(depth, GOB_SIZE_Z_SHIFT + block_depth); return aligned_width * aligned_height * aligned_depth; } else { return width * height * depth * bytes_per_pixel; diff --git a/src/video_core/vulkan_common/vulkan_device.cpp b/src/video_core/vulkan_common/vulkan_device.cpp index 75173324e..37d7b45a3 100644 --- a/src/video_core/vulkan_common/vulkan_device.cpp +++ b/src/video_core/vulkan_common/vulkan_device.cpp @@ -99,8 +99,7 @@ VkFormatFeatureFlags GetFormatFeatures(VkFormatProperties properties, FormatType }); } -std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( - vk::PhysicalDevice physical, const vk::InstanceDispatch& dld) { +std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties(vk::PhysicalDevice physical) { static constexpr std::array formats{ VK_FORMAT_A8B8G8R8_UNORM_PACK32, VK_FORMAT_A8B8G8R8_UINT_PACK32, @@ -210,7 +209,7 @@ std::unordered_map<VkFormat, VkFormatProperties> GetFormatProperties( Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR surface, const vk::InstanceDispatch& dld_) : instance{instance_}, dld{dld_}, physical{physical_}, properties{physical.GetProperties()}, - format_properties{GetFormatProperties(physical, dld)} { + format_properties{GetFormatProperties(physical)} { CheckSuitability(); SetupFamilies(surface); SetupFeatures(); @@ -221,6 +220,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR VkPhysicalDeviceFeatures2 features2{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_FEATURES_2, .pNext = nullptr, + .features{}, }; const void* first_next = &features2; void** next = &features2.pNext; @@ -256,7 +256,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR .shaderTessellationAndGeometryPointSize = false, .shaderImageGatherExtended = true, .shaderStorageImageExtendedFormats = false, - .shaderStorageImageMultisample = true, + .shaderStorageImageMultisample = is_shader_storage_image_multisample, .shaderStorageImageReadWithoutFormat = is_formatless_image_load_supported, .shaderStorageImageWriteWithoutFormat = true, .shaderUniformBufferArrayDynamicIndexing = false, @@ -310,6 +310,7 @@ Device::Device(VkInstance instance_, vk::PhysicalDevice physical_, VkSurfaceKHR VkPhysicalDeviceHostQueryResetFeaturesEXT host_query_reset{ .sType = VK_STRUCTURE_TYPE_PHYSICAL_DEVICE_HOST_QUERY_RESET_FEATURES_EXT, + .pNext = nullptr, .hostQueryReset = true, }; SetNext(next, host_query_reset); @@ -604,7 +605,6 @@ void Device::CheckSuitability() const { std::make_pair(features.occlusionQueryPrecise, "occlusionQueryPrecise"), std::make_pair(features.fragmentStoresAndAtomics, "fragmentStoresAndAtomics"), std::make_pair(features.shaderImageGatherExtended, "shaderImageGatherExtended"), - std::make_pair(features.shaderStorageImageMultisample, "shaderStorageImageMultisample"), std::make_pair(features.shaderStorageImageWriteWithoutFormat, "shaderStorageImageWriteWithoutFormat"), }; @@ -804,6 +804,7 @@ void Device::SetupFamilies(VkSurfaceKHR surface) { void Device::SetupFeatures() { const auto supported_features{physical.GetFeatures()}; is_formatless_image_load_supported = supported_features.shaderStorageImageReadWithoutFormat; + is_shader_storage_image_multisample = supported_features.shaderStorageImageMultisample; is_blit_depth_stencil_supported = TestDepthStencilBlits(); is_optimal_astc_supported = IsOptimalAstcSupported(supported_features); } diff --git a/src/video_core/vulkan_common/vulkan_device.h b/src/video_core/vulkan_common/vulkan_device.h index a973c3ce4..4b66dba7a 100644 --- a/src/video_core/vulkan_common/vulkan_device.h +++ b/src/video_core/vulkan_common/vulkan_device.h @@ -272,23 +272,24 @@ private: bool is_optimal_astc_supported{}; ///< Support for native ASTC. bool is_float16_supported{}; ///< Support for float16 arithmetics. bool is_warp_potentially_bigger{}; ///< Host warp size can be bigger than guest. - bool is_formatless_image_load_supported{}; ///< Support for shader image read without format. - bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil. - bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle. - bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs. - bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. - bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax. - bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. - bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. - bool ext_tooling_info{}; ///< Support for VK_EXT_tooling_info. - bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. - bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. - bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. - bool ext_robustness2{}; ///< Support for VK_EXT_robustness2. - bool ext_shader_stencil_export{}; ///< Support for VK_EXT_shader_stencil_export. - bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config. - bool has_renderdoc{}; ///< Has RenderDoc attached - bool has_nsight_graphics{}; ///< Has Nsight Graphics attached + bool is_formatless_image_load_supported{}; ///< Support for shader image read without format. + bool is_shader_storage_image_multisample{}; ///< Support for image operations on MSAA images. + bool is_blit_depth_stencil_supported{}; ///< Support for blitting from and to depth stencil. + bool nv_viewport_swizzle{}; ///< Support for VK_NV_viewport_swizzle. + bool khr_uniform_buffer_standard_layout{}; ///< Support for std430 on UBOs. + bool ext_index_type_uint8{}; ///< Support for VK_EXT_index_type_uint8. + bool ext_sampler_filter_minmax{}; ///< Support for VK_EXT_sampler_filter_minmax. + bool ext_depth_range_unrestricted{}; ///< Support for VK_EXT_depth_range_unrestricted. + bool ext_shader_viewport_index_layer{}; ///< Support for VK_EXT_shader_viewport_index_layer. + bool ext_tooling_info{}; ///< Support for VK_EXT_tooling_info. + bool ext_transform_feedback{}; ///< Support for VK_EXT_transform_feedback. + bool ext_custom_border_color{}; ///< Support for VK_EXT_custom_border_color. + bool ext_extended_dynamic_state{}; ///< Support for VK_EXT_extended_dynamic_state. + bool ext_robustness2{}; ///< Support for VK_EXT_robustness2. + bool ext_shader_stencil_export{}; ///< Support for VK_EXT_shader_stencil_export. + bool nv_device_diagnostics_config{}; ///< Support for VK_NV_device_diagnostics_config. + bool has_renderdoc{}; ///< Has RenderDoc attached + bool has_nsight_graphics{}; ///< Has Nsight Graphics attached // Asynchronous Graphics Pipeline setting bool use_asynchronous_shaders{}; ///< Setting to use asynchronous shaders/graphics pipeline diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.cpp b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp new file mode 100644 index 000000000..d6eb3af31 --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.cpp @@ -0,0 +1,268 @@ +// Copyright 2018 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#include <algorithm> +#include <bit> +#include <optional> +#include <vector> + +#include "common/alignment.h" +#include "common/assert.h" +#include "common/common_types.h" +#include "common/logging/log.h" +#include "video_core/vulkan_common/vulkan_device.h" +#include "video_core/vulkan_common/vulkan_memory_allocator.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" + +namespace Vulkan { +namespace { +struct Range { + u64 begin; + u64 end; + + [[nodiscard]] bool Contains(u64 iterator, u64 size) const noexcept { + return iterator < end && begin < iterator + size; + } +}; + +[[nodiscard]] u64 AllocationChunkSize(u64 required_size) { + static constexpr std::array sizes{ + 0x1000ULL << 10, 0x1400ULL << 10, 0x1800ULL << 10, 0x1c00ULL << 10, 0x2000ULL << 10, + 0x3200ULL << 10, 0x4000ULL << 10, 0x6000ULL << 10, 0x8000ULL << 10, 0xA000ULL << 10, + 0x10000ULL << 10, 0x18000ULL << 10, 0x20000ULL << 10, + }; + static_assert(std::is_sorted(sizes.begin(), sizes.end())); + + const auto it = std::ranges::lower_bound(sizes, required_size); + return it != sizes.end() ? *it : Common::AlignUp(required_size, 4ULL << 20); +} + +[[nodiscard]] VkMemoryPropertyFlags MemoryUsagePropertyFlags(MemoryUsage usage) { + switch (usage) { + case MemoryUsage::DeviceLocal: + return VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT; + case MemoryUsage::Upload: + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; + case MemoryUsage::Download: + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT | + VK_MEMORY_PROPERTY_HOST_CACHED_BIT; + } + UNREACHABLE_MSG("Invalid memory usage={}", usage); + return VK_MEMORY_PROPERTY_HOST_VISIBLE_BIT | VK_MEMORY_PROPERTY_HOST_COHERENT_BIT; +} +} // Anonymous namespace + +class MemoryAllocation { +public: + explicit MemoryAllocation(const Device& device_, vk::DeviceMemory memory_, + VkMemoryPropertyFlags properties, u64 allocation_size_, u32 type) + : device{device_}, memory{std::move(memory_)}, allocation_size{allocation_size_}, + property_flags{properties}, shifted_memory_type{1U << type} {} + + [[nodiscard]] std::optional<MemoryCommit> Commit(VkDeviceSize size, VkDeviceSize alignment) { + const std::optional<u64> alloc = FindFreeRegion(size, alignment); + if (!alloc) { + // Signal out of memory, it'll try to do more allocations. + return std::nullopt; + } + const Range range{ + .begin = *alloc, + .end = *alloc + size, + }; + commits.insert(std::ranges::upper_bound(commits, *alloc, {}, &Range::begin), range); + return std::make_optional<MemoryCommit>(this, *memory, *alloc, *alloc + size); + } + + void Free(u64 begin) { + const auto it = std::ranges::find(commits, begin, &Range::begin); + ASSERT_MSG(it != commits.end(), "Invalid commit"); + commits.erase(it); + } + + [[nodiscard]] std::span<u8> Map() { + if (memory_mapped_span.empty()) { + u8* const raw_pointer = memory.Map(0, allocation_size); + memory_mapped_span = std::span<u8>(raw_pointer, allocation_size); + } + return memory_mapped_span; + } + + /// Returns whether this allocation is compatible with the arguments. + [[nodiscard]] bool IsCompatible(VkMemoryPropertyFlags flags, u32 type_mask) const { + return (flags & property_flags) && (type_mask & shifted_memory_type) != 0; + } + +private: + [[nodiscard]] static constexpr u32 ShiftType(u32 type) { + return 1U << type; + } + + [[nodiscard]] std::optional<u64> FindFreeRegion(u64 size, u64 alignment) noexcept { + ASSERT(std::has_single_bit(alignment)); + const u64 alignment_log2 = std::countr_zero(alignment); + std::optional<u64> candidate; + u64 iterator = 0; + auto commit = commits.begin(); + while (iterator + size <= allocation_size) { + candidate = candidate.value_or(iterator); + if (commit == commits.end()) { + break; + } + if (commit->Contains(*candidate, size)) { + candidate = std::nullopt; + } + iterator = Common::AlignUpLog2(commit->end, alignment_log2); + ++commit; + } + return candidate; + } + + const Device& device; ///< Vulkan device. + const vk::DeviceMemory memory; ///< Vulkan memory allocation handler. + const u64 allocation_size; ///< Size of this allocation. + const VkMemoryPropertyFlags property_flags; ///< Vulkan memory property flags. + const u32 shifted_memory_type; ///< Shifted Vulkan memory type. + std::vector<Range> commits; ///< All commit ranges done from this allocation. + std::span<u8> memory_mapped_span; ///< Memory mapped span. Empty if not queried before. +}; + +MemoryCommit::MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, + u64 end_) noexcept + : allocation{allocation_}, memory{memory_}, begin{begin_}, end{end_} {} + +MemoryCommit::~MemoryCommit() { + Release(); +} + +MemoryCommit& MemoryCommit::operator=(MemoryCommit&& rhs) noexcept { + Release(); + allocation = std::exchange(rhs.allocation, nullptr); + memory = rhs.memory; + begin = rhs.begin; + end = rhs.end; + span = std::exchange(rhs.span, std::span<u8>{}); + return *this; +} + +MemoryCommit::MemoryCommit(MemoryCommit&& rhs) noexcept + : allocation{std::exchange(rhs.allocation, nullptr)}, memory{rhs.memory}, begin{rhs.begin}, + end{rhs.end}, span{std::exchange(rhs.span, std::span<u8>{})} {} + +std::span<u8> MemoryCommit::Map() { + if (span.empty()) { + span = allocation->Map().subspan(begin, end - begin); + } + return span; +} + +void MemoryCommit::Release() { + if (allocation) { + allocation->Free(begin); + } +} + +MemoryAllocator::MemoryAllocator(const Device& device_) + : device{device_}, properties{device_.GetPhysical().GetMemoryProperties()} {} + +MemoryAllocator::~MemoryAllocator() = default; + +MemoryCommit MemoryAllocator::Commit(const VkMemoryRequirements& requirements, MemoryUsage usage) { + // Find the fastest memory flags we can afford with the current requirements + const VkMemoryPropertyFlags flags = MemoryPropertyFlags(requirements.memoryTypeBits, usage); + if (std::optional<MemoryCommit> commit = TryCommit(requirements, flags)) { + return std::move(*commit); + } + // Commit has failed, allocate more memory. + // TODO(Rodrigo): Handle out of memory situations in some way like flushing to guest memory. + AllocMemory(flags, requirements.memoryTypeBits, AllocationChunkSize(requirements.size)); + + // Commit again, this time it won't fail since there's a fresh allocation above. + // If it does, there's a bug. + return TryCommit(requirements, flags).value(); +} + +MemoryCommit MemoryAllocator::Commit(const vk::Buffer& buffer, MemoryUsage usage) { + auto commit = Commit(device.GetLogical().GetBufferMemoryRequirements(*buffer), usage); + buffer.BindMemory(commit.Memory(), commit.Offset()); + return commit; +} + +MemoryCommit MemoryAllocator::Commit(const vk::Image& image, MemoryUsage usage) { + auto commit = Commit(device.GetLogical().GetImageMemoryRequirements(*image), usage); + image.BindMemory(commit.Memory(), commit.Offset()); + return commit; +} + +void MemoryAllocator::AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size) { + const u32 type = FindType(flags, type_mask).value(); + vk::DeviceMemory memory = device.GetLogical().AllocateMemory({ + .sType = VK_STRUCTURE_TYPE_MEMORY_ALLOCATE_INFO, + .pNext = nullptr, + .allocationSize = size, + .memoryTypeIndex = type, + }); + allocations.push_back( + std::make_unique<MemoryAllocation>(device, std::move(memory), flags, size, type)); +} + +std::optional<MemoryCommit> MemoryAllocator::TryCommit(const VkMemoryRequirements& requirements, + VkMemoryPropertyFlags flags) { + for (auto& allocation : allocations) { + if (!allocation->IsCompatible(flags, requirements.memoryTypeBits)) { + continue; + } + if (auto commit = allocation->Commit(requirements.size, requirements.alignment)) { + return commit; + } + } + return std::nullopt; +} + +VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const { + return MemoryPropertyFlags(type_mask, MemoryUsagePropertyFlags(usage)); +} + +VkMemoryPropertyFlags MemoryAllocator::MemoryPropertyFlags(u32 type_mask, + VkMemoryPropertyFlags flags) const { + if (FindType(flags, type_mask)) { + // Found a memory type with those requirements + return flags; + } + if (flags & VK_MEMORY_PROPERTY_HOST_CACHED_BIT) { + // Remove host cached bit in case it's not supported + return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_HOST_CACHED_BIT); + } + if (flags & VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT) { + // Remove device local, if it's not supported by the requested resource + return MemoryPropertyFlags(type_mask, flags & ~VK_MEMORY_PROPERTY_DEVICE_LOCAL_BIT); + } + UNREACHABLE_MSG("No compatible memory types found"); + return 0; +} + +std::optional<u32> MemoryAllocator::FindType(VkMemoryPropertyFlags flags, u32 type_mask) const { + for (u32 type_index = 0; type_index < properties.memoryTypeCount; ++type_index) { + const VkMemoryPropertyFlags type_flags = properties.memoryTypes[type_index].propertyFlags; + if ((type_mask & (1U << type_index)) && (type_flags & flags)) { + // The type matches in type and in the wanted properties. + return type_index; + } + } + // Failed to find index + return std::nullopt; +} + +bool IsHostVisible(MemoryUsage usage) noexcept { + switch (usage) { + case MemoryUsage::DeviceLocal: + return false; + case MemoryUsage::Upload: + case MemoryUsage::Download: + return true; + } + UNREACHABLE_MSG("Invalid memory usage={}", usage); + return false; +} + +} // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_memory_allocator.h b/src/video_core/vulkan_common/vulkan_memory_allocator.h new file mode 100644 index 000000000..53b3b275a --- /dev/null +++ b/src/video_core/vulkan_common/vulkan_memory_allocator.h @@ -0,0 +1,118 @@ +// Copyright 2019 yuzu Emulator Project +// Licensed under GPLv2 or any later version +// Refer to the license.txt file included. + +#pragma once + +#include <memory> +#include <span> +#include <utility> +#include <vector> +#include "common/common_types.h" +#include "video_core/vulkan_common/vulkan_wrapper.h" + +namespace Vulkan { + +class Device; +class MemoryMap; +class MemoryAllocation; + +/// Hints and requirements for the backing memory type of a commit +enum class MemoryUsage { + DeviceLocal, ///< Hints device local usages, fastest memory type to read and write from the GPU + Upload, ///< Requires a host visible memory type optimized for CPU to GPU uploads + Download, ///< Requires a host visible memory type optimized for GPU to CPU readbacks +}; + +/// Ownership handle of a memory commitment. +/// Points to a subregion of a memory allocation. +class MemoryCommit { +public: + explicit MemoryCommit() noexcept = default; + explicit MemoryCommit(MemoryAllocation* allocation_, VkDeviceMemory memory_, u64 begin_, + u64 end_) noexcept; + ~MemoryCommit(); + + MemoryCommit& operator=(MemoryCommit&&) noexcept; + MemoryCommit(MemoryCommit&&) noexcept; + + MemoryCommit& operator=(const MemoryCommit&) = delete; + MemoryCommit(const MemoryCommit&) = delete; + + /// Returns a host visible memory map. + /// It will map the backing allocation if it hasn't been mapped before. + std::span<u8> Map(); + + /// Returns the Vulkan memory handler. + VkDeviceMemory Memory() const { + return memory; + } + + /// Returns the start position of the commit relative to the allocation. + VkDeviceSize Offset() const { + return static_cast<VkDeviceSize>(begin); + } + +private: + void Release(); + + MemoryAllocation* allocation{}; ///< Pointer to the large memory allocation. + VkDeviceMemory memory{}; ///< Vulkan device memory handler. + u64 begin{}; ///< Beginning offset in bytes to where the commit exists. + u64 end{}; ///< Offset in bytes where the commit ends. + std::span<u8> span; ///< Host visible memory span. Empty if not queried before. +}; + +/// Memory allocator container. +/// Allocates and releases memory allocations on demand. +class MemoryAllocator { +public: + explicit MemoryAllocator(const Device& device_); + ~MemoryAllocator(); + + MemoryAllocator& operator=(const MemoryAllocator&) = delete; + MemoryAllocator(const MemoryAllocator&) = delete; + + /** + * Commits a memory with the specified requeriments. + * + * @param requirements Requirements returned from a Vulkan call. + * @param host_visible Signals the allocator that it *must* use host visible and coherent + * memory. When passing false, it will try to allocate device local memory. + * + * @returns A memory commit. + */ + MemoryCommit Commit(const VkMemoryRequirements& requirements, MemoryUsage usage); + + /// Commits memory required by the buffer and binds it. + MemoryCommit Commit(const vk::Buffer& buffer, MemoryUsage usage); + + /// Commits memory required by the image and binds it. + MemoryCommit Commit(const vk::Image& image, MemoryUsage usage); + +private: + /// Allocates a chunk of memory. + void AllocMemory(VkMemoryPropertyFlags flags, u32 type_mask, u64 size); + + /// Tries to allocate a memory commit. + std::optional<MemoryCommit> TryCommit(const VkMemoryRequirements& requirements, + VkMemoryPropertyFlags flags); + + /// Returns the fastest compatible memory property flags from a wanted usage. + VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, MemoryUsage usage) const; + + /// Returns the fastest compatible memory property flags from the wanted flags. + VkMemoryPropertyFlags MemoryPropertyFlags(u32 type_mask, VkMemoryPropertyFlags flags) const; + + /// Returns index to the fastest memory type compatible with the passed requirements. + std::optional<u32> FindType(VkMemoryPropertyFlags flags, u32 type_mask) const; + + const Device& device; ///< Device handle. + const VkPhysicalDeviceMemoryProperties properties; ///< Physical device properties. + std::vector<std::unique_ptr<MemoryAllocation>> allocations; ///< Current allocations. +}; + +/// Returns true when a memory usage is guaranteed to be host visible. +bool IsHostVisible(MemoryUsage usage) noexcept; + +} // namespace Vulkan diff --git a/src/video_core/vulkan_common/vulkan_wrapper.h b/src/video_core/vulkan_common/vulkan_wrapper.h index 912cab46c..9689de0cb 100644 --- a/src/video_core/vulkan_common/vulkan_wrapper.h +++ b/src/video_core/vulkan_common/vulkan_wrapper.h @@ -144,152 +144,152 @@ inline VkResult Filter(VkResult result) { /// Table holding Vulkan instance function pointers. struct InstanceDispatch { - PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr; - - PFN_vkCreateInstance vkCreateInstance; - PFN_vkDestroyInstance vkDestroyInstance; - PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties; - PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties; - - PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT; - PFN_vkCreateDevice vkCreateDevice; - PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT; - PFN_vkDestroyDevice vkDestroyDevice; - PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR; - PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties; - PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices; - PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr; - PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR; - PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties; - PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties; - PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties; - PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR; - PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties; - PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR; - PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR; - PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR; - PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR; - PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR; - PFN_vkQueuePresentKHR vkQueuePresentKHR; + PFN_vkGetInstanceProcAddr vkGetInstanceProcAddr{}; + + PFN_vkCreateInstance vkCreateInstance{}; + PFN_vkDestroyInstance vkDestroyInstance{}; + PFN_vkEnumerateInstanceExtensionProperties vkEnumerateInstanceExtensionProperties{}; + PFN_vkEnumerateInstanceLayerProperties vkEnumerateInstanceLayerProperties{}; + + PFN_vkCreateDebugUtilsMessengerEXT vkCreateDebugUtilsMessengerEXT{}; + PFN_vkCreateDevice vkCreateDevice{}; + PFN_vkDestroyDebugUtilsMessengerEXT vkDestroyDebugUtilsMessengerEXT{}; + PFN_vkDestroyDevice vkDestroyDevice{}; + PFN_vkDestroySurfaceKHR vkDestroySurfaceKHR{}; + PFN_vkEnumerateDeviceExtensionProperties vkEnumerateDeviceExtensionProperties{}; + PFN_vkEnumeratePhysicalDevices vkEnumeratePhysicalDevices{}; + PFN_vkGetDeviceProcAddr vkGetDeviceProcAddr{}; + PFN_vkGetPhysicalDeviceFeatures2KHR vkGetPhysicalDeviceFeatures2KHR{}; + PFN_vkGetPhysicalDeviceFormatProperties vkGetPhysicalDeviceFormatProperties{}; + PFN_vkGetPhysicalDeviceMemoryProperties vkGetPhysicalDeviceMemoryProperties{}; + PFN_vkGetPhysicalDeviceProperties vkGetPhysicalDeviceProperties{}; + PFN_vkGetPhysicalDeviceProperties2KHR vkGetPhysicalDeviceProperties2KHR{}; + PFN_vkGetPhysicalDeviceQueueFamilyProperties vkGetPhysicalDeviceQueueFamilyProperties{}; + PFN_vkGetPhysicalDeviceSurfaceCapabilitiesKHR vkGetPhysicalDeviceSurfaceCapabilitiesKHR{}; + PFN_vkGetPhysicalDeviceSurfaceFormatsKHR vkGetPhysicalDeviceSurfaceFormatsKHR{}; + PFN_vkGetPhysicalDeviceSurfacePresentModesKHR vkGetPhysicalDeviceSurfacePresentModesKHR{}; + PFN_vkGetPhysicalDeviceSurfaceSupportKHR vkGetPhysicalDeviceSurfaceSupportKHR{}; + PFN_vkGetSwapchainImagesKHR vkGetSwapchainImagesKHR{}; + PFN_vkQueuePresentKHR vkQueuePresentKHR{}; }; /// Table holding Vulkan device function pointers. struct DeviceDispatch : public InstanceDispatch { - PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR; - PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers; - PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets; - PFN_vkAllocateMemory vkAllocateMemory; - PFN_vkBeginCommandBuffer vkBeginCommandBuffer; - PFN_vkBindBufferMemory vkBindBufferMemory; - PFN_vkBindImageMemory vkBindImageMemory; - PFN_vkCmdBeginQuery vkCmdBeginQuery; - PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass; - PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT; - PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT; - PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets; - PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer; - PFN_vkCmdBindPipeline vkCmdBindPipeline; - PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT; - PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers; - PFN_vkCmdBlitImage vkCmdBlitImage; - PFN_vkCmdClearAttachments vkCmdClearAttachments; - PFN_vkCmdCopyBuffer vkCmdCopyBuffer; - PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage; - PFN_vkCmdCopyImage vkCmdCopyImage; - PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer; - PFN_vkCmdDispatch vkCmdDispatch; - PFN_vkCmdDraw vkCmdDraw; - PFN_vkCmdDrawIndexed vkCmdDrawIndexed; - PFN_vkCmdEndQuery vkCmdEndQuery; - PFN_vkCmdEndRenderPass vkCmdEndRenderPass; - PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT; - PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT; - PFN_vkCmdFillBuffer vkCmdFillBuffer; - PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier; - PFN_vkCmdPushConstants vkCmdPushConstants; - PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants; - PFN_vkCmdSetDepthBias vkCmdSetDepthBias; - PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds; - PFN_vkCmdSetEvent vkCmdSetEvent; - PFN_vkCmdSetScissor vkCmdSetScissor; - PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask; - PFN_vkCmdSetStencilReference vkCmdSetStencilReference; - PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask; - PFN_vkCmdSetViewport vkCmdSetViewport; - PFN_vkCmdWaitEvents vkCmdWaitEvents; - PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT; - PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT; - PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT; - PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT; - PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT; - PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT; - PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT; - PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT; - PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT; - PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT; - PFN_vkCmdResolveImage vkCmdResolveImage; - PFN_vkCreateBuffer vkCreateBuffer; - PFN_vkCreateBufferView vkCreateBufferView; - PFN_vkCreateCommandPool vkCreateCommandPool; - PFN_vkCreateComputePipelines vkCreateComputePipelines; - PFN_vkCreateDescriptorPool vkCreateDescriptorPool; - PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout; - PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR; - PFN_vkCreateEvent vkCreateEvent; - PFN_vkCreateFence vkCreateFence; - PFN_vkCreateFramebuffer vkCreateFramebuffer; - PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines; - PFN_vkCreateImage vkCreateImage; - PFN_vkCreateImageView vkCreateImageView; - PFN_vkCreatePipelineLayout vkCreatePipelineLayout; - PFN_vkCreateQueryPool vkCreateQueryPool; - PFN_vkCreateRenderPass vkCreateRenderPass; - PFN_vkCreateSampler vkCreateSampler; - PFN_vkCreateSemaphore vkCreateSemaphore; - PFN_vkCreateShaderModule vkCreateShaderModule; - PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR; - PFN_vkDestroyBuffer vkDestroyBuffer; - PFN_vkDestroyBufferView vkDestroyBufferView; - PFN_vkDestroyCommandPool vkDestroyCommandPool; - PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool; - PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout; - PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR; - PFN_vkDestroyEvent vkDestroyEvent; - PFN_vkDestroyFence vkDestroyFence; - PFN_vkDestroyFramebuffer vkDestroyFramebuffer; - PFN_vkDestroyImage vkDestroyImage; - PFN_vkDestroyImageView vkDestroyImageView; - PFN_vkDestroyPipeline vkDestroyPipeline; - PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout; - PFN_vkDestroyQueryPool vkDestroyQueryPool; - PFN_vkDestroyRenderPass vkDestroyRenderPass; - PFN_vkDestroySampler vkDestroySampler; - PFN_vkDestroySemaphore vkDestroySemaphore; - PFN_vkDestroyShaderModule vkDestroyShaderModule; - PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR; - PFN_vkDeviceWaitIdle vkDeviceWaitIdle; - PFN_vkEndCommandBuffer vkEndCommandBuffer; - PFN_vkFreeCommandBuffers vkFreeCommandBuffers; - PFN_vkFreeDescriptorSets vkFreeDescriptorSets; - PFN_vkFreeMemory vkFreeMemory; - PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements; - PFN_vkGetDeviceQueue vkGetDeviceQueue; - PFN_vkGetEventStatus vkGetEventStatus; - PFN_vkGetFenceStatus vkGetFenceStatus; - PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements; - PFN_vkGetQueryPoolResults vkGetQueryPoolResults; - PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR; - PFN_vkMapMemory vkMapMemory; - PFN_vkQueueSubmit vkQueueSubmit; - PFN_vkResetFences vkResetFences; - PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT; - PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT; - PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT; - PFN_vkUnmapMemory vkUnmapMemory; - PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR; - PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets; - PFN_vkWaitForFences vkWaitForFences; - PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR; + PFN_vkAcquireNextImageKHR vkAcquireNextImageKHR{}; + PFN_vkAllocateCommandBuffers vkAllocateCommandBuffers{}; + PFN_vkAllocateDescriptorSets vkAllocateDescriptorSets{}; + PFN_vkAllocateMemory vkAllocateMemory{}; + PFN_vkBeginCommandBuffer vkBeginCommandBuffer{}; + PFN_vkBindBufferMemory vkBindBufferMemory{}; + PFN_vkBindImageMemory vkBindImageMemory{}; + PFN_vkCmdBeginQuery vkCmdBeginQuery{}; + PFN_vkCmdBeginRenderPass vkCmdBeginRenderPass{}; + PFN_vkCmdBeginTransformFeedbackEXT vkCmdBeginTransformFeedbackEXT{}; + PFN_vkCmdBeginDebugUtilsLabelEXT vkCmdBeginDebugUtilsLabelEXT{}; + PFN_vkCmdBindDescriptorSets vkCmdBindDescriptorSets{}; + PFN_vkCmdBindIndexBuffer vkCmdBindIndexBuffer{}; + PFN_vkCmdBindPipeline vkCmdBindPipeline{}; + PFN_vkCmdBindTransformFeedbackBuffersEXT vkCmdBindTransformFeedbackBuffersEXT{}; + PFN_vkCmdBindVertexBuffers vkCmdBindVertexBuffers{}; + PFN_vkCmdBlitImage vkCmdBlitImage{}; + PFN_vkCmdClearAttachments vkCmdClearAttachments{}; + PFN_vkCmdCopyBuffer vkCmdCopyBuffer{}; + PFN_vkCmdCopyBufferToImage vkCmdCopyBufferToImage{}; + PFN_vkCmdCopyImage vkCmdCopyImage{}; + PFN_vkCmdCopyImageToBuffer vkCmdCopyImageToBuffer{}; + PFN_vkCmdDispatch vkCmdDispatch{}; + PFN_vkCmdDraw vkCmdDraw{}; + PFN_vkCmdDrawIndexed vkCmdDrawIndexed{}; + PFN_vkCmdEndQuery vkCmdEndQuery{}; + PFN_vkCmdEndRenderPass vkCmdEndRenderPass{}; + PFN_vkCmdEndTransformFeedbackEXT vkCmdEndTransformFeedbackEXT{}; + PFN_vkCmdEndDebugUtilsLabelEXT vkCmdEndDebugUtilsLabelEXT{}; + PFN_vkCmdFillBuffer vkCmdFillBuffer{}; + PFN_vkCmdPipelineBarrier vkCmdPipelineBarrier{}; + PFN_vkCmdPushConstants vkCmdPushConstants{}; + PFN_vkCmdSetBlendConstants vkCmdSetBlendConstants{}; + PFN_vkCmdSetDepthBias vkCmdSetDepthBias{}; + PFN_vkCmdSetDepthBounds vkCmdSetDepthBounds{}; + PFN_vkCmdSetEvent vkCmdSetEvent{}; + PFN_vkCmdSetScissor vkCmdSetScissor{}; + PFN_vkCmdSetStencilCompareMask vkCmdSetStencilCompareMask{}; + PFN_vkCmdSetStencilReference vkCmdSetStencilReference{}; + PFN_vkCmdSetStencilWriteMask vkCmdSetStencilWriteMask{}; + PFN_vkCmdSetViewport vkCmdSetViewport{}; + PFN_vkCmdWaitEvents vkCmdWaitEvents{}; + PFN_vkCmdBindVertexBuffers2EXT vkCmdBindVertexBuffers2EXT{}; + PFN_vkCmdSetCullModeEXT vkCmdSetCullModeEXT{}; + PFN_vkCmdSetDepthBoundsTestEnableEXT vkCmdSetDepthBoundsTestEnableEXT{}; + PFN_vkCmdSetDepthCompareOpEXT vkCmdSetDepthCompareOpEXT{}; + PFN_vkCmdSetDepthTestEnableEXT vkCmdSetDepthTestEnableEXT{}; + PFN_vkCmdSetDepthWriteEnableEXT vkCmdSetDepthWriteEnableEXT{}; + PFN_vkCmdSetFrontFaceEXT vkCmdSetFrontFaceEXT{}; + PFN_vkCmdSetPrimitiveTopologyEXT vkCmdSetPrimitiveTopologyEXT{}; + PFN_vkCmdSetStencilOpEXT vkCmdSetStencilOpEXT{}; + PFN_vkCmdSetStencilTestEnableEXT vkCmdSetStencilTestEnableEXT{}; + PFN_vkCmdResolveImage vkCmdResolveImage{}; + PFN_vkCreateBuffer vkCreateBuffer{}; + PFN_vkCreateBufferView vkCreateBufferView{}; + PFN_vkCreateCommandPool vkCreateCommandPool{}; + PFN_vkCreateComputePipelines vkCreateComputePipelines{}; + PFN_vkCreateDescriptorPool vkCreateDescriptorPool{}; + PFN_vkCreateDescriptorSetLayout vkCreateDescriptorSetLayout{}; + PFN_vkCreateDescriptorUpdateTemplateKHR vkCreateDescriptorUpdateTemplateKHR{}; + PFN_vkCreateEvent vkCreateEvent{}; + PFN_vkCreateFence vkCreateFence{}; + PFN_vkCreateFramebuffer vkCreateFramebuffer{}; + PFN_vkCreateGraphicsPipelines vkCreateGraphicsPipelines{}; + PFN_vkCreateImage vkCreateImage{}; + PFN_vkCreateImageView vkCreateImageView{}; + PFN_vkCreatePipelineLayout vkCreatePipelineLayout{}; + PFN_vkCreateQueryPool vkCreateQueryPool{}; + PFN_vkCreateRenderPass vkCreateRenderPass{}; + PFN_vkCreateSampler vkCreateSampler{}; + PFN_vkCreateSemaphore vkCreateSemaphore{}; + PFN_vkCreateShaderModule vkCreateShaderModule{}; + PFN_vkCreateSwapchainKHR vkCreateSwapchainKHR{}; + PFN_vkDestroyBuffer vkDestroyBuffer{}; + PFN_vkDestroyBufferView vkDestroyBufferView{}; + PFN_vkDestroyCommandPool vkDestroyCommandPool{}; + PFN_vkDestroyDescriptorPool vkDestroyDescriptorPool{}; + PFN_vkDestroyDescriptorSetLayout vkDestroyDescriptorSetLayout{}; + PFN_vkDestroyDescriptorUpdateTemplateKHR vkDestroyDescriptorUpdateTemplateKHR{}; + PFN_vkDestroyEvent vkDestroyEvent{}; + PFN_vkDestroyFence vkDestroyFence{}; + PFN_vkDestroyFramebuffer vkDestroyFramebuffer{}; + PFN_vkDestroyImage vkDestroyImage{}; + PFN_vkDestroyImageView vkDestroyImageView{}; + PFN_vkDestroyPipeline vkDestroyPipeline{}; + PFN_vkDestroyPipelineLayout vkDestroyPipelineLayout{}; + PFN_vkDestroyQueryPool vkDestroyQueryPool{}; + PFN_vkDestroyRenderPass vkDestroyRenderPass{}; + PFN_vkDestroySampler vkDestroySampler{}; + PFN_vkDestroySemaphore vkDestroySemaphore{}; + PFN_vkDestroyShaderModule vkDestroyShaderModule{}; + PFN_vkDestroySwapchainKHR vkDestroySwapchainKHR{}; + PFN_vkDeviceWaitIdle vkDeviceWaitIdle{}; + PFN_vkEndCommandBuffer vkEndCommandBuffer{}; + PFN_vkFreeCommandBuffers vkFreeCommandBuffers{}; + PFN_vkFreeDescriptorSets vkFreeDescriptorSets{}; + PFN_vkFreeMemory vkFreeMemory{}; + PFN_vkGetBufferMemoryRequirements vkGetBufferMemoryRequirements{}; + PFN_vkGetDeviceQueue vkGetDeviceQueue{}; + PFN_vkGetEventStatus vkGetEventStatus{}; + PFN_vkGetFenceStatus vkGetFenceStatus{}; + PFN_vkGetImageMemoryRequirements vkGetImageMemoryRequirements{}; + PFN_vkGetQueryPoolResults vkGetQueryPoolResults{}; + PFN_vkGetSemaphoreCounterValueKHR vkGetSemaphoreCounterValueKHR{}; + PFN_vkMapMemory vkMapMemory{}; + PFN_vkQueueSubmit vkQueueSubmit{}; + PFN_vkResetFences vkResetFences{}; + PFN_vkResetQueryPoolEXT vkResetQueryPoolEXT{}; + PFN_vkSetDebugUtilsObjectNameEXT vkSetDebugUtilsObjectNameEXT{}; + PFN_vkSetDebugUtilsObjectTagEXT vkSetDebugUtilsObjectTagEXT{}; + PFN_vkUnmapMemory vkUnmapMemory{}; + PFN_vkUpdateDescriptorSetWithTemplateKHR vkUpdateDescriptorSetWithTemplateKHR{}; + PFN_vkUpdateDescriptorSets vkUpdateDescriptorSets{}; + PFN_vkWaitForFences vkWaitForFences{}; + PFN_vkWaitSemaphoresKHR vkWaitSemaphoresKHR{}; }; /// Loads instance agnostic function pointers. diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 85ee2577d..e6c8f18af 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp @@ -290,8 +290,8 @@ GRenderWindow::GRenderWindow(GMainWindow* parent, EmuThread* emu_thread_, QString::fromUtf8(Common::g_scm_branch), QString::fromUtf8(Common::g_scm_desc))); setAttribute(Qt::WA_AcceptTouchEvents); - auto layout = new QHBoxLayout(this); - layout->setMargin(0); + auto* layout = new QHBoxLayout(this); + layout->setContentsMargins(0, 0, 0, 0); setLayout(layout); input_subsystem->Initialize(); diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index b33f8437a..d6b17a28d 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp @@ -117,31 +117,13 @@ void ConfigureDialog::UpdateVisibleTabs() { return; } - const std::map<QWidget*, QString> widgets = { - {ui->generalTab, tr("General")}, - {ui->systemTab, tr("System")}, - {ui->profileManagerTab, tr("Profiles")}, - {ui->inputTab, tr("Controls")}, - {ui->hotkeysTab, tr("Hotkeys")}, - {ui->cpuTab, tr("CPU")}, - {ui->cpuDebugTab, tr("Debug")}, - {ui->graphicsTab, tr("Graphics")}, - {ui->graphicsAdvancedTab, tr("Advanced")}, - {ui->audioTab, tr("Audio")}, - {ui->debugTab, tr("Debug")}, - {ui->webTab, tr("Web")}, - {ui->uiTab, tr("UI")}, - {ui->filesystemTab, tr("Filesystem")}, - {ui->serviceTab, tr("Services")}, - }; - [[maybe_unused]] const QSignalBlocker blocker(ui->tabWidget); ui->tabWidget->clear(); - const QList<QWidget*> tabs = qvariant_cast<QList<QWidget*>>(items[0]->data(Qt::UserRole)); + const auto tabs = qvariant_cast<QList<QWidget*>>(items[0]->data(Qt::UserRole)); - for (const auto tab : tabs) { + for (auto* const tab : tabs) { ui->tabWidget->addTab(tab, tab->accessibleName()); } } diff --git a/src/yuzu/configuration/configure_motion_touch.cpp b/src/yuzu/configuration/configure_motion_touch.cpp index eb8eacbf9..caaa85930 100644 --- a/src/yuzu/configuration/configure_motion_touch.cpp +++ b/src/yuzu/configuration/configure_motion_touch.cpp @@ -4,12 +4,15 @@ #include <array> #include <sstream> + #include <QCloseEvent> #include <QLabel> #include <QMessageBox> #include <QPushButton> +#include <QRegularExpression> #include <QStringListModel> #include <QVBoxLayout> + #include "common/logging/log.h" #include "core/settings.h" #include "input_common/main.h" @@ -109,7 +112,6 @@ ConfigureMotionTouch::~ConfigureMotionTouch() = default; void ConfigureMotionTouch::SetConfiguration() { const Common::ParamPackage motion_param(Settings::values.motion_device); const Common::ParamPackage touch_param(Settings::values.touch_device); - const std::string motion_engine = motion_param.Get("engine", "motion_emu"); const std::string touch_engine = touch_param.Get("engine", "emu_window"); ui->touch_provider->setCurrentIndex( @@ -185,14 +187,15 @@ void ConfigureMotionTouch::ConnectEvents() { } void ConfigureMotionTouch::OnUDPAddServer() { - QRegExp re(tr(R"re(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4]" - "[0-9]|[01]?[0-9][0-9]?)$)re")); // a valid ip address + // Validator for IP address + const QRegularExpression re(QStringLiteral( + R"re(^(?:(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\.){3}(?:25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$)re")); bool ok; - QString port_text = ui->udp_port->text(); - QString server_text = ui->udp_server->text(); + const QString port_text = ui->udp_port->text(); + const QString server_text = ui->udp_server->text(); const QString server_string = tr("%1:%2").arg(server_text, port_text); - int port_number = port_text.toInt(&ok, 10); - int row = udp_server_list_model->rowCount(); + const int port_number = port_text.toInt(&ok, 10); + const int row = udp_server_list_model->rowCount(); if (!ok) { QMessageBox::warning(this, tr("yuzu"), tr("Port number has invalid characters")); @@ -202,7 +205,7 @@ void ConfigureMotionTouch::OnUDPAddServer() { QMessageBox::warning(this, tr("yuzu"), tr("Port has to be in range 0 and 65353")); return; } - if (!re.exactMatch(server_text)) { + if (!re.match(server_text).hasMatch()) { QMessageBox::warning(this, tr("yuzu"), tr("IP address is not valid")); return; } @@ -327,14 +330,13 @@ void ConfigureMotionTouch::ApplyConfiguration() { std::string touch_engine = ui->touch_provider->currentData().toString().toStdString(); Common::ParamPackage touch_param{}; - touch_param.Set("engine", std::move(touch_engine)); - if (touch_engine == "cemuhookudp") { touch_param.Set("min_x", min_x); touch_param.Set("min_y", min_y); touch_param.Set("max_x", max_x); touch_param.Set("max_y", max_y); } + touch_param.Set("engine", std::move(touch_engine)); Settings::values.touch_device = touch_param.Serialize(); Settings::values.use_touch_from_button = ui->touch_from_button_checkbox->isChecked(); diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 70d865112..37b0d1a0e 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp @@ -119,7 +119,7 @@ void GameListSearchField::setFocus() { GameListSearchField::GameListSearchField(GameList* parent) : QWidget{parent} { auto* const key_release_eater = new KeyReleaseEater(parent, this); layout_filter = new QHBoxLayout; - layout_filter->setMargin(8); + layout_filter->setContentsMargins(8, 8, 8, 8); label_filter = new QLabel; label_filter->setText(tr("Filter:")); edit_filter = new QLineEdit; diff --git a/src/yuzu_tester/CMakeLists.txt b/src/yuzu_tester/CMakeLists.txt deleted file mode 100644 index d8a2a1511..000000000 --- a/src/yuzu_tester/CMakeLists.txt +++ /dev/null @@ -1,32 +0,0 @@ -set(CMAKE_MODULE_PATH ${CMAKE_MODULE_PATH} ${PROJECT_SOURCE_DIR}/CMakeModules) - -add_executable(yuzu-tester - config.cpp - config.h - default_ini.h - emu_window/emu_window_sdl2_hide.cpp - emu_window/emu_window_sdl2_hide.h - resource.h - service/yuzutest.cpp - service/yuzutest.h - yuzu.cpp - yuzu.rc -) - -create_target_directory_groups(yuzu-tester) - -target_link_libraries(yuzu-tester PRIVATE common core input_common) -target_link_libraries(yuzu-tester PRIVATE inih glad) -if (MSVC) - target_link_libraries(yuzu-tester PRIVATE getopt) -endif() -target_link_libraries(yuzu-tester PRIVATE ${PLATFORM_LIBRARIES} SDL2 Threads::Threads) - -if(UNIX AND NOT APPLE) - install(TARGETS yuzu-tester RUNTIME DESTINATION "${CMAKE_INSTALL_PREFIX}/bin") -endif() - -if (MSVC) - include(CopyYuzuSDLDeps) - copy_yuzu_SDL_deps(yuzu-tester) -endif() diff --git a/src/yuzu_tester/config.cpp b/src/yuzu_tester/config.cpp deleted file mode 100644 index 0aa143e1f..000000000 --- a/src/yuzu_tester/config.cpp +++ /dev/null @@ -1,194 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <memory> -#include <sstream> -#include <SDL.h> -#include <inih/cpp/INIReader.h> -#include "common/file_util.h" -#include "common/logging/log.h" -#include "common/param_package.h" -#include "core/hle/service/acc/profile_manager.h" -#include "core/settings.h" -#include "input_common/main.h" -#include "yuzu_tester/config.h" -#include "yuzu_tester/default_ini.h" - -namespace FS = Common::FS; - -Config::Config() { - // TODO: Don't hardcode the path; let the frontend decide where to put the config files. - sdl2_config_loc = FS::GetUserPath(FS::UserPath::ConfigDir) + "sdl2-tester-config.ini"; - sdl2_config = std::make_unique<INIReader>(sdl2_config_loc); - - Reload(); -} - -Config::~Config() = default; - -bool Config::LoadINI(const std::string& default_contents, bool retry) { - const char* location = this->sdl2_config_loc.c_str(); - if (sdl2_config->ParseError() < 0) { - if (retry) { - LOG_WARNING(Config, "Failed to load {}. Creating file from defaults...", location); - FS::CreateFullPath(location); - FS::WriteStringToFile(true, default_contents, location); - sdl2_config = std::make_unique<INIReader>(location); // Reopen file - - return LoadINI(default_contents, false); - } - LOG_ERROR(Config, "Failed."); - return false; - } - LOG_INFO(Config, "Successfully loaded {}", location); - return true; -} - -void Config::ReadValues() { - // Controls - for (std::size_t p = 0; p < Settings::values.players.GetValue().size(); ++p) { - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - Settings::values.players.GetValue()[p].buttons[i] = ""; - } - - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - Settings::values.players.GetValue()[p].analogs[i] = ""; - } - } - - Settings::values.mouse_enabled = false; - for (int i = 0; i < Settings::NativeMouseButton::NumMouseButtons; ++i) { - Settings::values.mouse_buttons[i] = ""; - } - - Settings::values.motion_device = ""; - - Settings::values.keyboard_enabled = false; - - Settings::values.debug_pad_enabled = false; - for (int i = 0; i < Settings::NativeButton::NumButtons; ++i) { - Settings::values.debug_pad_buttons[i] = ""; - } - - for (int i = 0; i < Settings::NativeAnalog::NumAnalogs; ++i) { - Settings::values.debug_pad_analogs[i] = ""; - } - - Settings::values.vibration_enabled.SetValue(true); - Settings::values.enable_accurate_vibrations.SetValue(false); - Settings::values.motion_enabled.SetValue(true); - Settings::values.touchscreen.enabled = ""; - Settings::values.touchscreen.device = ""; - Settings::values.touchscreen.finger = 0; - Settings::values.touchscreen.rotation_angle = 0; - Settings::values.touchscreen.diameter_x = 15; - Settings::values.touchscreen.diameter_y = 15; - - Settings::values.use_docked_mode.SetValue( - sdl2_config->GetBoolean("Controls", "use_docked_mode", true)); - - // Data Storage - Settings::values.use_virtual_sd = - sdl2_config->GetBoolean("Data Storage", "use_virtual_sd", true); - FS::GetUserPath(Common::FS::UserPath::NANDDir, - sdl2_config->Get("Data Storage", "nand_directory", - Common::FS::GetUserPath(Common::FS::UserPath::NANDDir))); - FS::GetUserPath(Common::FS::UserPath::SDMCDir, - sdl2_config->Get("Data Storage", "sdmc_directory", - Common::FS::GetUserPath(Common::FS::UserPath::SDMCDir))); - - // System - Settings::values.current_user = std::clamp<int>( - sdl2_config->GetInteger("System", "current_user", 0), 0, Service::Account::MAX_USERS - 1); - - const auto rng_seed_enabled = sdl2_config->GetBoolean("System", "rng_seed_enabled", false); - if (rng_seed_enabled) { - Settings::values.rng_seed.SetValue(sdl2_config->GetInteger("System", "rng_seed", 0)); - } else { - Settings::values.rng_seed.SetValue(std::nullopt); - } - - const auto custom_rtc_enabled = sdl2_config->GetBoolean("System", "custom_rtc_enabled", false); - if (custom_rtc_enabled) { - Settings::values.custom_rtc.SetValue( - std::chrono::seconds(sdl2_config->GetInteger("System", "custom_rtc", 0))); - } else { - Settings::values.custom_rtc.SetValue(std::nullopt); - } - - // Core - Settings::values.use_multi_core.SetValue( - sdl2_config->GetBoolean("Core", "use_multi_core", false)); - - // Renderer - Settings::values.aspect_ratio.SetValue( - static_cast<int>(sdl2_config->GetInteger("Renderer", "aspect_ratio", 0))); - Settings::values.max_anisotropy.SetValue( - static_cast<int>(sdl2_config->GetInteger("Renderer", "max_anisotropy", 0))); - Settings::values.use_frame_limit.SetValue(false); - Settings::values.frame_limit.SetValue(100); - Settings::values.use_disk_shader_cache.SetValue( - sdl2_config->GetBoolean("Renderer", "use_disk_shader_cache", false)); - const int gpu_accuracy_level = sdl2_config->GetInteger("Renderer", "gpu_accuracy", 0); - Settings::values.gpu_accuracy.SetValue(static_cast<Settings::GPUAccuracy>(gpu_accuracy_level)); - Settings::values.use_asynchronous_gpu_emulation.SetValue( - sdl2_config->GetBoolean("Renderer", "use_asynchronous_gpu_emulation", false)); - Settings::values.use_fast_gpu_time.SetValue( - sdl2_config->GetBoolean("Renderer", "use_fast_gpu_time", true)); - - Settings::values.bg_red.SetValue( - static_cast<float>(sdl2_config->GetReal("Renderer", "bg_red", 0.0))); - Settings::values.bg_green.SetValue( - static_cast<float>(sdl2_config->GetReal("Renderer", "bg_green", 0.0))); - Settings::values.bg_blue.SetValue( - static_cast<float>(sdl2_config->GetReal("Renderer", "bg_blue", 0.0))); - - // Audio - Settings::values.sink_id = "null"; - Settings::values.enable_audio_stretching.SetValue(false); - Settings::values.audio_device_id = "auto"; - Settings::values.volume.SetValue(0); - - Settings::values.language_index.SetValue( - sdl2_config->GetInteger("System", "language_index", 1)); - - // Miscellaneous - Settings::values.log_filter = sdl2_config->Get("Miscellaneous", "log_filter", "*:Trace"); - Settings::values.use_dev_keys = sdl2_config->GetBoolean("Miscellaneous", "use_dev_keys", false); - - // Debugging - Settings::values.program_args = ""; - Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false); - Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false); - - const auto title_list = sdl2_config->Get("AddOns", "title_ids", ""); - std::stringstream ss(title_list); - std::string line; - while (std::getline(ss, line, '|')) { - const auto title_id = std::stoul(line, nullptr, 16); - const auto disabled_list = sdl2_config->Get("AddOns", "disabled_" + line, ""); - - std::stringstream inner_ss(disabled_list); - std::string inner_line; - std::vector<std::string> out; - while (std::getline(inner_ss, inner_line, '|')) { - out.push_back(inner_line); - } - - Settings::values.disabled_addons.insert_or_assign(title_id, out); - } - - // Web Service - Settings::values.enable_telemetry = - sdl2_config->GetBoolean("WebService", "enable_telemetry", true); - Settings::values.web_api_url = - sdl2_config->Get("WebService", "web_api_url", "https://api.yuzu-emu.org"); - Settings::values.yuzu_username = sdl2_config->Get("WebService", "yuzu_username", ""); - Settings::values.yuzu_token = sdl2_config->Get("WebService", "yuzu_token", ""); -} - -void Config::Reload() { - LoadINI(DefaultINI::sdl2_config_file); - ReadValues(); -} diff --git a/src/yuzu_tester/config.h b/src/yuzu_tester/config.h deleted file mode 100644 index 3b68e5bc9..000000000 --- a/src/yuzu_tester/config.h +++ /dev/null @@ -1,24 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <memory> -#include <string> - -class INIReader; - -class Config { - std::unique_ptr<INIReader> sdl2_config; - std::string sdl2_config_loc; - - bool LoadINI(const std::string& default_contents = "", bool retry = true); - void ReadValues(); - -public: - Config(); - ~Config(); - - void Reload(); -}; diff --git a/src/yuzu_tester/default_ini.h b/src/yuzu_tester/default_ini.h deleted file mode 100644 index 779c3791b..000000000 --- a/src/yuzu_tester/default_ini.h +++ /dev/null @@ -1,182 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -namespace DefaultINI { - -const char* sdl2_config_file = R"( -[Core] -# Whether to use multi-core for CPU emulation -# 0 (default): Disabled, 1: Enabled -use_multi_core= - -[Cpu] -# Enable inline page tables optimization (faster guest memory access) -# 0: Disabled, 1 (default): Enabled -cpuopt_page_tables = - -# Enable block linking CPU optimization (reduce block dispatcher use during predictable jumps) -# 0: Disabled, 1 (default): Enabled -cpuopt_block_linking = - -# Enable return stack buffer CPU optimization (reduce block dispatcher use during predictable returns) -# 0: Disabled, 1 (default): Enabled -cpuopt_return_stack_buffer = - -# Enable fast dispatcher CPU optimization (use a two-tiered dispatcher architecture) -# 0: Disabled, 1 (default): Enabled -cpuopt_fast_dispatcher = - -# Enable context elimination CPU Optimization (reduce host memory use for guest context) -# 0: Disabled, 1 (default): Enabled -cpuopt_context_elimination = - -# Enable constant propagation CPU optimization (basic IR optimization) -# 0: Disabled, 1 (default): Enabled -cpuopt_const_prop = - -# Enable miscellaneous CPU optimizations (basic IR optimization) -# 0: Disabled, 1 (default): Enabled -cpuopt_misc_ir = - -# Enable reduction of memory misalignment checks (reduce memory fallbacks for misaligned access) -# 0: Disabled, 1 (default): Enabled -cpuopt_reduce_misalign_checks = - -[Renderer] -# Whether to use software or hardware rendering. -# 0: Software, 1 (default): Hardware -use_hw_renderer = - -# Whether to use the Just-In-Time (JIT) compiler for shader emulation -# 0: Interpreter (slow), 1 (default): JIT (fast) -use_shader_jit = - -# Aspect ratio -# 0: Default (16:9), 1: Force 4:3, 2: Force 21:9, 3: Stretch to Window -aspect_ratio = - -# Anisotropic filtering -# 0: Default, 1: 2x, 2: 4x, 3: 8x, 4: 16x -max_anisotropy = - -# Whether to enable V-Sync (caps the framerate at 60FPS) or not. -# 0 (default): Off, 1: On -use_vsync = - -# Whether to use disk based shader cache -# 0 (default): Off, 1 : On -use_disk_shader_cache = - -# Whether to use accurate GPU emulation -# 0 (default): Off (fast), 1 : On (slow) -use_accurate_gpu_emulation = - -# Whether to use asynchronous GPU emulation -# 0 : Off (slow), 1 (default): On (fast) -use_asynchronous_gpu_emulation = - -# The clear color for the renderer. What shows up on the sides of the bottom screen. -# Must be in range of 0.0-1.0. Defaults to 1.0 for all. -bg_red = -bg_blue = -bg_green = - -[Layout] -# Layout for the screen inside the render window. -# 0 (default): Default Top Bottom Screen, 1: Single Screen Only, 2: Large Screen Small Screen -layout_option = - -# Toggle custom layout (using the settings below) on or off. -# 0 (default): Off, 1: On -custom_layout = - -# Screen placement when using Custom layout option -# 0x, 0y is the top left corner of the render window. -custom_top_left = -custom_top_top = -custom_top_right = -custom_top_bottom = -custom_bottom_left = -custom_bottom_top = -custom_bottom_right = -custom_bottom_bottom = - -# Swaps the prominent screen with the other screen. -# For example, if Single Screen is chosen, setting this to 1 will display the bottom screen instead of the top screen. -# 0 (default): Top Screen is prominent, 1: Bottom Screen is prominent -swap_screen = - -[Data Storage] -# Whether to create a virtual SD card. -# 1 (default): Yes, 0: No -use_virtual_sd = - -[System] -# Whether the system is docked -# 1 (default): Yes, 0: No -use_docked_mode = - -# Allow the use of NFC in games -# 1 (default): Yes, 0 : No -enable_nfc = - -# Sets the seed for the RNG generator built into the switch -# rng_seed will be ignored and randomly generated if rng_seed_enabled is false -rng_seed_enabled = -rng_seed = - -# Sets the current time (in seconds since 12:00 AM Jan 1, 1970) that will be used by the time service -# This will auto-increment, with the time set being the time the game is started -# This override will only occur if custom_rtc_enabled is true, otherwise the current time is used -custom_rtc_enabled = -custom_rtc = - -# Sets the account username, max length is 32 characters -# yuzu (default) -username = yuzu - -# Sets the systems language index -# 0: Japanese, 1: English (default), 2: French, 3: German, 4: Italian, 5: Spanish, 6: Chinese, -# 7: Korean, 8: Dutch, 9: Portuguese, 10: Russian, 11: Taiwanese, 12: British English, 13: Canadian French, -# 14: Latin American Spanish, 15: Simplified Chinese, 16: Traditional Chinese -language_index = - -# The system region that yuzu will use during emulation -# -1: Auto-select (default), 0: Japan, 1: USA, 2: Europe, 3: Australia, 4: China, 5: Korea, 6: Taiwan -region_value = - -[Miscellaneous] -# A filter which removes logs below a certain logging level. -# Examples: *:Debug Kernel.SVC:Trace Service.*:Critical -log_filter = *:Trace - -[Debugging] -# Arguments to be passed to argv/argc in the emulated program. It is preferable to use the testing service datastring -program_args= -# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them -dump_exefs=false -# Determines whether or not yuzu will dump all NSOs it attempts to load while loading them -dump_nso=false - -[WebService] -# Whether or not to enable telemetry -# 0: No, 1 (default): Yes -enable_telemetry = -# URL for Web API -web_api_url = https://api.yuzu-emu.org -# Username and token for yuzu Web Service -# See https://profile.yuzu-emu.org/ for more info -yuzu_username = -yuzu_token = - -[AddOns] -# Used to disable add-ons -# List of title IDs of games that will have add-ons disabled (separated by '|'): -title_ids = -# For each title ID, have a key/value pair called `disabled_<title_id>` equal to the names of the add-ons to disable (sep. by '|') -# e.x. disabled_0100000000010000 = Update|DLC <- disables Updates and DLC on Super Mario Odyssey -)"; -} diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp deleted file mode 100644 index 358e03870..000000000 --- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.cpp +++ /dev/null @@ -1,146 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <algorithm> -#include <cstdlib> -#include <string> - -#include <fmt/format.h> - -#define SDL_MAIN_HANDLED -#include <SDL.h> - -#include <glad/glad.h> - -#include "common/logging/log.h" -#include "common/scm_rev.h" -#include "core/settings.h" -#include "input_common/main.h" -#include "yuzu_tester/emu_window/emu_window_sdl2_hide.h" - -bool EmuWindow_SDL2_Hide::SupportsRequiredGLExtensions() { - std::vector<std::string> unsupported_ext; - - if (!GLAD_GL_ARB_direct_state_access) - unsupported_ext.push_back("ARB_direct_state_access"); - if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) - unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev"); - if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) - unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); - if (!GLAD_GL_ARB_multi_bind) - unsupported_ext.push_back("ARB_multi_bind"); - - // Extensions required to support some texture formats. - if (!GLAD_GL_EXT_texture_compression_s3tc) - unsupported_ext.push_back("EXT_texture_compression_s3tc"); - if (!GLAD_GL_ARB_texture_compression_rgtc) - unsupported_ext.push_back("ARB_texture_compression_rgtc"); - if (!GLAD_GL_ARB_depth_buffer_float) - unsupported_ext.push_back("ARB_depth_buffer_float"); - - for (const std::string& ext : unsupported_ext) - LOG_CRITICAL(Frontend, "Unsupported GL extension: {}", ext); - - return unsupported_ext.empty(); -} - -EmuWindow_SDL2_Hide::EmuWindow_SDL2_Hide() { - // Initialize the window - if (SDL_Init(SDL_INIT_VIDEO) < 0) { - LOG_CRITICAL(Frontend, "Failed to initialize SDL2! Exiting..."); - exit(1); - } - - input_subsystem->Initialize(); - - SDL_SetMainReady(); - - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); - SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); - SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); - SDL_GL_SetAttribute(SDL_GL_RED_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_GREEN_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_BLUE_SIZE, 8); - SDL_GL_SetAttribute(SDL_GL_ALPHA_SIZE, 0); - - std::string window_title = fmt::format("yuzu-tester {} | {}-{}", Common::g_build_fullname, - Common::g_scm_branch, Common::g_scm_desc); - render_window = SDL_CreateWindow(window_title.c_str(), - SDL_WINDOWPOS_UNDEFINED, // x position - SDL_WINDOWPOS_UNDEFINED, // y position - Layout::ScreenUndocked::Width, Layout::ScreenUndocked::Height, - SDL_WINDOW_OPENGL | SDL_WINDOW_RESIZABLE | - SDL_WINDOW_ALLOW_HIGHDPI | SDL_WINDOW_HIDDEN); - - if (render_window == nullptr) { - LOG_CRITICAL(Frontend, "Failed to create SDL2 window! {}", SDL_GetError()); - exit(1); - } - - gl_context = SDL_GL_CreateContext(render_window); - - if (gl_context == nullptr) { - LOG_CRITICAL(Frontend, "Failed to create SDL2 GL context! {}", SDL_GetError()); - exit(1); - } - - if (!gladLoadGLLoader(static_cast<GLADloadproc>(SDL_GL_GetProcAddress))) { - LOG_CRITICAL(Frontend, "Failed to initialize GL functions! {}", SDL_GetError()); - exit(1); - } - - if (!SupportsRequiredGLExtensions()) { - LOG_CRITICAL(Frontend, "GPU does not support all required OpenGL extensions! Exiting..."); - exit(1); - } - - SDL_PumpEvents(); - SDL_GL_SetSwapInterval(false); - LOG_INFO(Frontend, "yuzu-tester Version: {} | {}-{}", Common::g_build_fullname, - Common::g_scm_branch, Common::g_scm_desc); - Settings::LogSettings(); -} - -EmuWindow_SDL2_Hide::~EmuWindow_SDL2_Hide() { - input_subsystem->Shutdown(); - SDL_GL_DeleteContext(gl_context); - SDL_Quit(); -} - -bool EmuWindow_SDL2_Hide::IsShown() const { - return false; -} - -class SDLGLContext : public Core::Frontend::GraphicsContext { -public: - explicit SDLGLContext() { - // create a hidden window to make the shared context against - window = SDL_CreateWindow(NULL, SDL_WINDOWPOS_UNDEFINED, SDL_WINDOWPOS_UNDEFINED, 0, 0, - SDL_WINDOW_HIDDEN | SDL_WINDOW_OPENGL); - context = SDL_GL_CreateContext(window); - } - - ~SDLGLContext() { - DoneCurrent(); - SDL_GL_DeleteContext(context); - SDL_DestroyWindow(window); - } - - void MakeCurrent() override { - SDL_GL_MakeCurrent(window, context); - } - - void DoneCurrent() override { - SDL_GL_MakeCurrent(window, nullptr); - } - -private: - SDL_Window* window; - SDL_GLContext context; -}; - -std::unique_ptr<Core::Frontend::GraphicsContext> EmuWindow_SDL2_Hide::CreateSharedContext() const { - return std::make_unique<SDLGLContext>(); -} diff --git a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h b/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h deleted file mode 100644 index adccdf35e..000000000 --- a/src/yuzu_tester/emu_window/emu_window_sdl2_hide.h +++ /dev/null @@ -1,37 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include "core/frontend/emu_window.h" - -struct SDL_Window; - -namespace InputCommon { -class InputSubsystem; -} - -class EmuWindow_SDL2_Hide : public Core::Frontend::EmuWindow { -public: - explicit EmuWindow_SDL2_Hide(); - ~EmuWindow_SDL2_Hide(); - - /// Whether the screen is being shown or not. - bool IsShown() const override; - - std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override; - -private: - /// Whether the GPU and driver supports the OpenGL extension required - bool SupportsRequiredGLExtensions(); - - std::unique_ptr<InputCommon::InputSubsystem> input_subsystem; - - /// Internal SDL2 render window - SDL_Window* render_window; - - using SDL_GLContext = void*; - /// The OpenGL context associated with the window - SDL_GLContext gl_context; -}; diff --git a/src/yuzu_tester/resource.h b/src/yuzu_tester/resource.h deleted file mode 100644 index df8e459e4..000000000 --- a/src/yuzu_tester/resource.h +++ /dev/null @@ -1,16 +0,0 @@ -//{{NO_DEPENDENCIES}} -// Microsoft Visual C++ generated include file. -// Used by pcafe.rc -// -#define IDI_ICON3 103 - -// Next default values for new objects -// -#ifdef APSTUDIO_INVOKED -#ifndef APSTUDIO_READONLY_SYMBOLS -#define _APS_NEXT_RESOURCE_VALUE 105 -#define _APS_NEXT_COMMAND_VALUE 40001 -#define _APS_NEXT_CONTROL_VALUE 1001 -#define _APS_NEXT_SYMED_VALUE 101 -#endif -#endif diff --git a/src/yuzu_tester/service/yuzutest.cpp b/src/yuzu_tester/service/yuzutest.cpp deleted file mode 100644 index e257fae25..000000000 --- a/src/yuzu_tester/service/yuzutest.cpp +++ /dev/null @@ -1,115 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <memory> -#include "common/string_util.h" -#include "core/core.h" -#include "core/hle/ipc_helpers.h" -#include "core/hle/service/service.h" -#include "core/hle/service/sm/sm.h" -#include "yuzu_tester/service/yuzutest.h" - -namespace Service::Yuzu { - -constexpr u64 SERVICE_VERSION = 0x00000002; - -class YuzuTest final : public ServiceFramework<YuzuTest> { -public: - explicit YuzuTest(Core::System& system_, std::string data_, - std::function<void(std::vector<TestResult>)> finish_callback_) - : ServiceFramework{system_, "yuzutest"}, data{std::move(data_)}, finish_callback{std::move( - finish_callback_)} { - static const FunctionInfo functions[] = { - {0, &YuzuTest::Initialize, "Initialize"}, - {1, &YuzuTest::GetServiceVersion, "GetServiceVersion"}, - {2, &YuzuTest::GetData, "GetData"}, - {10, &YuzuTest::StartIndividual, "StartIndividual"}, - {20, &YuzuTest::FinishIndividual, "FinishIndividual"}, - {100, &YuzuTest::ExitProgram, "ExitProgram"}, - }; - - RegisterHandlers(functions); - } - -private: - void Initialize(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Frontend, "called"); - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } - - void GetServiceVersion(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Frontend, "called"); - IPC::ResponseBuilder rb{ctx, 4}; - rb.Push(RESULT_SUCCESS); - rb.Push(SERVICE_VERSION); - } - - void GetData(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Frontend, "called"); - const auto size = ctx.GetWriteBufferSize(); - const auto write_size = std::min(size, data.size()); - ctx.WriteBuffer(data.data(), write_size); - - IPC::ResponseBuilder rb{ctx, 3}; - rb.Push(RESULT_SUCCESS); - rb.Push<u32>(static_cast<u32>(write_size)); - } - - void StartIndividual(Kernel::HLERequestContext& ctx) { - const auto name_raw = ctx.ReadBuffer(); - - const auto name = Common::StringFromFixedZeroTerminatedBuffer( - reinterpret_cast<const char*>(name_raw.data()), name_raw.size()); - - LOG_DEBUG(Frontend, "called, name={}", name); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } - - void FinishIndividual(Kernel::HLERequestContext& ctx) { - IPC::RequestParser rp{ctx}; - - const auto code = rp.PopRaw<u32>(); - - const auto result_data_raw = ctx.ReadBuffer(); - const auto test_name_raw = ctx.ReadBuffer(1); - - const auto data = Common::StringFromFixedZeroTerminatedBuffer( - reinterpret_cast<const char*>(result_data_raw.data()), result_data_raw.size()); - const auto test_name = Common::StringFromFixedZeroTerminatedBuffer( - reinterpret_cast<const char*>(test_name_raw.data()), test_name_raw.size()); - - LOG_INFO(Frontend, "called, result_code={:08X}, data={}, name={}", code, data, test_name); - - results.push_back({code, data, test_name}); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - } - - void ExitProgram(Kernel::HLERequestContext& ctx) { - LOG_DEBUG(Frontend, "called"); - - IPC::ResponseBuilder rb{ctx, 2}; - rb.Push(RESULT_SUCCESS); - - finish_callback(std::move(results)); - } - - std::string data; - - std::vector<TestResult> results; - std::function<void(std::vector<TestResult>)> finish_callback; -}; - -void InstallInterfaces(Core::System& system, std::string data, - std::function<void(std::vector<TestResult>)> finish_callback) { - auto& sm = system.ServiceManager(); - std::make_shared<YuzuTest>(system, std::move(data), std::move(finish_callback)) - ->InstallAsService(sm); -} - -} // namespace Service::Yuzu diff --git a/src/yuzu_tester/service/yuzutest.h b/src/yuzu_tester/service/yuzutest.h deleted file mode 100644 index 7794814fa..000000000 --- a/src/yuzu_tester/service/yuzutest.h +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#pragma once - -#include <functional> -#include <string> - -namespace Core { -class System; -} - -namespace Service::Yuzu { - -struct TestResult { - u32 code; - std::string data; - std::string name; -}; - -void InstallInterfaces(Core::System& system, std::string data, - std::function<void(std::vector<TestResult>)> finish_callback); - -} // namespace Service::Yuzu diff --git a/src/yuzu_tester/yuzu.cpp b/src/yuzu_tester/yuzu.cpp deleted file mode 100644 index 09cf2ad77..000000000 --- a/src/yuzu_tester/yuzu.cpp +++ /dev/null @@ -1,268 +0,0 @@ -// Copyright 2019 yuzu Emulator Project -// Licensed under GPLv2 or any later version -// Refer to the license.txt file included. - -#include <chrono> -#include <iostream> -#include <memory> -#include <string> -#include <thread> - -#include <fmt/ostream.h> - -#include "common/common_paths.h" -#include "common/detached_tasks.h" -#include "common/file_util.h" -#include "common/logging/backend.h" -#include "common/logging/filter.h" -#include "common/logging/log.h" -#include "common/microprofile.h" -#include "common/scm_rev.h" -#include "common/scope_exit.h" -#include "common/string_util.h" -#include "common/telemetry.h" -#include "core/core.h" -#include "core/crypto/key_manager.h" -#include "core/file_sys/registered_cache.h" -#include "core/file_sys/vfs_real.h" -#include "core/hle/service/filesystem/filesystem.h" -#include "core/loader/loader.h" -#include "core/settings.h" -#include "core/telemetry_session.h" -#include "video_core/renderer_base.h" -#include "yuzu_tester/config.h" -#include "yuzu_tester/emu_window/emu_window_sdl2_hide.h" -#include "yuzu_tester/service/yuzutest.h" - -#ifdef _WIN32 -// windows.h needs to be included before shellapi.h -#include <windows.h> - -#include <shellapi.h> -#endif - -#undef _UNICODE -#include <getopt.h> -#ifndef _MSC_VER -#include <unistd.h> -#endif - -#ifdef _WIN32 -extern "C" { -// tells Nvidia and AMD drivers to use the dedicated GPU by default on laptops with switchable -// graphics -__declspec(dllexport) unsigned long NvOptimusEnablement = 0x00000001; -__declspec(dllexport) int AmdPowerXpressRequestHighPerformance = 1; -} -#endif - -static void PrintHelp(const char* argv0) { - std::cout << "Usage: " << argv0 - << " [options] <filename>\n" - "-h, --help Display this help and exit\n" - "-v, --version Output version information and exit\n" - "-d, --datastring Pass following string as data to test service command #2\n" - "-l, --log Log to console in addition to file (will log to file only " - "by default)\n"; -} - -static void PrintVersion() { - std::cout << "yuzu [Test Utility] " << Common::g_scm_branch << " " << Common::g_scm_desc - << std::endl; -} - -static void InitializeLogging(bool console) { - Log::Filter log_filter(Log::Level::Debug); - log_filter.ParseFilterString(Settings::values.log_filter); - Log::SetGlobalFilter(log_filter); - - if (console) - Log::AddBackend(std::make_unique<Log::ColorConsoleBackend>()); - - const std::string& log_dir = Common::FS::GetUserPath(Common::FS::UserPath::LogDir); - Common::FS::CreateFullPath(log_dir); - Log::AddBackend(std::make_unique<Log::FileBackend>(log_dir + LOG_FILE)); -#ifdef _WIN32 - Log::AddBackend(std::make_unique<Log::DebuggerBackend>()); -#endif -} - -/// Application entry point -int main(int argc, char** argv) { - Common::DetachedTasks detached_tasks; - Config config; - - int option_index = 0; - -#ifdef _WIN32 - int argc_w; - auto argv_w = CommandLineToArgvW(GetCommandLineW(), &argc_w); - - if (argv_w == nullptr) { - std::cout << "Failed to get command line arguments" << std::endl; - return -1; - } -#endif - std::string filepath; - - static struct option long_options[] = { - {"help", no_argument, 0, 'h'}, - {"version", no_argument, 0, 'v'}, - {"datastring", optional_argument, 0, 'd'}, - {"log", no_argument, 0, 'l'}, - {0, 0, 0, 0}, - }; - - bool console_log = false; - std::string datastring; - - while (optind < argc) { - int arg = getopt_long(argc, argv, "hvdl::", long_options, &option_index); - if (arg != -1) { - switch (static_cast<char>(arg)) { - case 'h': - PrintHelp(argv[0]); - return 0; - case 'v': - PrintVersion(); - return 0; - case 'd': - datastring = argv[optind]; - ++optind; - break; - case 'l': - console_log = true; - break; - } - } else { -#ifdef _WIN32 - filepath = Common::UTF16ToUTF8(argv_w[optind]); -#else - filepath = argv[optind]; -#endif - optind++; - } - } - - InitializeLogging(console_log); - -#ifdef _WIN32 - LocalFree(argv_w); -#endif - - MicroProfileOnThreadCreate("EmuThread"); - SCOPE_EXIT({ MicroProfileShutdown(); }); - - if (filepath.empty()) { - LOG_CRITICAL(Frontend, "Failed to load application: No application specified"); - std::cout << "Failed to load application: No application specified" << std::endl; - PrintHelp(argv[0]); - return -1; - } - - Core::System& system{Core::System::GetInstance()}; - - Settings::Apply(system); - - const auto emu_window{std::make_unique<EmuWindow_SDL2_Hide>()}; - - bool finished = false; - int return_value = 0; - const auto callback = [&finished, - &return_value](std::vector<Service::Yuzu::TestResult> results) { - finished = true; - return_value = 0; - - // Find the minimum length needed to fully enclose all test names (and the header field) in - // the fmt::format column by first finding the maximum size of any test name and comparing - // that to 9, the string length of 'Test Name' - const auto needed_length_name = - std::max<u64>(std::max_element(results.begin(), results.end(), - [](const auto& lhs, const auto& rhs) { - return lhs.name.size() < rhs.name.size(); - }) - ->name.size(), - 9ull); - - std::size_t passed = 0; - std::size_t failed = 0; - - std::cout << fmt::format("Result [Res Code] | {:<{}} | Extra Data", "Test Name", - needed_length_name) - << std::endl; - - for (const auto& res : results) { - const auto main_res = res.code == 0 ? "PASSED" : "FAILED"; - if (res.code == 0) - ++passed; - else - ++failed; - std::cout << fmt::format("{} [{:08X}] | {:<{}} | {}", main_res, res.code, res.name, - needed_length_name, res.data) - << std::endl; - } - - std::cout << std::endl - << fmt::format("{:4d} Passed | {:4d} Failed | {:4d} Total | {:2.2f} Passed Ratio", - passed, failed, passed + failed, - static_cast<float>(passed) / (passed + failed)) - << std::endl - << (failed == 0 ? "PASSED" : "FAILED") << std::endl; - - if (failed > 0) - return_value = -1; - }; - - system.SetContentProvider(std::make_unique<FileSys::ContentProviderUnion>()); - system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); - system.GetFileSystemController().CreateFactories(*system.GetFilesystem()); - - SCOPE_EXIT({ system.Shutdown(); }); - - const Core::System::ResultStatus load_result{system.Load(*emu_window, filepath)}; - - switch (load_result) { - case Core::System::ResultStatus::ErrorGetLoader: - LOG_CRITICAL(Frontend, "Failed to obtain loader for {}!", filepath); - return -1; - case Core::System::ResultStatus::ErrorLoader: - LOG_CRITICAL(Frontend, "Failed to load ROM!"); - return -1; - case Core::System::ResultStatus::ErrorNotInitialized: - LOG_CRITICAL(Frontend, "CPUCore not initialized"); - return -1; - case Core::System::ResultStatus::ErrorVideoCore: - LOG_CRITICAL(Frontend, "Failed to initialize VideoCore!"); - return -1; - case Core::System::ResultStatus::Success: - break; // Expected case - default: - if (static_cast<u32>(load_result) > - static_cast<u32>(Core::System::ResultStatus::ErrorLoader)) { - const u16 loader_id = static_cast<u16>(Core::System::ResultStatus::ErrorLoader); - const u16 error_id = static_cast<u16>(load_result) - loader_id; - LOG_CRITICAL(Frontend, - "While attempting to load the ROM requested, an error occurred. Please " - "refer to the yuzu wiki for more information or the yuzu discord for " - "additional help.\n\nError Code: {:04X}-{:04X}\nError Description: {}", - loader_id, error_id, static_cast<Loader::ResultStatus>(error_id)); - } - break; - } - - Service::Yuzu::InstallInterfaces(system, datastring, callback); - - system.TelemetrySession().AddField(Common::Telemetry::FieldType::App, "Frontend", - "SDLHideTester"); - - system.GPU().Start(); - - void(system.Run()); - while (!finished) { - std::this_thread::sleep_for(std::chrono::milliseconds(1)); - } - void(system.Pause()); - - detached_tasks.WaitForAllTasks(); - return return_value; -} diff --git a/src/yuzu_tester/yuzu.rc b/src/yuzu_tester/yuzu.rc deleted file mode 100644 index 0cde75e2f..000000000 --- a/src/yuzu_tester/yuzu.rc +++ /dev/null @@ -1,17 +0,0 @@ -#include "winresrc.h" -///////////////////////////////////////////////////////////////////////////// -// -// Icon -// - -// Icon with lowest ID value placed first to ensure application icon -// remains consistent on all systems. -YUZU_ICON ICON "../../dist/yuzu.ico" - - -///////////////////////////////////////////////////////////////////////////// -// -// RT_MANIFEST -// - -0 RT_MANIFEST "../../dist/yuzu.manifest" |