diff options
| author | 2018-08-11 10:35:47 +1000 | |
|---|---|---|
| committer | 2018-08-11 10:35:47 +1000 | |
| commit | b76ddb7647cbb390cce4143d91a1db171b0fa503 (patch) | |
| tree | a6e2e334e82b035923c41458150604dd5fb31d65 /src | |
| parent | Added IsUserRegistrationRequestPermitted (diff) | |
| parent | Merge pull request #1007 from MerryMage/dynarmic (diff) | |
| download | yuzu-b76ddb7647cbb390cce4143d91a1db171b0fa503.tar.gz yuzu-b76ddb7647cbb390cce4143d91a1db171b0fa503.tar.xz yuzu-b76ddb7647cbb390cce4143d91a1db171b0fa503.zip | |
Merge remote-tracking branch 'origin/master' into better-account
Diffstat (limited to 'src')
76 files changed, 1562 insertions, 634 deletions
diff --git a/src/common/alignment.h b/src/common/alignment.h index b77da4a92..b9dd38746 100644 --- a/src/common/alignment.h +++ b/src/common/alignment.h | |||
| @@ -9,13 +9,13 @@ namespace Common { | |||
| 9 | 9 | ||
| 10 | template <typename T> | 10 | template <typename T> |
| 11 | constexpr T AlignUp(T value, size_t size) { | 11 | constexpr T AlignUp(T value, size_t size) { |
| 12 | static_assert(std::is_unsigned<T>::value, "T must be an unsigned value."); | 12 | static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); |
| 13 | return static_cast<T>(value + (size - value % size) % size); | 13 | return static_cast<T>(value + (size - value % size) % size); |
| 14 | } | 14 | } |
| 15 | 15 | ||
| 16 | template <typename T> | 16 | template <typename T> |
| 17 | constexpr T AlignDown(T value, size_t size) { | 17 | constexpr T AlignDown(T value, size_t size) { |
| 18 | static_assert(std::is_unsigned<T>::value, "T must be an unsigned value."); | 18 | static_assert(std::is_unsigned_v<T>, "T must be an unsigned value."); |
| 19 | return static_cast<T>(value - value % size); | 19 | return static_cast<T>(value - value % size); |
| 20 | } | 20 | } |
| 21 | 21 | ||
diff --git a/src/common/bit_set.h b/src/common/bit_set.h index 84e3cbe58..5a197d8c1 100644 --- a/src/common/bit_set.h +++ b/src/common/bit_set.h | |||
| @@ -96,7 +96,7 @@ static inline int LeastSignificantSetBit(u64 val) { | |||
| 96 | 96 | ||
| 97 | template <typename IntTy> | 97 | template <typename IntTy> |
| 98 | class BitSet { | 98 | class BitSet { |
| 99 | static_assert(!std::is_signed<IntTy>::value, "BitSet should not be used with signed types"); | 99 | static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types"); |
| 100 | 100 | ||
| 101 | public: | 101 | public: |
| 102 | // A reference to a particular bit, returned from operator[]. | 102 | // A reference to a particular bit, returned from operator[]. |
diff --git a/src/common/color.h b/src/common/color.h index 24a445dac..0379040be 100644 --- a/src/common/color.h +++ b/src/common/color.h | |||
| @@ -4,6 +4,8 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <cstring> | ||
| 8 | |||
| 7 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 8 | #include "common/swap.h" | 10 | #include "common/swap.h" |
| 9 | #include "common/vector_math.h" | 11 | #include "common/vector_math.h" |
| @@ -55,7 +57,7 @@ constexpr u8 Convert8To6(u8 value) { | |||
| 55 | * @param bytes Pointer to encoded source color | 57 | * @param bytes Pointer to encoded source color |
| 56 | * @return Result color decoded as Math::Vec4<u8> | 58 | * @return Result color decoded as Math::Vec4<u8> |
| 57 | */ | 59 | */ |
| 58 | inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) { | 60 | inline Math::Vec4<u8> DecodeRGBA8(const u8* bytes) { |
| 59 | return {bytes[3], bytes[2], bytes[1], bytes[0]}; | 61 | return {bytes[3], bytes[2], bytes[1], bytes[0]}; |
| 60 | } | 62 | } |
| 61 | 63 | ||
| @@ -64,7 +66,7 @@ inline const Math::Vec4<u8> DecodeRGBA8(const u8* bytes) { | |||
| 64 | * @param bytes Pointer to encoded source color | 66 | * @param bytes Pointer to encoded source color |
| 65 | * @return Result color decoded as Math::Vec4<u8> | 67 | * @return Result color decoded as Math::Vec4<u8> |
| 66 | */ | 68 | */ |
| 67 | inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) { | 69 | inline Math::Vec4<u8> DecodeRGB8(const u8* bytes) { |
| 68 | return {bytes[2], bytes[1], bytes[0], 255}; | 70 | return {bytes[2], bytes[1], bytes[0], 255}; |
| 69 | } | 71 | } |
| 70 | 72 | ||
| @@ -73,7 +75,7 @@ inline const Math::Vec4<u8> DecodeRGB8(const u8* bytes) { | |||
| 73 | * @param bytes Pointer to encoded source color | 75 | * @param bytes Pointer to encoded source color |
| 74 | * @return Result color decoded as Math::Vec4<u8> | 76 | * @return Result color decoded as Math::Vec4<u8> |
| 75 | */ | 77 | */ |
| 76 | inline const Math::Vec4<u8> DecodeRG8(const u8* bytes) { | 78 | inline Math::Vec4<u8> DecodeRG8(const u8* bytes) { |
| 77 | return {bytes[1], bytes[0], 0, 255}; | 79 | return {bytes[1], bytes[0], 0, 255}; |
| 78 | } | 80 | } |
| 79 | 81 | ||
| @@ -82,8 +84,9 @@ inline const Math::Vec4<u8> DecodeRG8(const u8* bytes) { | |||
| 82 | * @param bytes Pointer to encoded source color | 84 | * @param bytes Pointer to encoded source color |
| 83 | * @return Result color decoded as Math::Vec4<u8> | 85 | * @return Result color decoded as Math::Vec4<u8> |
| 84 | */ | 86 | */ |
| 85 | inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) { | 87 | inline Math::Vec4<u8> DecodeRGB565(const u8* bytes) { |
| 86 | const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); | 88 | u16_le pixel; |
| 89 | std::memcpy(&pixel, bytes, sizeof(pixel)); | ||
| 87 | return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F), | 90 | return {Convert5To8((pixel >> 11) & 0x1F), Convert6To8((pixel >> 5) & 0x3F), |
| 88 | Convert5To8(pixel & 0x1F), 255}; | 91 | Convert5To8(pixel & 0x1F), 255}; |
| 89 | } | 92 | } |
| @@ -93,8 +96,9 @@ inline const Math::Vec4<u8> DecodeRGB565(const u8* bytes) { | |||
| 93 | * @param bytes Pointer to encoded source color | 96 | * @param bytes Pointer to encoded source color |
| 94 | * @return Result color decoded as Math::Vec4<u8> | 97 | * @return Result color decoded as Math::Vec4<u8> |
| 95 | */ | 98 | */ |
| 96 | inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) { | 99 | inline Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) { |
| 97 | const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); | 100 | u16_le pixel; |
| 101 | std::memcpy(&pixel, bytes, sizeof(pixel)); | ||
| 98 | return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F), | 102 | return {Convert5To8((pixel >> 11) & 0x1F), Convert5To8((pixel >> 6) & 0x1F), |
| 99 | Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1)}; | 103 | Convert5To8((pixel >> 1) & 0x1F), Convert1To8(pixel & 0x1)}; |
| 100 | } | 104 | } |
| @@ -104,8 +108,9 @@ inline const Math::Vec4<u8> DecodeRGB5A1(const u8* bytes) { | |||
| 104 | * @param bytes Pointer to encoded source color | 108 | * @param bytes Pointer to encoded source color |
| 105 | * @return Result color decoded as Math::Vec4<u8> | 109 | * @return Result color decoded as Math::Vec4<u8> |
| 106 | */ | 110 | */ |
| 107 | inline const Math::Vec4<u8> DecodeRGBA4(const u8* bytes) { | 111 | inline Math::Vec4<u8> DecodeRGBA4(const u8* bytes) { |
| 108 | const u16_le pixel = *reinterpret_cast<const u16_le*>(bytes); | 112 | u16_le pixel; |
| 113 | std::memcpy(&pixel, bytes, sizeof(pixel)); | ||
| 109 | return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF), | 114 | return {Convert4To8((pixel >> 12) & 0xF), Convert4To8((pixel >> 8) & 0xF), |
| 110 | Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF)}; | 115 | Convert4To8((pixel >> 4) & 0xF), Convert4To8(pixel & 0xF)}; |
| 111 | } | 116 | } |
| @@ -116,7 +121,9 @@ inline const Math::Vec4<u8> DecodeRGBA4(const u8* bytes) { | |||
| 116 | * @return Depth value as an u32 | 121 | * @return Depth value as an u32 |
| 117 | */ | 122 | */ |
| 118 | inline u32 DecodeD16(const u8* bytes) { | 123 | inline u32 DecodeD16(const u8* bytes) { |
| 119 | return *reinterpret_cast<const u16_le*>(bytes); | 124 | u16_le data; |
| 125 | std::memcpy(&data, bytes, sizeof(data)); | ||
| 126 | return data; | ||
| 120 | } | 127 | } |
| 121 | 128 | ||
| 122 | /** | 129 | /** |
| @@ -133,7 +140,7 @@ inline u32 DecodeD24(const u8* bytes) { | |||
| 133 | * @param bytes Pointer to encoded source values | 140 | * @param bytes Pointer to encoded source values |
| 134 | * @return Resulting values stored as a Math::Vec2 | 141 | * @return Resulting values stored as a Math::Vec2 |
| 135 | */ | 142 | */ |
| 136 | inline const Math::Vec2<u32> DecodeD24S8(const u8* bytes) { | 143 | inline Math::Vec2<u32> DecodeD24S8(const u8* bytes) { |
| 137 | return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]}; | 144 | return {static_cast<u32>((bytes[2] << 16) | (bytes[1] << 8) | bytes[0]), bytes[3]}; |
| 138 | } | 145 | } |
| 139 | 146 | ||
| @@ -175,8 +182,10 @@ inline void EncodeRG8(const Math::Vec4<u8>& color, u8* bytes) { | |||
| 175 | * @param bytes Destination pointer to store encoded color | 182 | * @param bytes Destination pointer to store encoded color |
| 176 | */ | 183 | */ |
| 177 | inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) { | 184 | inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) { |
| 178 | *reinterpret_cast<u16_le*>(bytes) = | 185 | const u16_le data = |
| 179 | (Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b()); | 186 | (Convert8To5(color.r()) << 11) | (Convert8To6(color.g()) << 5) | Convert8To5(color.b()); |
| 187 | |||
| 188 | std::memcpy(bytes, &data, sizeof(data)); | ||
| 180 | } | 189 | } |
| 181 | 190 | ||
| 182 | /** | 191 | /** |
| @@ -185,9 +194,10 @@ inline void EncodeRGB565(const Math::Vec4<u8>& color, u8* bytes) { | |||
| 185 | * @param bytes Destination pointer to store encoded color | 194 | * @param bytes Destination pointer to store encoded color |
| 186 | */ | 195 | */ |
| 187 | inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) { | 196 | inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) { |
| 188 | *reinterpret_cast<u16_le*>(bytes) = (Convert8To5(color.r()) << 11) | | 197 | const u16_le data = (Convert8To5(color.r()) << 11) | (Convert8To5(color.g()) << 6) | |
| 189 | (Convert8To5(color.g()) << 6) | | 198 | (Convert8To5(color.b()) << 1) | Convert8To1(color.a()); |
| 190 | (Convert8To5(color.b()) << 1) | Convert8To1(color.a()); | 199 | |
| 200 | std::memcpy(bytes, &data, sizeof(data)); | ||
| 191 | } | 201 | } |
| 192 | 202 | ||
| 193 | /** | 203 | /** |
| @@ -196,9 +206,10 @@ inline void EncodeRGB5A1(const Math::Vec4<u8>& color, u8* bytes) { | |||
| 196 | * @param bytes Destination pointer to store encoded color | 206 | * @param bytes Destination pointer to store encoded color |
| 197 | */ | 207 | */ |
| 198 | inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) { | 208 | inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) { |
| 199 | *reinterpret_cast<u16_le*>(bytes) = (Convert8To4(color.r()) << 12) | | 209 | const u16 data = (Convert8To4(color.r()) << 12) | (Convert8To4(color.g()) << 8) | |
| 200 | (Convert8To4(color.g()) << 8) | | 210 | (Convert8To4(color.b()) << 4) | Convert8To4(color.a()); |
| 201 | (Convert8To4(color.b()) << 4) | Convert8To4(color.a()); | 211 | |
| 212 | std::memcpy(bytes, &data, sizeof(data)); | ||
| 202 | } | 213 | } |
| 203 | 214 | ||
| 204 | /** | 215 | /** |
| @@ -207,7 +218,8 @@ inline void EncodeRGBA4(const Math::Vec4<u8>& color, u8* bytes) { | |||
| 207 | * @param bytes Pointer where to store the encoded value | 218 | * @param bytes Pointer where to store the encoded value |
| 208 | */ | 219 | */ |
| 209 | inline void EncodeD16(u32 value, u8* bytes) { | 220 | inline void EncodeD16(u32 value, u8* bytes) { |
| 210 | *reinterpret_cast<u16_le*>(bytes) = value & 0xFFFF; | 221 | const u16_le data = static_cast<u16>(value); |
| 222 | std::memcpy(bytes, &data, sizeof(data)); | ||
| 211 | } | 223 | } |
| 212 | 224 | ||
| 213 | /** | 225 | /** |
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp index 7aeda737f..3ce590062 100644 --- a/src/common/file_util.cpp +++ b/src/common/file_util.cpp | |||
| @@ -884,11 +884,21 @@ std::string_view RemoveTrailingSlash(std::string_view path) { | |||
| 884 | return path; | 884 | return path; |
| 885 | } | 885 | } |
| 886 | 886 | ||
| 887 | std::string SanitizePath(std::string_view path_) { | 887 | std::string SanitizePath(std::string_view path_, DirectorySeparator directory_separator) { |
| 888 | std::string path(path_); | 888 | std::string path(path_); |
| 889 | std::replace(path.begin(), path.end(), '\\', '/'); | 889 | char type1 = directory_separator == DirectorySeparator::BackwardSlash ? '/' : '\\'; |
| 890 | char type2 = directory_separator == DirectorySeparator::BackwardSlash ? '\\' : '/'; | ||
| 891 | |||
| 892 | if (directory_separator == DirectorySeparator::PlatformDefault) { | ||
| 893 | #ifdef _WIN32 | ||
| 894 | type1 = '/'; | ||
| 895 | type2 = '\\'; | ||
| 896 | #endif | ||
| 897 | } | ||
| 898 | |||
| 899 | std::replace(path.begin(), path.end(), type1, type2); | ||
| 890 | path.erase(std::unique(path.begin(), path.end(), | 900 | path.erase(std::unique(path.begin(), path.end(), |
| 891 | [](char c1, char c2) { return c1 == '/' && c2 == '/'; }), | 901 | [type2](char c1, char c2) { return c1 == type2 && c2 == type2; }), |
| 892 | path.end()); | 902 | path.end()); |
| 893 | return std::string(RemoveTrailingSlash(path)); | 903 | return std::string(RemoveTrailingSlash(path)); |
| 894 | } | 904 | } |
diff --git a/src/common/file_util.h b/src/common/file_util.h index 430dac41c..2711872ae 100644 --- a/src/common/file_util.h +++ b/src/common/file_util.h | |||
| @@ -182,8 +182,12 @@ std::vector<T> SliceVector(const std::vector<T>& vector, size_t first, size_t la | |||
| 182 | return std::vector<T>(vector.begin() + first, vector.begin() + first + last); | 182 | return std::vector<T>(vector.begin() + first, vector.begin() + first + last); |
| 183 | } | 183 | } |
| 184 | 184 | ||
| 185 | // Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. | 185 | enum class DirectorySeparator { ForwardSlash, BackwardSlash, PlatformDefault }; |
| 186 | std::string SanitizePath(std::string_view path); | 186 | |
| 187 | // Removes trailing slash, makes all '\\' into '/', and removes duplicate '/'. Makes '/' into '\\' | ||
| 188 | // depending if directory_separator is BackwardSlash or PlatformDefault and running on windows | ||
| 189 | std::string SanitizePath(std::string_view path, | ||
| 190 | DirectorySeparator directory_separator = DirectorySeparator::ForwardSlash); | ||
| 187 | 191 | ||
| 188 | // simple wrapper for cstdlib file functions to | 192 | // simple wrapper for cstdlib file functions to |
| 189 | // hopefully will make error checking easier | 193 | // hopefully will make error checking easier |
| @@ -208,7 +212,7 @@ public: | |||
| 208 | 212 | ||
| 209 | template <typename T> | 213 | template <typename T> |
| 210 | size_t ReadArray(T* data, size_t length) const { | 214 | size_t ReadArray(T* data, size_t length) const { |
| 211 | static_assert(std::is_trivially_copyable<T>(), | 215 | static_assert(std::is_trivially_copyable_v<T>, |
| 212 | "Given array does not consist of trivially copyable objects"); | 216 | "Given array does not consist of trivially copyable objects"); |
| 213 | 217 | ||
| 214 | if (!IsOpen()) { | 218 | if (!IsOpen()) { |
| @@ -220,7 +224,7 @@ public: | |||
| 220 | 224 | ||
| 221 | template <typename T> | 225 | template <typename T> |
| 222 | size_t WriteArray(const T* data, size_t length) { | 226 | size_t WriteArray(const T* data, size_t length) { |
| 223 | static_assert(std::is_trivially_copyable<T>(), | 227 | static_assert(std::is_trivially_copyable_v<T>, |
| 224 | "Given array does not consist of trivially copyable objects"); | 228 | "Given array does not consist of trivially copyable objects"); |
| 225 | if (!IsOpen()) { | 229 | if (!IsOpen()) { |
| 226 | return std::numeric_limits<size_t>::max(); | 230 | return std::numeric_limits<size_t>::max(); |
| @@ -231,19 +235,19 @@ public: | |||
| 231 | 235 | ||
| 232 | template <typename T> | 236 | template <typename T> |
| 233 | size_t ReadBytes(T* data, size_t length) const { | 237 | size_t ReadBytes(T* data, size_t length) const { |
| 234 | static_assert(std::is_trivially_copyable<T>(), "T must be trivially copyable"); | 238 | static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable"); |
| 235 | return ReadArray(reinterpret_cast<char*>(data), length); | 239 | return ReadArray(reinterpret_cast<char*>(data), length); |
| 236 | } | 240 | } |
| 237 | 241 | ||
| 238 | template <typename T> | 242 | template <typename T> |
| 239 | size_t WriteBytes(const T* data, size_t length) { | 243 | size_t WriteBytes(const T* data, size_t length) { |
| 240 | static_assert(std::is_trivially_copyable<T>(), "T must be trivially copyable"); | 244 | static_assert(std::is_trivially_copyable_v<T>, "T must be trivially copyable"); |
| 241 | return WriteArray(reinterpret_cast<const char*>(data), length); | 245 | return WriteArray(reinterpret_cast<const char*>(data), length); |
| 242 | } | 246 | } |
| 243 | 247 | ||
| 244 | template <typename T> | 248 | template <typename T> |
| 245 | size_t WriteObject(const T& object) { | 249 | size_t WriteObject(const T& object) { |
| 246 | static_assert(!std::is_pointer<T>::value, "Given object is a pointer"); | 250 | static_assert(!std::is_pointer_v<T>, "WriteObject arguments must not be a pointer"); |
| 247 | return WriteArray(&object, 1); | 251 | return WriteArray(&object, 1); |
| 248 | } | 252 | } |
| 249 | 253 | ||
diff --git a/src/common/hash.h b/src/common/hash.h index 73c326980..2c761e545 100644 --- a/src/common/hash.h +++ b/src/common/hash.h | |||
| @@ -28,7 +28,7 @@ static inline u64 ComputeHash64(const void* data, size_t len) { | |||
| 28 | */ | 28 | */ |
| 29 | template <typename T> | 29 | template <typename T> |
| 30 | static inline u64 ComputeStructHash64(const T& data) { | 30 | static inline u64 ComputeStructHash64(const T& data) { |
| 31 | static_assert(std::is_trivially_copyable<T>(), | 31 | static_assert(std::is_trivially_copyable_v<T>, |
| 32 | "Type passed to ComputeStructHash64 must be trivially copyable"); | 32 | "Type passed to ComputeStructHash64 must be trivially copyable"); |
| 33 | return ComputeHash64(&data, sizeof(data)); | 33 | return ComputeHash64(&data, sizeof(data)); |
| 34 | } | 34 | } |
| @@ -38,7 +38,7 @@ template <typename T> | |||
| 38 | struct HashableStruct { | 38 | struct HashableStruct { |
| 39 | // In addition to being trivially copyable, T must also have a trivial default constructor, | 39 | // In addition to being trivially copyable, T must also have a trivial default constructor, |
| 40 | // because any member initialization would be overridden by memset | 40 | // because any member initialization would be overridden by memset |
| 41 | static_assert(std::is_trivial<T>(), "Type passed to HashableStruct must be trivial"); | 41 | static_assert(std::is_trivial_v<T>, "Type passed to HashableStruct must be trivial"); |
| 42 | /* | 42 | /* |
| 43 | * We use a union because "implicitly-defined copy/move constructor for a union X copies the | 43 | * We use a union because "implicitly-defined copy/move constructor for a union X copies the |
| 44 | * object representation of X." and "implicitly-defined copy assignment operator for a union X | 44 | * object representation of X." and "implicitly-defined copy assignment operator for a union X |
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp index 355abd682..e80784c3c 100644 --- a/src/common/logging/backend.cpp +++ b/src/common/logging/backend.cpp | |||
| @@ -171,15 +171,21 @@ void FileBackend::Write(const Entry& entry) { | |||
| 171 | SUB(Service, ARP) \ | 171 | SUB(Service, ARP) \ |
| 172 | SUB(Service, BCAT) \ | 172 | SUB(Service, BCAT) \ |
| 173 | SUB(Service, BPC) \ | 173 | SUB(Service, BPC) \ |
| 174 | SUB(Service, BTDRV) \ | ||
| 174 | SUB(Service, BTM) \ | 175 | SUB(Service, BTM) \ |
| 175 | SUB(Service, Capture) \ | 176 | SUB(Service, Capture) \ |
| 177 | SUB(Service, ERPT) \ | ||
| 178 | SUB(Service, ETicket) \ | ||
| 179 | SUB(Service, EUPLD) \ | ||
| 176 | SUB(Service, Fatal) \ | 180 | SUB(Service, Fatal) \ |
| 177 | SUB(Service, FGM) \ | 181 | SUB(Service, FGM) \ |
| 178 | SUB(Service, Friend) \ | 182 | SUB(Service, Friend) \ |
| 179 | SUB(Service, FS) \ | 183 | SUB(Service, FS) \ |
| 184 | SUB(Service, GRC) \ | ||
| 180 | SUB(Service, HID) \ | 185 | SUB(Service, HID) \ |
| 181 | SUB(Service, LBL) \ | 186 | SUB(Service, LBL) \ |
| 182 | SUB(Service, LDN) \ | 187 | SUB(Service, LDN) \ |
| 188 | SUB(Service, LDR) \ | ||
| 183 | SUB(Service, LM) \ | 189 | SUB(Service, LM) \ |
| 184 | SUB(Service, Migration) \ | 190 | SUB(Service, Migration) \ |
| 185 | SUB(Service, Mii) \ | 191 | SUB(Service, Mii) \ |
| @@ -188,11 +194,13 @@ void FileBackend::Write(const Entry& entry) { | |||
| 188 | SUB(Service, NFC) \ | 194 | SUB(Service, NFC) \ |
| 189 | SUB(Service, NFP) \ | 195 | SUB(Service, NFP) \ |
| 190 | SUB(Service, NIFM) \ | 196 | SUB(Service, NIFM) \ |
| 197 | SUB(Service, NIM) \ | ||
| 191 | SUB(Service, NS) \ | 198 | SUB(Service, NS) \ |
| 192 | SUB(Service, NVDRV) \ | 199 | SUB(Service, NVDRV) \ |
| 193 | SUB(Service, PCIE) \ | 200 | SUB(Service, PCIE) \ |
| 194 | SUB(Service, PCTL) \ | 201 | SUB(Service, PCTL) \ |
| 195 | SUB(Service, PCV) \ | 202 | SUB(Service, PCV) \ |
| 203 | SUB(Service, PM) \ | ||
| 196 | SUB(Service, PREPO) \ | 204 | SUB(Service, PREPO) \ |
| 197 | SUB(Service, PSC) \ | 205 | SUB(Service, PSC) \ |
| 198 | SUB(Service, SET) \ | 206 | SUB(Service, SET) \ |
diff --git a/src/common/logging/log.h b/src/common/logging/log.h index a889ebefa..e12f47f8f 100644 --- a/src/common/logging/log.h +++ b/src/common/logging/log.h | |||
| @@ -58,15 +58,21 @@ enum class Class : ClassType { | |||
| 58 | Service_Audio, ///< The Audio (Audio control) service | 58 | Service_Audio, ///< The Audio (Audio control) service |
| 59 | Service_BCAT, ///< The BCAT service | 59 | Service_BCAT, ///< The BCAT service |
| 60 | Service_BPC, ///< The BPC service | 60 | Service_BPC, ///< The BPC service |
| 61 | Service_BTDRV, ///< The Bluetooth driver service | ||
| 61 | Service_BTM, ///< The BTM service | 62 | Service_BTM, ///< The BTM service |
| 62 | Service_Capture, ///< The capture service | 63 | Service_Capture, ///< The capture service |
| 64 | Service_ERPT, ///< The error reporting service | ||
| 65 | Service_ETicket, ///< The ETicket service | ||
| 66 | Service_EUPLD, ///< The error upload service | ||
| 63 | Service_Fatal, ///< The Fatal service | 67 | Service_Fatal, ///< The Fatal service |
| 64 | Service_FGM, ///< The FGM service | 68 | Service_FGM, ///< The FGM service |
| 65 | Service_Friend, ///< The friend service | 69 | Service_Friend, ///< The friend service |
| 66 | Service_FS, ///< The FS (Filesystem) service | 70 | Service_FS, ///< The FS (Filesystem) service |
| 71 | Service_GRC, ///< The game recording service | ||
| 67 | Service_HID, ///< The HID (Human interface device) service | 72 | Service_HID, ///< The HID (Human interface device) service |
| 68 | Service_LBL, ///< The LBL (LCD backlight) service | 73 | Service_LBL, ///< The LBL (LCD backlight) service |
| 69 | Service_LDN, ///< The LDN (Local domain network) service | 74 | Service_LDN, ///< The LDN (Local domain network) service |
| 75 | Service_LDR, ///< The loader service | ||
| 70 | Service_LM, ///< The LM (Logger) service | 76 | Service_LM, ///< The LM (Logger) service |
| 71 | Service_Migration, ///< The migration service | 77 | Service_Migration, ///< The migration service |
| 72 | Service_Mii, ///< The Mii service | 78 | Service_Mii, ///< The Mii service |
| @@ -75,11 +81,13 @@ enum class Class : ClassType { | |||
| 75 | Service_NFC, ///< The NFC (Near-field communication) service | 81 | Service_NFC, ///< The NFC (Near-field communication) service |
| 76 | Service_NFP, ///< The NFP service | 82 | Service_NFP, ///< The NFP service |
| 77 | Service_NIFM, ///< The NIFM (Network interface) service | 83 | Service_NIFM, ///< The NIFM (Network interface) service |
| 84 | Service_NIM, ///< The NIM service | ||
| 78 | Service_NS, ///< The NS services | 85 | Service_NS, ///< The NS services |
| 79 | Service_NVDRV, ///< The NVDRV (Nvidia driver) service | 86 | Service_NVDRV, ///< The NVDRV (Nvidia driver) service |
| 80 | Service_PCIE, ///< The PCIe service | 87 | Service_PCIE, ///< The PCIe service |
| 81 | Service_PCTL, ///< The PCTL (Parental control) service | 88 | Service_PCTL, ///< The PCTL (Parental control) service |
| 82 | Service_PCV, ///< The PCV service | 89 | Service_PCV, ///< The PCV service |
| 90 | Service_PM, ///< The PM service | ||
| 83 | Service_PREPO, ///< The PREPO (Play report) service | 91 | Service_PREPO, ///< The PREPO (Play report) service |
| 84 | Service_PSC, ///< The PSC service | 92 | Service_PSC, ///< The PSC service |
| 85 | Service_SET, ///< The SET (Settings) service | 93 | Service_SET, ///< The SET (Settings) service |
diff --git a/src/common/vector_math.h b/src/common/vector_math.h index cca43bd4c..8feb49941 100644 --- a/src/common/vector_math.h +++ b/src/common/vector_math.h | |||
| @@ -43,139 +43,135 @@ template <typename T> | |||
| 43 | class Vec4; | 43 | class Vec4; |
| 44 | 44 | ||
| 45 | template <typename T> | 45 | template <typename T> |
| 46 | static inline Vec2<T> MakeVec(const T& x, const T& y); | ||
| 47 | template <typename T> | ||
| 48 | static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z); | ||
| 49 | template <typename T> | ||
| 50 | static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w); | ||
| 51 | |||
| 52 | template <typename T> | ||
| 53 | class Vec2 { | 46 | class Vec2 { |
| 54 | public: | 47 | public: |
| 55 | T x{}; | 48 | T x{}; |
| 56 | T y{}; | 49 | T y{}; |
| 57 | 50 | ||
| 58 | Vec2() = default; | 51 | constexpr Vec2() = default; |
| 59 | Vec2(const T& _x, const T& _y) : x(_x), y(_y) {} | 52 | constexpr Vec2(const T& x_, const T& y_) : x(x_), y(y_) {} |
| 60 | 53 | ||
| 61 | template <typename T2> | 54 | template <typename T2> |
| 62 | Vec2<T2> Cast() const { | 55 | constexpr Vec2<T2> Cast() const { |
| 63 | return Vec2<T2>((T2)x, (T2)y); | 56 | return Vec2<T2>(static_cast<T2>(x), static_cast<T2>(y)); |
| 64 | } | 57 | } |
| 65 | 58 | ||
| 66 | static Vec2 AssignToAll(const T& f) { | 59 | static constexpr Vec2 AssignToAll(const T& f) { |
| 67 | return Vec2<T>(f, f); | 60 | return Vec2{f, f}; |
| 68 | } | 61 | } |
| 69 | 62 | ||
| 70 | Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const { | 63 | constexpr Vec2<decltype(T{} + T{})> operator+(const Vec2& other) const { |
| 71 | return MakeVec(x + other.x, y + other.y); | 64 | return {x + other.x, y + other.y}; |
| 72 | } | 65 | } |
| 73 | void operator+=(const Vec2& other) { | 66 | constexpr Vec2& operator+=(const Vec2& other) { |
| 74 | x += other.x; | 67 | x += other.x; |
| 75 | y += other.y; | 68 | y += other.y; |
| 69 | return *this; | ||
| 76 | } | 70 | } |
| 77 | Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const { | 71 | constexpr Vec2<decltype(T{} - T{})> operator-(const Vec2& other) const { |
| 78 | return MakeVec(x - other.x, y - other.y); | 72 | return {x - other.x, y - other.y}; |
| 79 | } | 73 | } |
| 80 | void operator-=(const Vec2& other) { | 74 | constexpr Vec2& operator-=(const Vec2& other) { |
| 81 | x -= other.x; | 75 | x -= other.x; |
| 82 | y -= other.y; | 76 | y -= other.y; |
| 77 | return *this; | ||
| 83 | } | 78 | } |
| 84 | 79 | ||
| 85 | template <typename U = T> | 80 | template <typename U = T> |
| 86 | Vec2<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const { | 81 | constexpr Vec2<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const { |
| 87 | return MakeVec(-x, -y); | 82 | return {-x, -y}; |
| 88 | } | 83 | } |
| 89 | Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const { | 84 | constexpr Vec2<decltype(T{} * T{})> operator*(const Vec2& other) const { |
| 90 | return MakeVec(x * other.x, y * other.y); | 85 | return {x * other.x, y * other.y}; |
| 91 | } | 86 | } |
| 87 | |||
| 92 | template <typename V> | 88 | template <typename V> |
| 93 | Vec2<decltype(T{} * V{})> operator*(const V& f) const { | 89 | constexpr Vec2<decltype(T{} * V{})> operator*(const V& f) const { |
| 94 | return MakeVec(x * f, y * f); | 90 | return {x * f, y * f}; |
| 95 | } | 91 | } |
| 92 | |||
| 96 | template <typename V> | 93 | template <typename V> |
| 97 | void operator*=(const V& f) { | 94 | constexpr Vec2& operator*=(const V& f) { |
| 98 | *this = *this * f; | 95 | *this = *this * f; |
| 96 | return *this; | ||
| 99 | } | 97 | } |
| 98 | |||
| 100 | template <typename V> | 99 | template <typename V> |
| 101 | Vec2<decltype(T{} / V{})> operator/(const V& f) const { | 100 | constexpr Vec2<decltype(T{} / V{})> operator/(const V& f) const { |
| 102 | return MakeVec(x / f, y / f); | 101 | return {x / f, y / f}; |
| 103 | } | 102 | } |
| 103 | |||
| 104 | template <typename V> | 104 | template <typename V> |
| 105 | void operator/=(const V& f) { | 105 | constexpr Vec2& operator/=(const V& f) { |
| 106 | *this = *this / f; | 106 | *this = *this / f; |
| 107 | return *this; | ||
| 107 | } | 108 | } |
| 108 | 109 | ||
| 109 | T Length2() const { | 110 | constexpr T Length2() const { |
| 110 | return x * x + y * y; | 111 | return x * x + y * y; |
| 111 | } | 112 | } |
| 112 | 113 | ||
| 113 | // Only implemented for T=float | 114 | // Only implemented for T=float |
| 114 | float Length() const; | 115 | float Length() const; |
| 115 | void SetLength(const float l); | ||
| 116 | Vec2 WithLength(const float l) const; | ||
| 117 | float Distance2To(Vec2& other); | ||
| 118 | Vec2 Normalized() const; | ||
| 119 | float Normalize(); // returns the previous length, which is often useful | 116 | float Normalize(); // returns the previous length, which is often useful |
| 120 | 117 | ||
| 121 | T& operator[](int i) // allow vector[1] = 3 (vector.y=3) | 118 | constexpr T& operator[](std::size_t i) { |
| 122 | { | ||
| 123 | return *((&x) + i); | 119 | return *((&x) + i); |
| 124 | } | 120 | } |
| 125 | T operator[](const int i) const { | 121 | constexpr const T& operator[](std::size_t i) const { |
| 126 | return *((&x) + i); | 122 | return *((&x) + i); |
| 127 | } | 123 | } |
| 128 | 124 | ||
| 129 | void SetZero() { | 125 | constexpr void SetZero() { |
| 130 | x = 0; | 126 | x = 0; |
| 131 | y = 0; | 127 | y = 0; |
| 132 | } | 128 | } |
| 133 | 129 | ||
| 134 | // Common aliases: UV (texel coordinates), ST (texture coordinates) | 130 | // Common aliases: UV (texel coordinates), ST (texture coordinates) |
| 135 | T& u() { | 131 | constexpr T& u() { |
| 136 | return x; | 132 | return x; |
| 137 | } | 133 | } |
| 138 | T& v() { | 134 | constexpr T& v() { |
| 139 | return y; | 135 | return y; |
| 140 | } | 136 | } |
| 141 | T& s() { | 137 | constexpr T& s() { |
| 142 | return x; | 138 | return x; |
| 143 | } | 139 | } |
| 144 | T& t() { | 140 | constexpr T& t() { |
| 145 | return y; | 141 | return y; |
| 146 | } | 142 | } |
| 147 | 143 | ||
| 148 | const T& u() const { | 144 | constexpr const T& u() const { |
| 149 | return x; | 145 | return x; |
| 150 | } | 146 | } |
| 151 | const T& v() const { | 147 | constexpr const T& v() const { |
| 152 | return y; | 148 | return y; |
| 153 | } | 149 | } |
| 154 | const T& s() const { | 150 | constexpr const T& s() const { |
| 155 | return x; | 151 | return x; |
| 156 | } | 152 | } |
| 157 | const T& t() const { | 153 | constexpr const T& t() const { |
| 158 | return y; | 154 | return y; |
| 159 | } | 155 | } |
| 160 | 156 | ||
| 161 | // swizzlers - create a subvector of specific components | 157 | // swizzlers - create a subvector of specific components |
| 162 | const Vec2 yx() const { | 158 | constexpr Vec2 yx() const { |
| 163 | return Vec2(y, x); | 159 | return Vec2(y, x); |
| 164 | } | 160 | } |
| 165 | const Vec2 vu() const { | 161 | constexpr Vec2 vu() const { |
| 166 | return Vec2(y, x); | 162 | return Vec2(y, x); |
| 167 | } | 163 | } |
| 168 | const Vec2 ts() const { | 164 | constexpr Vec2 ts() const { |
| 169 | return Vec2(y, x); | 165 | return Vec2(y, x); |
| 170 | } | 166 | } |
| 171 | }; | 167 | }; |
| 172 | 168 | ||
| 173 | template <typename T, typename V> | 169 | template <typename T, typename V> |
| 174 | Vec2<T> operator*(const V& f, const Vec2<T>& vec) { | 170 | constexpr Vec2<T> operator*(const V& f, const Vec2<T>& vec) { |
| 175 | return Vec2<T>(f * vec.x, f * vec.y); | 171 | return Vec2<T>(f * vec.x, f * vec.y); |
| 176 | } | 172 | } |
| 177 | 173 | ||
| 178 | typedef Vec2<float> Vec2f; | 174 | using Vec2f = Vec2<float>; |
| 179 | 175 | ||
| 180 | template <> | 176 | template <> |
| 181 | inline float Vec2<float>::Length() const { | 177 | inline float Vec2<float>::Length() const { |
| @@ -196,147 +192,151 @@ public: | |||
| 196 | T y{}; | 192 | T y{}; |
| 197 | T z{}; | 193 | T z{}; |
| 198 | 194 | ||
| 199 | Vec3() = default; | 195 | constexpr Vec3() = default; |
| 200 | Vec3(const T& _x, const T& _y, const T& _z) : x(_x), y(_y), z(_z) {} | 196 | constexpr Vec3(const T& x_, const T& y_, const T& z_) : x(x_), y(y_), z(z_) {} |
| 201 | 197 | ||
| 202 | template <typename T2> | 198 | template <typename T2> |
| 203 | Vec3<T2> Cast() const { | 199 | constexpr Vec3<T2> Cast() const { |
| 204 | return MakeVec<T2>((T2)x, (T2)y, (T2)z); | 200 | return Vec3<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z)); |
| 205 | } | 201 | } |
| 206 | 202 | ||
| 207 | // Only implemented for T=int and T=float | 203 | static constexpr Vec3 AssignToAll(const T& f) { |
| 208 | static Vec3 FromRGB(unsigned int rgb); | 204 | return Vec3(f, f, f); |
| 209 | unsigned int ToRGB() const; // alpha bits set to zero | ||
| 210 | |||
| 211 | static Vec3 AssignToAll(const T& f) { | ||
| 212 | return MakeVec(f, f, f); | ||
| 213 | } | 205 | } |
| 214 | 206 | ||
| 215 | Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const { | 207 | constexpr Vec3<decltype(T{} + T{})> operator+(const Vec3& other) const { |
| 216 | return MakeVec(x + other.x, y + other.y, z + other.z); | 208 | return {x + other.x, y + other.y, z + other.z}; |
| 217 | } | 209 | } |
| 218 | void operator+=(const Vec3& other) { | 210 | |
| 211 | constexpr Vec3& operator+=(const Vec3& other) { | ||
| 219 | x += other.x; | 212 | x += other.x; |
| 220 | y += other.y; | 213 | y += other.y; |
| 221 | z += other.z; | 214 | z += other.z; |
| 215 | return *this; | ||
| 222 | } | 216 | } |
| 223 | Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const { | 217 | |
| 224 | return MakeVec(x - other.x, y - other.y, z - other.z); | 218 | constexpr Vec3<decltype(T{} - T{})> operator-(const Vec3& other) const { |
| 219 | return {x - other.x, y - other.y, z - other.z}; | ||
| 225 | } | 220 | } |
| 226 | void operator-=(const Vec3& other) { | 221 | |
| 222 | constexpr Vec3& operator-=(const Vec3& other) { | ||
| 227 | x -= other.x; | 223 | x -= other.x; |
| 228 | y -= other.y; | 224 | y -= other.y; |
| 229 | z -= other.z; | 225 | z -= other.z; |
| 226 | return *this; | ||
| 230 | } | 227 | } |
| 231 | 228 | ||
| 232 | template <typename U = T> | 229 | template <typename U = T> |
| 233 | Vec3<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const { | 230 | constexpr Vec3<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const { |
| 234 | return MakeVec(-x, -y, -z); | 231 | return {-x, -y, -z}; |
| 235 | } | 232 | } |
| 236 | Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const { | 233 | |
| 237 | return MakeVec(x * other.x, y * other.y, z * other.z); | 234 | constexpr Vec3<decltype(T{} * T{})> operator*(const Vec3& other) const { |
| 235 | return {x * other.x, y * other.y, z * other.z}; | ||
| 238 | } | 236 | } |
| 237 | |||
| 239 | template <typename V> | 238 | template <typename V> |
| 240 | Vec3<decltype(T{} * V{})> operator*(const V& f) const { | 239 | constexpr Vec3<decltype(T{} * V{})> operator*(const V& f) const { |
| 241 | return MakeVec(x * f, y * f, z * f); | 240 | return {x * f, y * f, z * f}; |
| 242 | } | 241 | } |
| 242 | |||
| 243 | template <typename V> | 243 | template <typename V> |
| 244 | void operator*=(const V& f) { | 244 | constexpr Vec3& operator*=(const V& f) { |
| 245 | *this = *this * f; | 245 | *this = *this * f; |
| 246 | return *this; | ||
| 246 | } | 247 | } |
| 247 | template <typename V> | 248 | template <typename V> |
| 248 | Vec3<decltype(T{} / V{})> operator/(const V& f) const { | 249 | constexpr Vec3<decltype(T{} / V{})> operator/(const V& f) const { |
| 249 | return MakeVec(x / f, y / f, z / f); | 250 | return {x / f, y / f, z / f}; |
| 250 | } | 251 | } |
| 252 | |||
| 251 | template <typename V> | 253 | template <typename V> |
| 252 | void operator/=(const V& f) { | 254 | constexpr Vec3& operator/=(const V& f) { |
| 253 | *this = *this / f; | 255 | *this = *this / f; |
| 256 | return *this; | ||
| 254 | } | 257 | } |
| 255 | 258 | ||
| 256 | T Length2() const { | 259 | constexpr T Length2() const { |
| 257 | return x * x + y * y + z * z; | 260 | return x * x + y * y + z * z; |
| 258 | } | 261 | } |
| 259 | 262 | ||
| 260 | // Only implemented for T=float | 263 | // Only implemented for T=float |
| 261 | float Length() const; | 264 | float Length() const; |
| 262 | void SetLength(const float l); | ||
| 263 | Vec3 WithLength(const float l) const; | ||
| 264 | float Distance2To(Vec3& other); | ||
| 265 | Vec3 Normalized() const; | 265 | Vec3 Normalized() const; |
| 266 | float Normalize(); // returns the previous length, which is often useful | 266 | float Normalize(); // returns the previous length, which is often useful |
| 267 | 267 | ||
| 268 | T& operator[](int i) // allow vector[2] = 3 (vector.z=3) | 268 | constexpr T& operator[](std::size_t i) { |
| 269 | { | ||
| 270 | return *((&x) + i); | 269 | return *((&x) + i); |
| 271 | } | 270 | } |
| 272 | T operator[](const int i) const { | 271 | |
| 272 | constexpr const T& operator[](std::size_t i) const { | ||
| 273 | return *((&x) + i); | 273 | return *((&x) + i); |
| 274 | } | 274 | } |
| 275 | 275 | ||
| 276 | void SetZero() { | 276 | constexpr void SetZero() { |
| 277 | x = 0; | 277 | x = 0; |
| 278 | y = 0; | 278 | y = 0; |
| 279 | z = 0; | 279 | z = 0; |
| 280 | } | 280 | } |
| 281 | 281 | ||
| 282 | // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates) | 282 | // Common aliases: UVW (texel coordinates), RGB (colors), STQ (texture coordinates) |
| 283 | T& u() { | 283 | constexpr T& u() { |
| 284 | return x; | 284 | return x; |
| 285 | } | 285 | } |
| 286 | T& v() { | 286 | constexpr T& v() { |
| 287 | return y; | 287 | return y; |
| 288 | } | 288 | } |
| 289 | T& w() { | 289 | constexpr T& w() { |
| 290 | return z; | 290 | return z; |
| 291 | } | 291 | } |
| 292 | 292 | ||
| 293 | T& r() { | 293 | constexpr T& r() { |
| 294 | return x; | 294 | return x; |
| 295 | } | 295 | } |
| 296 | T& g() { | 296 | constexpr T& g() { |
| 297 | return y; | 297 | return y; |
| 298 | } | 298 | } |
| 299 | T& b() { | 299 | constexpr T& b() { |
| 300 | return z; | 300 | return z; |
| 301 | } | 301 | } |
| 302 | 302 | ||
| 303 | T& s() { | 303 | constexpr T& s() { |
| 304 | return x; | 304 | return x; |
| 305 | } | 305 | } |
| 306 | T& t() { | 306 | constexpr T& t() { |
| 307 | return y; | 307 | return y; |
| 308 | } | 308 | } |
| 309 | T& q() { | 309 | constexpr T& q() { |
| 310 | return z; | 310 | return z; |
| 311 | } | 311 | } |
| 312 | 312 | ||
| 313 | const T& u() const { | 313 | constexpr const T& u() const { |
| 314 | return x; | 314 | return x; |
| 315 | } | 315 | } |
| 316 | const T& v() const { | 316 | constexpr const T& v() const { |
| 317 | return y; | 317 | return y; |
| 318 | } | 318 | } |
| 319 | const T& w() const { | 319 | constexpr const T& w() const { |
| 320 | return z; | 320 | return z; |
| 321 | } | 321 | } |
| 322 | 322 | ||
| 323 | const T& r() const { | 323 | constexpr const T& r() const { |
| 324 | return x; | 324 | return x; |
| 325 | } | 325 | } |
| 326 | const T& g() const { | 326 | constexpr const T& g() const { |
| 327 | return y; | 327 | return y; |
| 328 | } | 328 | } |
| 329 | const T& b() const { | 329 | constexpr const T& b() const { |
| 330 | return z; | 330 | return z; |
| 331 | } | 331 | } |
| 332 | 332 | ||
| 333 | const T& s() const { | 333 | constexpr const T& s() const { |
| 334 | return x; | 334 | return x; |
| 335 | } | 335 | } |
| 336 | const T& t() const { | 336 | constexpr const T& t() const { |
| 337 | return y; | 337 | return y; |
| 338 | } | 338 | } |
| 339 | const T& q() const { | 339 | constexpr const T& q() const { |
| 340 | return z; | 340 | return z; |
| 341 | } | 341 | } |
| 342 | 342 | ||
| @@ -345,7 +345,7 @@ public: | |||
| 345 | // _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all | 345 | // _DEFINE_SWIZZLER2 defines a single such function, DEFINE_SWIZZLER2 defines all of them for all |
| 346 | // component names (x<->r) and permutations (xy<->yx) | 346 | // component names (x<->r) and permutations (xy<->yx) |
| 347 | #define _DEFINE_SWIZZLER2(a, b, name) \ | 347 | #define _DEFINE_SWIZZLER2(a, b, name) \ |
| 348 | const Vec2<T> name() const { \ | 348 | constexpr Vec2<T> name() const { \ |
| 349 | return Vec2<T>(a, b); \ | 349 | return Vec2<T>(a, b); \ |
| 350 | } | 350 | } |
| 351 | #define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \ | 351 | #define DEFINE_SWIZZLER2(a, b, a2, b2, a3, b3, a4, b4) \ |
| @@ -366,7 +366,7 @@ public: | |||
| 366 | }; | 366 | }; |
| 367 | 367 | ||
| 368 | template <typename T, typename V> | 368 | template <typename T, typename V> |
| 369 | Vec3<T> operator*(const V& f, const Vec3<T>& vec) { | 369 | constexpr Vec3<T> operator*(const V& f, const Vec3<T>& vec) { |
| 370 | return Vec3<T>(f * vec.x, f * vec.y, f * vec.z); | 370 | return Vec3<T>(f * vec.x, f * vec.y, f * vec.z); |
| 371 | } | 371 | } |
| 372 | 372 | ||
| @@ -387,7 +387,7 @@ inline float Vec3<float>::Normalize() { | |||
| 387 | return length; | 387 | return length; |
| 388 | } | 388 | } |
| 389 | 389 | ||
| 390 | typedef Vec3<float> Vec3f; | 390 | using Vec3f = Vec3<float>; |
| 391 | 391 | ||
| 392 | template <typename T> | 392 | template <typename T> |
| 393 | class Vec4 { | 393 | class Vec4 { |
| @@ -397,86 +397,88 @@ public: | |||
| 397 | T z{}; | 397 | T z{}; |
| 398 | T w{}; | 398 | T w{}; |
| 399 | 399 | ||
| 400 | Vec4() = default; | 400 | constexpr Vec4() = default; |
| 401 | Vec4(const T& _x, const T& _y, const T& _z, const T& _w) : x(_x), y(_y), z(_z), w(_w) {} | 401 | constexpr Vec4(const T& x_, const T& y_, const T& z_, const T& w_) |
| 402 | : x(x_), y(y_), z(z_), w(w_) {} | ||
| 402 | 403 | ||
| 403 | template <typename T2> | 404 | template <typename T2> |
| 404 | Vec4<T2> Cast() const { | 405 | constexpr Vec4<T2> Cast() const { |
| 405 | return Vec4<T2>((T2)x, (T2)y, (T2)z, (T2)w); | 406 | return Vec4<T2>(static_cast<T2>(x), static_cast<T2>(y), static_cast<T2>(z), |
| 407 | static_cast<T2>(w)); | ||
| 406 | } | 408 | } |
| 407 | 409 | ||
| 408 | // Only implemented for T=int and T=float | 410 | static constexpr Vec4 AssignToAll(const T& f) { |
| 409 | static Vec4 FromRGBA(unsigned int rgba); | 411 | return Vec4(f, f, f, f); |
| 410 | unsigned int ToRGBA() const; | ||
| 411 | |||
| 412 | static Vec4 AssignToAll(const T& f) { | ||
| 413 | return Vec4<T>(f, f, f, f); | ||
| 414 | } | 412 | } |
| 415 | 413 | ||
| 416 | Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const { | 414 | constexpr Vec4<decltype(T{} + T{})> operator+(const Vec4& other) const { |
| 417 | return MakeVec(x + other.x, y + other.y, z + other.z, w + other.w); | 415 | return {x + other.x, y + other.y, z + other.z, w + other.w}; |
| 418 | } | 416 | } |
| 419 | void operator+=(const Vec4& other) { | 417 | |
| 418 | constexpr Vec4& operator+=(const Vec4& other) { | ||
| 420 | x += other.x; | 419 | x += other.x; |
| 421 | y += other.y; | 420 | y += other.y; |
| 422 | z += other.z; | 421 | z += other.z; |
| 423 | w += other.w; | 422 | w += other.w; |
| 423 | return *this; | ||
| 424 | } | 424 | } |
| 425 | Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const { | 425 | |
| 426 | return MakeVec(x - other.x, y - other.y, z - other.z, w - other.w); | 426 | constexpr Vec4<decltype(T{} - T{})> operator-(const Vec4& other) const { |
| 427 | return {x - other.x, y - other.y, z - other.z, w - other.w}; | ||
| 427 | } | 428 | } |
| 428 | void operator-=(const Vec4& other) { | 429 | |
| 430 | constexpr Vec4& operator-=(const Vec4& other) { | ||
| 429 | x -= other.x; | 431 | x -= other.x; |
| 430 | y -= other.y; | 432 | y -= other.y; |
| 431 | z -= other.z; | 433 | z -= other.z; |
| 432 | w -= other.w; | 434 | w -= other.w; |
| 435 | return *this; | ||
| 433 | } | 436 | } |
| 434 | 437 | ||
| 435 | template <typename U = T> | 438 | template <typename U = T> |
| 436 | Vec4<std::enable_if_t<std::is_signed<U>::value, U>> operator-() const { | 439 | constexpr Vec4<std::enable_if_t<std::is_signed_v<U>, U>> operator-() const { |
| 437 | return MakeVec(-x, -y, -z, -w); | 440 | return {-x, -y, -z, -w}; |
| 438 | } | 441 | } |
| 439 | Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const { | 442 | |
| 440 | return MakeVec(x * other.x, y * other.y, z * other.z, w * other.w); | 443 | constexpr Vec4<decltype(T{} * T{})> operator*(const Vec4& other) const { |
| 444 | return {x * other.x, y * other.y, z * other.z, w * other.w}; | ||
| 441 | } | 445 | } |
| 446 | |||
| 442 | template <typename V> | 447 | template <typename V> |
| 443 | Vec4<decltype(T{} * V{})> operator*(const V& f) const { | 448 | constexpr Vec4<decltype(T{} * V{})> operator*(const V& f) const { |
| 444 | return MakeVec(x * f, y * f, z * f, w * f); | 449 | return {x * f, y * f, z * f, w * f}; |
| 445 | } | 450 | } |
| 451 | |||
| 446 | template <typename V> | 452 | template <typename V> |
| 447 | void operator*=(const V& f) { | 453 | constexpr Vec4& operator*=(const V& f) { |
| 448 | *this = *this * f; | 454 | *this = *this * f; |
| 455 | return *this; | ||
| 449 | } | 456 | } |
| 457 | |||
| 450 | template <typename V> | 458 | template <typename V> |
| 451 | Vec4<decltype(T{} / V{})> operator/(const V& f) const { | 459 | constexpr Vec4<decltype(T{} / V{})> operator/(const V& f) const { |
| 452 | return MakeVec(x / f, y / f, z / f, w / f); | 460 | return {x / f, y / f, z / f, w / f}; |
| 453 | } | 461 | } |
| 462 | |||
| 454 | template <typename V> | 463 | template <typename V> |
| 455 | void operator/=(const V& f) { | 464 | constexpr Vec4& operator/=(const V& f) { |
| 456 | *this = *this / f; | 465 | *this = *this / f; |
| 466 | return *this; | ||
| 457 | } | 467 | } |
| 458 | 468 | ||
| 459 | T Length2() const { | 469 | constexpr T Length2() const { |
| 460 | return x * x + y * y + z * z + w * w; | 470 | return x * x + y * y + z * z + w * w; |
| 461 | } | 471 | } |
| 462 | 472 | ||
| 463 | // Only implemented for T=float | 473 | constexpr T& operator[](std::size_t i) { |
| 464 | float Length() const; | ||
| 465 | void SetLength(const float l); | ||
| 466 | Vec4 WithLength(const float l) const; | ||
| 467 | float Distance2To(Vec4& other); | ||
| 468 | Vec4 Normalized() const; | ||
| 469 | float Normalize(); // returns the previous length, which is often useful | ||
| 470 | |||
| 471 | T& operator[](int i) // allow vector[2] = 3 (vector.z=3) | ||
| 472 | { | ||
| 473 | return *((&x) + i); | 474 | return *((&x) + i); |
| 474 | } | 475 | } |
| 475 | T operator[](const int i) const { | 476 | |
| 477 | constexpr const T& operator[](std::size_t i) const { | ||
| 476 | return *((&x) + i); | 478 | return *((&x) + i); |
| 477 | } | 479 | } |
| 478 | 480 | ||
| 479 | void SetZero() { | 481 | constexpr void SetZero() { |
| 480 | x = 0; | 482 | x = 0; |
| 481 | y = 0; | 483 | y = 0; |
| 482 | z = 0; | 484 | z = 0; |
| @@ -484,29 +486,29 @@ public: | |||
| 484 | } | 486 | } |
| 485 | 487 | ||
| 486 | // Common alias: RGBA (colors) | 488 | // Common alias: RGBA (colors) |
| 487 | T& r() { | 489 | constexpr T& r() { |
| 488 | return x; | 490 | return x; |
| 489 | } | 491 | } |
| 490 | T& g() { | 492 | constexpr T& g() { |
| 491 | return y; | 493 | return y; |
| 492 | } | 494 | } |
| 493 | T& b() { | 495 | constexpr T& b() { |
| 494 | return z; | 496 | return z; |
| 495 | } | 497 | } |
| 496 | T& a() { | 498 | constexpr T& a() { |
| 497 | return w; | 499 | return w; |
| 498 | } | 500 | } |
| 499 | 501 | ||
| 500 | const T& r() const { | 502 | constexpr const T& r() const { |
| 501 | return x; | 503 | return x; |
| 502 | } | 504 | } |
| 503 | const T& g() const { | 505 | constexpr const T& g() const { |
| 504 | return y; | 506 | return y; |
| 505 | } | 507 | } |
| 506 | const T& b() const { | 508 | constexpr const T& b() const { |
| 507 | return z; | 509 | return z; |
| 508 | } | 510 | } |
| 509 | const T& a() const { | 511 | constexpr const T& a() const { |
| 510 | return w; | 512 | return w; |
| 511 | } | 513 | } |
| 512 | 514 | ||
| @@ -518,7 +520,7 @@ public: | |||
| 518 | // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and | 520 | // DEFINE_SWIZZLER2_COMP2 defines two component functions for all component names (x<->r) and |
| 519 | // permutations (xy<->yx) | 521 | // permutations (xy<->yx) |
| 520 | #define _DEFINE_SWIZZLER2(a, b, name) \ | 522 | #define _DEFINE_SWIZZLER2(a, b, name) \ |
| 521 | const Vec2<T> name() const { \ | 523 | constexpr Vec2<T> name() const { \ |
| 522 | return Vec2<T>(a, b); \ | 524 | return Vec2<T>(a, b); \ |
| 523 | } | 525 | } |
| 524 | #define DEFINE_SWIZZLER2_COMP1(a, a2) \ | 526 | #define DEFINE_SWIZZLER2_COMP1(a, a2) \ |
| @@ -545,7 +547,7 @@ public: | |||
| 545 | #undef _DEFINE_SWIZZLER2 | 547 | #undef _DEFINE_SWIZZLER2 |
| 546 | 548 | ||
| 547 | #define _DEFINE_SWIZZLER3(a, b, c, name) \ | 549 | #define _DEFINE_SWIZZLER3(a, b, c, name) \ |
| 548 | const Vec3<T> name() const { \ | 550 | constexpr Vec3<T> name() const { \ |
| 549 | return Vec3<T>(a, b, c); \ | 551 | return Vec3<T>(a, b, c); \ |
| 550 | } | 552 | } |
| 551 | #define DEFINE_SWIZZLER3_COMP1(a, a2) \ | 553 | #define DEFINE_SWIZZLER3_COMP1(a, a2) \ |
| @@ -579,51 +581,51 @@ public: | |||
| 579 | }; | 581 | }; |
| 580 | 582 | ||
| 581 | template <typename T, typename V> | 583 | template <typename T, typename V> |
| 582 | Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) { | 584 | constexpr Vec4<decltype(V{} * T{})> operator*(const V& f, const Vec4<T>& vec) { |
| 583 | return MakeVec(f * vec.x, f * vec.y, f * vec.z, f * vec.w); | 585 | return {f * vec.x, f * vec.y, f * vec.z, f * vec.w}; |
| 584 | } | 586 | } |
| 585 | 587 | ||
| 586 | typedef Vec4<float> Vec4f; | 588 | using Vec4f = Vec4<float>; |
| 587 | 589 | ||
| 588 | template <typename T> | 590 | template <typename T> |
| 589 | static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) { | 591 | constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec2<T>& a, const Vec2<T>& b) { |
| 590 | return a.x * b.x + a.y * b.y; | 592 | return a.x * b.x + a.y * b.y; |
| 591 | } | 593 | } |
| 592 | 594 | ||
| 593 | template <typename T> | 595 | template <typename T> |
| 594 | static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) { | 596 | constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec3<T>& a, const Vec3<T>& b) { |
| 595 | return a.x * b.x + a.y * b.y + a.z * b.z; | 597 | return a.x * b.x + a.y * b.y + a.z * b.z; |
| 596 | } | 598 | } |
| 597 | 599 | ||
| 598 | template <typename T> | 600 | template <typename T> |
| 599 | static inline decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) { | 601 | constexpr decltype(T{} * T{} + T{} * T{}) Dot(const Vec4<T>& a, const Vec4<T>& b) { |
| 600 | return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; | 602 | return a.x * b.x + a.y * b.y + a.z * b.z + a.w * b.w; |
| 601 | } | 603 | } |
| 602 | 604 | ||
| 603 | template <typename T> | 605 | template <typename T> |
| 604 | static inline Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) { | 606 | constexpr Vec3<decltype(T{} * T{} - T{} * T{})> Cross(const Vec3<T>& a, const Vec3<T>& b) { |
| 605 | return MakeVec(a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x); | 607 | return {a.y * b.z - a.z * b.y, a.z * b.x - a.x * b.z, a.x * b.y - a.y * b.x}; |
| 606 | } | 608 | } |
| 607 | 609 | ||
| 608 | // linear interpolation via float: 0.0=begin, 1.0=end | 610 | // linear interpolation via float: 0.0=begin, 1.0=end |
| 609 | template <typename X> | 611 | template <typename X> |
| 610 | static inline decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end, | 612 | constexpr decltype(X{} * float{} + X{} * float{}) Lerp(const X& begin, const X& end, |
| 611 | const float t) { | 613 | const float t) { |
| 612 | return begin * (1.f - t) + end * t; | 614 | return begin * (1.f - t) + end * t; |
| 613 | } | 615 | } |
| 614 | 616 | ||
| 615 | // linear interpolation via int: 0=begin, base=end | 617 | // linear interpolation via int: 0=begin, base=end |
| 616 | template <typename X, int base> | 618 | template <typename X, int base> |
| 617 | static inline decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end, | 619 | constexpr decltype((X{} * int{} + X{} * int{}) / base) LerpInt(const X& begin, const X& end, |
| 618 | const int t) { | 620 | const int t) { |
| 619 | return (begin * (base - t) + end * t) / base; | 621 | return (begin * (base - t) + end * t) / base; |
| 620 | } | 622 | } |
| 621 | 623 | ||
| 622 | // bilinear interpolation. s is for interpolating x00-x01 and x10-x11, and t is for the second | 624 | // bilinear interpolation. s is for interpolating x00-x01 and x10-x11, and t is for the second |
| 623 | // interpolation. | 625 | // interpolation. |
| 624 | template <typename X> | 626 | template <typename X> |
| 625 | inline auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, const float s, | 627 | constexpr auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x11, const float s, |
| 626 | const float t) { | 628 | const float t) { |
| 627 | auto y0 = Lerp(x00, x01, s); | 629 | auto y0 = Lerp(x00, x01, s); |
| 628 | auto y1 = Lerp(x10, x11, s); | 630 | auto y1 = Lerp(x10, x11, s); |
| 629 | return Lerp(y0, y1, t); | 631 | return Lerp(y0, y1, t); |
| @@ -631,42 +633,42 @@ inline auto BilinearInterp(const X& x00, const X& x01, const X& x10, const X& x1 | |||
| 631 | 633 | ||
| 632 | // Utility vector factories | 634 | // Utility vector factories |
| 633 | template <typename T> | 635 | template <typename T> |
| 634 | static inline Vec2<T> MakeVec(const T& x, const T& y) { | 636 | constexpr Vec2<T> MakeVec(const T& x, const T& y) { |
| 635 | return Vec2<T>{x, y}; | 637 | return Vec2<T>{x, y}; |
| 636 | } | 638 | } |
| 637 | 639 | ||
| 638 | template <typename T> | 640 | template <typename T> |
| 639 | static inline Vec3<T> MakeVec(const T& x, const T& y, const T& z) { | 641 | constexpr Vec3<T> MakeVec(const T& x, const T& y, const T& z) { |
| 640 | return Vec3<T>{x, y, z}; | 642 | return Vec3<T>{x, y, z}; |
| 641 | } | 643 | } |
| 642 | 644 | ||
| 643 | template <typename T> | 645 | template <typename T> |
| 644 | static inline Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) { | 646 | constexpr Vec4<T> MakeVec(const T& x, const T& y, const Vec2<T>& zw) { |
| 645 | return MakeVec(x, y, zw[0], zw[1]); | 647 | return MakeVec(x, y, zw[0], zw[1]); |
| 646 | } | 648 | } |
| 647 | 649 | ||
| 648 | template <typename T> | 650 | template <typename T> |
| 649 | static inline Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) { | 651 | constexpr Vec3<T> MakeVec(const Vec2<T>& xy, const T& z) { |
| 650 | return MakeVec(xy[0], xy[1], z); | 652 | return MakeVec(xy[0], xy[1], z); |
| 651 | } | 653 | } |
| 652 | 654 | ||
| 653 | template <typename T> | 655 | template <typename T> |
| 654 | static inline Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) { | 656 | constexpr Vec3<T> MakeVec(const T& x, const Vec2<T>& yz) { |
| 655 | return MakeVec(x, yz[0], yz[1]); | 657 | return MakeVec(x, yz[0], yz[1]); |
| 656 | } | 658 | } |
| 657 | 659 | ||
| 658 | template <typename T> | 660 | template <typename T> |
| 659 | static inline Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) { | 661 | constexpr Vec4<T> MakeVec(const T& x, const T& y, const T& z, const T& w) { |
| 660 | return Vec4<T>{x, y, z, w}; | 662 | return Vec4<T>{x, y, z, w}; |
| 661 | } | 663 | } |
| 662 | 664 | ||
| 663 | template <typename T> | 665 | template <typename T> |
| 664 | static inline Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) { | 666 | constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const T& z, const T& w) { |
| 665 | return MakeVec(xy[0], xy[1], z, w); | 667 | return MakeVec(xy[0], xy[1], z, w); |
| 666 | } | 668 | } |
| 667 | 669 | ||
| 668 | template <typename T> | 670 | template <typename T> |
| 669 | static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) { | 671 | constexpr Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) { |
| 670 | return MakeVec(x, yz[0], yz[1], w); | 672 | return MakeVec(x, yz[0], yz[1], w); |
| 671 | } | 673 | } |
| 672 | 674 | ||
| @@ -674,17 +676,17 @@ static inline Vec4<T> MakeVec(const T& x, const Vec2<T>& yz, const T& w) { | |||
| 674 | // Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error | 676 | // Even if someone wanted to use an odd object like Vec2<Vec2<T>>, the compiler would error |
| 675 | // out soon enough due to misuse of the returned structure. | 677 | // out soon enough due to misuse of the returned structure. |
| 676 | template <typename T> | 678 | template <typename T> |
| 677 | static inline Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) { | 679 | constexpr Vec4<T> MakeVec(const Vec2<T>& xy, const Vec2<T>& zw) { |
| 678 | return MakeVec(xy[0], xy[1], zw[0], zw[1]); | 680 | return MakeVec(xy[0], xy[1], zw[0], zw[1]); |
| 679 | } | 681 | } |
| 680 | 682 | ||
| 681 | template <typename T> | 683 | template <typename T> |
| 682 | static inline Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) { | 684 | constexpr Vec4<T> MakeVec(const Vec3<T>& xyz, const T& w) { |
| 683 | return MakeVec(xyz[0], xyz[1], xyz[2], w); | 685 | return MakeVec(xyz[0], xyz[1], xyz[2], w); |
| 684 | } | 686 | } |
| 685 | 687 | ||
| 686 | template <typename T> | 688 | template <typename T> |
| 687 | static inline Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) { | 689 | constexpr Vec4<T> MakeVec(const T& x, const Vec3<T>& yzw) { |
| 688 | return MakeVec(x, yzw[0], yzw[1], yzw[2]); | 690 | return MakeVec(x, yzw[0], yzw[1], yzw[2]); |
| 689 | } | 691 | } |
| 690 | 692 | ||
diff --git a/src/common/x64/xbyak_util.h b/src/common/x64/xbyak_util.h index 0f52f704b..ec76e0a47 100644 --- a/src/common/x64/xbyak_util.h +++ b/src/common/x64/xbyak_util.h | |||
| @@ -34,7 +34,7 @@ inline bool IsWithin2G(const Xbyak::CodeGenerator& code, uintptr_t target) { | |||
| 34 | 34 | ||
| 35 | template <typename T> | 35 | template <typename T> |
| 36 | inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) { | 36 | inline void CallFarFunction(Xbyak::CodeGenerator& code, const T f) { |
| 37 | static_assert(std::is_pointer<T>(), "Argument must be a (function) pointer."); | 37 | static_assert(std::is_pointer_v<T>, "Argument must be a (function) pointer."); |
| 38 | size_t addr = reinterpret_cast<size_t>(f); | 38 | size_t addr = reinterpret_cast<size_t>(f); |
| 39 | if (IsWithin2G(code, addr)) { | 39 | if (IsWithin2G(code, addr)) { |
| 40 | code.call(f); | 40 | code.call(f); |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 085ba68d0..69c45c026 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -89,7 +89,7 @@ System::ResultStatus System::SingleStep() { | |||
| 89 | } | 89 | } |
| 90 | 90 | ||
| 91 | System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) { | 91 | System::ResultStatus System::Load(EmuWindow& emu_window, const std::string& filepath) { |
| 92 | app_loader = Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(filepath)); | 92 | app_loader = Loader::GetLoader(virtual_filesystem->OpenFile(filepath, FileSys::Mode::Read)); |
| 93 | 93 | ||
| 94 | if (!app_loader) { | 94 | if (!app_loader) { |
| 95 | LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); | 95 | LOG_CRITICAL(Core, "Failed to obtain loader for {}!", filepath); |
| @@ -174,6 +174,10 @@ System::ResultStatus System::Init(EmuWindow& emu_window) { | |||
| 174 | 174 | ||
| 175 | CoreTiming::Init(); | 175 | CoreTiming::Init(); |
| 176 | 176 | ||
| 177 | // Create a default fs if one doesn't already exist. | ||
| 178 | if (virtual_filesystem == nullptr) | ||
| 179 | virtual_filesystem = std::make_shared<FileSys::RealVfsFilesystem>(); | ||
| 180 | |||
| 177 | current_process = Kernel::Process::Create("main"); | 181 | current_process = Kernel::Process::Create("main"); |
| 178 | 182 | ||
| 179 | cpu_barrier = std::make_shared<CpuBarrier>(); | 183 | cpu_barrier = std::make_shared<CpuBarrier>(); |
| @@ -186,7 +190,7 @@ System::ResultStatus System::Init(EmuWindow& emu_window) { | |||
| 186 | service_manager = std::make_shared<Service::SM::ServiceManager>(); | 190 | service_manager = std::make_shared<Service::SM::ServiceManager>(); |
| 187 | 191 | ||
| 188 | Kernel::Init(); | 192 | Kernel::Init(); |
| 189 | Service::Init(service_manager); | 193 | Service::Init(service_manager, virtual_filesystem); |
| 190 | GDBStub::Init(); | 194 | GDBStub::Init(); |
| 191 | 195 | ||
| 192 | renderer = VideoCore::CreateRenderer(emu_window); | 196 | renderer = VideoCore::CreateRenderer(emu_window); |
diff --git a/src/core/core.h b/src/core/core.h index c8ca4b247..7cf7ea4e1 100644 --- a/src/core/core.h +++ b/src/core/core.h | |||
| @@ -17,6 +17,8 @@ | |||
| 17 | #include "core/memory.h" | 17 | #include "core/memory.h" |
| 18 | #include "core/perf_stats.h" | 18 | #include "core/perf_stats.h" |
| 19 | #include "core/telemetry_session.h" | 19 | #include "core/telemetry_session.h" |
| 20 | #include "file_sys/vfs_real.h" | ||
| 21 | #include "hle/service/filesystem/filesystem.h" | ||
| 20 | #include "video_core/debug_utils/debug_utils.h" | 22 | #include "video_core/debug_utils/debug_utils.h" |
| 21 | #include "video_core/gpu.h" | 23 | #include "video_core/gpu.h" |
| 22 | 24 | ||
| @@ -211,6 +213,14 @@ public: | |||
| 211 | return debug_context; | 213 | return debug_context; |
| 212 | } | 214 | } |
| 213 | 215 | ||
| 216 | void SetFilesystem(FileSys::VirtualFilesystem vfs) { | ||
| 217 | virtual_filesystem = std::move(vfs); | ||
| 218 | } | ||
| 219 | |||
| 220 | FileSys::VirtualFilesystem GetFilesystem() const { | ||
| 221 | return virtual_filesystem; | ||
| 222 | } | ||
| 223 | |||
| 214 | private: | 224 | private: |
| 215 | System(); | 225 | System(); |
| 216 | 226 | ||
| @@ -225,6 +235,8 @@ private: | |||
| 225 | */ | 235 | */ |
| 226 | ResultStatus Init(EmuWindow& emu_window); | 236 | ResultStatus Init(EmuWindow& emu_window); |
| 227 | 237 | ||
| 238 | /// RealVfsFilesystem instance | ||
| 239 | FileSys::VirtualFilesystem virtual_filesystem; | ||
| 228 | /// AppLoader used to load the current executing application | 240 | /// AppLoader used to load the current executing application |
| 229 | std::unique_ptr<Loader::AppLoader> app_loader; | 241 | std::unique_ptr<Loader::AppLoader> app_loader; |
| 230 | std::unique_ptr<VideoCore::RendererBase> renderer; | 242 | std::unique_ptr<VideoCore::RendererBase> renderer; |
diff --git a/src/core/file_sys/card_image.cpp b/src/core/file_sys/card_image.cpp index 395eea8ae..e897d9913 100644 --- a/src/core/file_sys/card_image.cpp +++ b/src/core/file_sys/card_image.cpp | |||
| @@ -5,6 +5,7 @@ | |||
| 5 | #include <array> | 5 | #include <array> |
| 6 | #include <string> | 6 | #include <string> |
| 7 | #include <core/loader/loader.h> | 7 | #include <core/loader/loader.h> |
| 8 | #include "common/logging/log.h" | ||
| 8 | #include "core/file_sys/card_image.h" | 9 | #include "core/file_sys/card_image.h" |
| 9 | #include "core/file_sys/partition_filesystem.h" | 10 | #include "core/file_sys/partition_filesystem.h" |
| 10 | #include "core/file_sys/vfs_offset.h" | 11 | #include "core/file_sys/vfs_offset.h" |
diff --git a/src/core/file_sys/content_archive.cpp b/src/core/file_sys/content_archive.cpp index 3529166ac..d3007d981 100644 --- a/src/core/file_sys/content_archive.cpp +++ b/src/core/file_sys/content_archive.cpp | |||
| @@ -170,6 +170,10 @@ VirtualFile NCA::Decrypt(NCASectionHeader s_header, VirtualFile in, u64 starting | |||
| 170 | } | 170 | } |
| 171 | 171 | ||
| 172 | NCA::NCA(VirtualFile file_) : file(std::move(file_)) { | 172 | NCA::NCA(VirtualFile file_) : file(std::move(file_)) { |
| 173 | if (file == nullptr) { | ||
| 174 | status = Loader::ResultStatus::ErrorInvalidFormat; | ||
| 175 | return; | ||
| 176 | } | ||
| 173 | if (sizeof(NCAHeader) != file->ReadObject(&header)) | 177 | if (sizeof(NCAHeader) != file->ReadObject(&header)) |
| 174 | LOG_ERROR(Loader, "File reader errored out during header read."); | 178 | LOG_ERROR(Loader, "File reader errored out during header read."); |
| 175 | 179 | ||
diff --git a/src/core/file_sys/content_archive.h b/src/core/file_sys/content_archive.h index a8879d9a8..5cfd5031a 100644 --- a/src/core/file_sys/content_archive.h +++ b/src/core/file_sys/content_archive.h | |||
| @@ -12,6 +12,7 @@ | |||
| 12 | #include "common/common_funcs.h" | 12 | #include "common/common_funcs.h" |
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "common/swap.h" | 14 | #include "common/swap.h" |
| 15 | #include "control_metadata.h" | ||
| 15 | #include "core/crypto/key_manager.h" | 16 | #include "core/crypto/key_manager.h" |
| 16 | #include "core/file_sys/partition_filesystem.h" | 17 | #include "core/file_sys/partition_filesystem.h" |
| 17 | #include "core/loader/loader.h" | 18 | #include "core/loader/loader.h" |
diff --git a/src/core/file_sys/control_metadata.h b/src/core/file_sys/control_metadata.h index cc3b745f7..6582cc240 100644 --- a/src/core/file_sys/control_metadata.h +++ b/src/core/file_sys/control_metadata.h | |||
| @@ -62,6 +62,13 @@ enum class Language : u8 { | |||
| 62 | Chinese = 14, | 62 | Chinese = 14, |
| 63 | }; | 63 | }; |
| 64 | 64 | ||
| 65 | static constexpr std::array<const char*, 15> LANGUAGE_NAMES = { | ||
| 66 | "AmericanEnglish", "BritishEnglish", "Japanese", | ||
| 67 | "French", "German", "LatinAmericanSpanish", | ||
| 68 | "Spanish", "Italian", "Dutch", | ||
| 69 | "CanadianFrench", "Portugese", "Russian", | ||
| 70 | "Korean", "Taiwanese", "Chinese"}; | ||
| 71 | |||
| 65 | // A class representing the format used by NX metadata files, typically named Control.nacp. | 72 | // A class representing the format used by NX metadata files, typically named Control.nacp. |
| 66 | // These store application name, dev name, title id, and other miscellaneous data. | 73 | // These store application name, dev name, title id, and other miscellaneous data. |
| 67 | class NACP { | 74 | class NACP { |
diff --git a/src/core/file_sys/directory.h b/src/core/file_sys/directory.h index 213ce1826..3759e743a 100644 --- a/src/core/file_sys/directory.h +++ b/src/core/file_sys/directory.h | |||
| @@ -4,8 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | ||
| 8 | #include <cstddef> | 7 | #include <cstddef> |
| 8 | #include <iterator> | ||
| 9 | #include <string_view> | ||
| 9 | #include "common/common_funcs.h" | 10 | #include "common/common_funcs.h" |
| 10 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 11 | 12 | ||
| @@ -21,9 +22,14 @@ enum EntryType : u8 { | |||
| 21 | 22 | ||
| 22 | // Structure of a directory entry, from | 23 | // Structure of a directory entry, from |
| 23 | // http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry | 24 | // http://switchbrew.org/index.php?title=Filesystem_services#DirectoryEntry |
| 24 | const size_t FILENAME_LENGTH = 0x300; | ||
| 25 | struct Entry { | 25 | struct Entry { |
| 26 | char filename[FILENAME_LENGTH]; | 26 | Entry(std::string_view view, EntryType entry_type, u64 entry_size) |
| 27 | : type{entry_type}, file_size{entry_size} { | ||
| 28 | const size_t copy_size = view.copy(filename, std::size(filename) - 1); | ||
| 29 | filename[copy_size] = '\0'; | ||
| 30 | } | ||
| 31 | |||
| 32 | char filename[0x300]; | ||
| 27 | INSERT_PADDING_BYTES(4); | 33 | INSERT_PADDING_BYTES(4); |
| 28 | EntryType type; | 34 | EntryType type; |
| 29 | INSERT_PADDING_BYTES(3); | 35 | INSERT_PADDING_BYTES(3); |
diff --git a/src/core/file_sys/savedata_factory.h b/src/core/file_sys/savedata_factory.h index e3a578c0f..f3cf50d5a 100644 --- a/src/core/file_sys/savedata_factory.h +++ b/src/core/file_sys/savedata_factory.h | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <string> | 8 | #include <string> |
| 9 | #include "common/common_types.h" | 9 | #include "common/common_types.h" |
| 10 | #include "common/swap.h" | ||
| 10 | #include "core/hle/result.h" | 11 | #include "core/hle/result.h" |
| 11 | 12 | ||
| 12 | namespace FileSys { | 13 | namespace FileSys { |
diff --git a/src/core/file_sys/vfs.cpp b/src/core/file_sys/vfs.cpp index dae1c16ef..24e158962 100644 --- a/src/core/file_sys/vfs.cpp +++ b/src/core/file_sys/vfs.cpp | |||
| @@ -4,12 +4,160 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <numeric> | 6 | #include <numeric> |
| 7 | #include <string> | ||
| 8 | #include "common/common_paths.h" | ||
| 7 | #include "common/file_util.h" | 9 | #include "common/file_util.h" |
| 8 | #include "common/logging/backend.h" | 10 | #include "common/logging/backend.h" |
| 9 | #include "core/file_sys/vfs.h" | 11 | #include "core/file_sys/vfs.h" |
| 10 | 12 | ||
| 11 | namespace FileSys { | 13 | namespace FileSys { |
| 12 | 14 | ||
| 15 | VfsFilesystem::VfsFilesystem(VirtualDir root_) : root(std::move(root_)) {} | ||
| 16 | |||
| 17 | VfsFilesystem::~VfsFilesystem() = default; | ||
| 18 | |||
| 19 | std::string VfsFilesystem::GetName() const { | ||
| 20 | return root->GetName(); | ||
| 21 | } | ||
| 22 | |||
| 23 | bool VfsFilesystem::IsReadable() const { | ||
| 24 | return root->IsReadable(); | ||
| 25 | } | ||
| 26 | |||
| 27 | bool VfsFilesystem::IsWritable() const { | ||
| 28 | return root->IsWritable(); | ||
| 29 | } | ||
| 30 | |||
| 31 | VfsEntryType VfsFilesystem::GetEntryType(std::string_view path_) const { | ||
| 32 | const auto path = FileUtil::SanitizePath(path_); | ||
| 33 | if (root->GetFileRelative(path) != nullptr) | ||
| 34 | return VfsEntryType::File; | ||
| 35 | if (root->GetDirectoryRelative(path) != nullptr) | ||
| 36 | return VfsEntryType::Directory; | ||
| 37 | |||
| 38 | return VfsEntryType::None; | ||
| 39 | } | ||
| 40 | |||
| 41 | VirtualFile VfsFilesystem::OpenFile(std::string_view path_, Mode perms) { | ||
| 42 | const auto path = FileUtil::SanitizePath(path_); | ||
| 43 | return root->GetFileRelative(path); | ||
| 44 | } | ||
| 45 | |||
| 46 | VirtualFile VfsFilesystem::CreateFile(std::string_view path_, Mode perms) { | ||
| 47 | const auto path = FileUtil::SanitizePath(path_); | ||
| 48 | return root->CreateFileRelative(path); | ||
| 49 | } | ||
| 50 | |||
| 51 | VirtualFile VfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) { | ||
| 52 | const auto old_path = FileUtil::SanitizePath(old_path_); | ||
| 53 | const auto new_path = FileUtil::SanitizePath(new_path_); | ||
| 54 | |||
| 55 | // VfsDirectory impls are only required to implement copy across the current directory. | ||
| 56 | if (FileUtil::GetParentPath(old_path) == FileUtil::GetParentPath(new_path)) { | ||
| 57 | if (!root->Copy(FileUtil::GetFilename(old_path), FileUtil::GetFilename(new_path))) | ||
| 58 | return nullptr; | ||
| 59 | return OpenFile(new_path, Mode::ReadWrite); | ||
| 60 | } | ||
| 61 | |||
| 62 | // Do it using RawCopy. Non-default impls are encouraged to optimize this. | ||
| 63 | const auto old_file = OpenFile(old_path, Mode::Read); | ||
| 64 | if (old_file == nullptr) | ||
| 65 | return nullptr; | ||
| 66 | auto new_file = OpenFile(new_path, Mode::Read); | ||
| 67 | if (new_file != nullptr) | ||
| 68 | return nullptr; | ||
| 69 | new_file = CreateFile(new_path, Mode::Write); | ||
| 70 | if (new_file == nullptr) | ||
| 71 | return nullptr; | ||
| 72 | if (!VfsRawCopy(old_file, new_file)) | ||
| 73 | return nullptr; | ||
| 74 | return new_file; | ||
| 75 | } | ||
| 76 | |||
| 77 | VirtualFile VfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { | ||
| 78 | const auto old_path = FileUtil::SanitizePath(old_path_); | ||
| 79 | const auto new_path = FileUtil::SanitizePath(new_path_); | ||
| 80 | |||
| 81 | // Again, non-default impls are highly encouraged to provide a more optimized version of this. | ||
| 82 | auto out = CopyFile(old_path_, new_path_); | ||
| 83 | if (out == nullptr) | ||
| 84 | return nullptr; | ||
| 85 | if (DeleteFile(old_path)) | ||
| 86 | return out; | ||
| 87 | return nullptr; | ||
| 88 | } | ||
| 89 | |||
| 90 | bool VfsFilesystem::DeleteFile(std::string_view path_) { | ||
| 91 | const auto path = FileUtil::SanitizePath(path_); | ||
| 92 | auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write); | ||
| 93 | if (parent == nullptr) | ||
| 94 | return false; | ||
| 95 | return parent->DeleteFile(FileUtil::GetFilename(path)); | ||
| 96 | } | ||
| 97 | |||
| 98 | VirtualDir VfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { | ||
| 99 | const auto path = FileUtil::SanitizePath(path_); | ||
| 100 | return root->GetDirectoryRelative(path); | ||
| 101 | } | ||
| 102 | |||
| 103 | VirtualDir VfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { | ||
| 104 | const auto path = FileUtil::SanitizePath(path_); | ||
| 105 | return root->CreateDirectoryRelative(path); | ||
| 106 | } | ||
| 107 | |||
| 108 | VirtualDir VfsFilesystem::CopyDirectory(std::string_view old_path_, std::string_view new_path_) { | ||
| 109 | const auto old_path = FileUtil::SanitizePath(old_path_); | ||
| 110 | const auto new_path = FileUtil::SanitizePath(new_path_); | ||
| 111 | |||
| 112 | // Non-default impls are highly encouraged to provide a more optimized version of this. | ||
| 113 | auto old_dir = OpenDirectory(old_path, Mode::Read); | ||
| 114 | if (old_dir == nullptr) | ||
| 115 | return nullptr; | ||
| 116 | auto new_dir = OpenDirectory(new_path, Mode::Read); | ||
| 117 | if (new_dir != nullptr) | ||
| 118 | return nullptr; | ||
| 119 | new_dir = CreateDirectory(new_path, Mode::Write); | ||
| 120 | if (new_dir == nullptr) | ||
| 121 | return nullptr; | ||
| 122 | |||
| 123 | for (const auto& file : old_dir->GetFiles()) { | ||
| 124 | const auto x = | ||
| 125 | CopyFile(old_path + DIR_SEP + file->GetName(), new_path + DIR_SEP + file->GetName()); | ||
| 126 | if (x == nullptr) | ||
| 127 | return nullptr; | ||
| 128 | } | ||
| 129 | |||
| 130 | for (const auto& dir : old_dir->GetSubdirectories()) { | ||
| 131 | const auto x = | ||
| 132 | CopyDirectory(old_path + DIR_SEP + dir->GetName(), new_path + DIR_SEP + dir->GetName()); | ||
| 133 | if (x == nullptr) | ||
| 134 | return nullptr; | ||
| 135 | } | ||
| 136 | |||
| 137 | return new_dir; | ||
| 138 | } | ||
| 139 | |||
| 140 | VirtualDir VfsFilesystem::MoveDirectory(std::string_view old_path_, std::string_view new_path_) { | ||
| 141 | const auto old_path = FileUtil::SanitizePath(old_path_); | ||
| 142 | const auto new_path = FileUtil::SanitizePath(new_path_); | ||
| 143 | |||
| 144 | // Non-default impls are highly encouraged to provide a more optimized version of this. | ||
| 145 | auto out = CopyDirectory(old_path_, new_path_); | ||
| 146 | if (out == nullptr) | ||
| 147 | return nullptr; | ||
| 148 | if (DeleteDirectory(old_path)) | ||
| 149 | return out; | ||
| 150 | return nullptr; | ||
| 151 | } | ||
| 152 | |||
| 153 | bool VfsFilesystem::DeleteDirectory(std::string_view path_) { | ||
| 154 | const auto path = FileUtil::SanitizePath(path_); | ||
| 155 | auto parent = OpenDirectory(FileUtil::GetParentPath(path), Mode::Write); | ||
| 156 | if (parent == nullptr) | ||
| 157 | return false; | ||
| 158 | return parent->DeleteSubdirectoryRecursive(FileUtil::GetFilename(path)); | ||
| 159 | } | ||
| 160 | |||
| 13 | VfsFile::~VfsFile() = default; | 161 | VfsFile::~VfsFile() = default; |
| 14 | 162 | ||
| 15 | std::string VfsFile::GetExtension() const { | 163 | std::string VfsFile::GetExtension() const { |
diff --git a/src/core/file_sys/vfs.h b/src/core/file_sys/vfs.h index fab9e2b45..141a053ce 100644 --- a/src/core/file_sys/vfs.h +++ b/src/core/file_sys/vfs.h | |||
| @@ -11,14 +11,74 @@ | |||
| 11 | #include <vector> | 11 | #include <vector> |
| 12 | #include "boost/optional.hpp" | 12 | #include "boost/optional.hpp" |
| 13 | #include "common/common_types.h" | 13 | #include "common/common_types.h" |
| 14 | #include "core/file_sys/mode.h" | ||
| 14 | 15 | ||
| 15 | namespace FileSys { | 16 | namespace FileSys { |
| 17 | |||
| 18 | struct VfsFilesystem; | ||
| 16 | struct VfsFile; | 19 | struct VfsFile; |
| 17 | struct VfsDirectory; | 20 | struct VfsDirectory; |
| 18 | 21 | ||
| 19 | // Convenience typedefs to use VfsDirectory and VfsFile | 22 | // Convenience typedefs to use Vfs* interfaces |
| 20 | using VirtualDir = std::shared_ptr<FileSys::VfsDirectory>; | 23 | using VirtualFilesystem = std::shared_ptr<VfsFilesystem>; |
| 21 | using VirtualFile = std::shared_ptr<FileSys::VfsFile>; | 24 | using VirtualDir = std::shared_ptr<VfsDirectory>; |
| 25 | using VirtualFile = std::shared_ptr<VfsFile>; | ||
| 26 | |||
| 27 | // An enumeration representing what can be at the end of a path in a VfsFilesystem | ||
| 28 | enum class VfsEntryType { | ||
| 29 | None, | ||
| 30 | File, | ||
| 31 | Directory, | ||
| 32 | }; | ||
| 33 | |||
| 34 | // A class representing an abstract filesystem. A default implementation given the root VirtualDir | ||
| 35 | // is provided for convenience, but if the Vfs implementation has any additional state or | ||
| 36 | // functionality, they will need to override. | ||
| 37 | struct VfsFilesystem : NonCopyable { | ||
| 38 | VfsFilesystem(VirtualDir root); | ||
| 39 | virtual ~VfsFilesystem(); | ||
| 40 | |||
| 41 | // Gets the friendly name for the filesystem. | ||
| 42 | virtual std::string GetName() const; | ||
| 43 | |||
| 44 | // Return whether or not the user has read permissions on this filesystem. | ||
| 45 | virtual bool IsReadable() const; | ||
| 46 | // Return whether or not the user has write permission on this filesystem. | ||
| 47 | virtual bool IsWritable() const; | ||
| 48 | |||
| 49 | // Determine if the entry at path is non-existant, a file, or a directory. | ||
| 50 | virtual VfsEntryType GetEntryType(std::string_view path) const; | ||
| 51 | |||
| 52 | // Opens the file with path relative to root. If it doesn't exist, returns nullptr. | ||
| 53 | virtual VirtualFile OpenFile(std::string_view path, Mode perms); | ||
| 54 | // Creates a new, empty file at path | ||
| 55 | virtual VirtualFile CreateFile(std::string_view path, Mode perms); | ||
| 56 | // Copies the file from old_path to new_path, returning the new file on success and nullptr on | ||
| 57 | // failure. | ||
| 58 | virtual VirtualFile CopyFile(std::string_view old_path, std::string_view new_path); | ||
| 59 | // Moves the file from old_path to new_path, returning the moved file on success and nullptr on | ||
| 60 | // failure. | ||
| 61 | virtual VirtualFile MoveFile(std::string_view old_path, std::string_view new_path); | ||
| 62 | // Deletes the file with path relative to root, returing true on success. | ||
| 63 | virtual bool DeleteFile(std::string_view path); | ||
| 64 | |||
| 65 | // Opens the directory with path relative to root. If it doesn't exist, returns nullptr. | ||
| 66 | virtual VirtualDir OpenDirectory(std::string_view path, Mode perms); | ||
| 67 | // Creates a new, empty directory at path | ||
| 68 | virtual VirtualDir CreateDirectory(std::string_view path, Mode perms); | ||
| 69 | // Copies the directory from old_path to new_path, returning the new directory on success and | ||
| 70 | // nullptr on failure. | ||
| 71 | virtual VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path); | ||
| 72 | // Moves the directory from old_path to new_path, returning the moved directory on success and | ||
| 73 | // nullptr on failure. | ||
| 74 | virtual VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path); | ||
| 75 | // Deletes the directory with path relative to root, returing true on success. | ||
| 76 | virtual bool DeleteDirectory(std::string_view path); | ||
| 77 | |||
| 78 | protected: | ||
| 79 | // Root directory in default implementation. | ||
| 80 | VirtualDir root; | ||
| 81 | }; | ||
| 22 | 82 | ||
| 23 | // A class representing a file in an abstract filesystem. | 83 | // A class representing a file in an abstract filesystem. |
| 24 | struct VfsFile : NonCopyable { | 84 | struct VfsFile : NonCopyable { |
diff --git a/src/core/file_sys/vfs_real.cpp b/src/core/file_sys/vfs_real.cpp index 82d54da4a..1b5919737 100644 --- a/src/core/file_sys/vfs_real.cpp +++ b/src/core/file_sys/vfs_real.cpp | |||
| @@ -6,7 +6,7 @@ | |||
| 6 | #include <cstddef> | 6 | #include <cstddef> |
| 7 | #include <iterator> | 7 | #include <iterator> |
| 8 | #include <utility> | 8 | #include <utility> |
| 9 | 9 | #include "common/assert.h" | |
| 10 | #include "common/common_paths.h" | 10 | #include "common/common_paths.h" |
| 11 | #include "common/logging/log.h" | 11 | #include "common/logging/log.h" |
| 12 | #include "core/file_sys/vfs_real.h" | 12 | #include "core/file_sys/vfs_real.h" |
| @@ -29,6 +29,8 @@ static std::string ModeFlagsToString(Mode mode) { | |||
| 29 | mode_str = "a"; | 29 | mode_str = "a"; |
| 30 | else if (mode & Mode::Write) | 30 | else if (mode & Mode::Write) |
| 31 | mode_str = "w"; | 31 | mode_str = "w"; |
| 32 | else | ||
| 33 | UNREACHABLE_MSG("Invalid file open mode: {:02X}", static_cast<u8>(mode)); | ||
| 32 | } | 34 | } |
| 33 | 35 | ||
| 34 | mode_str += "b"; | 36 | mode_str += "b"; |
| @@ -36,8 +38,174 @@ static std::string ModeFlagsToString(Mode mode) { | |||
| 36 | return mode_str; | 38 | return mode_str; |
| 37 | } | 39 | } |
| 38 | 40 | ||
| 39 | RealVfsFile::RealVfsFile(const std::string& path_, Mode perms_) | 41 | RealVfsFilesystem::RealVfsFilesystem() : VfsFilesystem(nullptr) {} |
| 40 | : backing(path_, ModeFlagsToString(perms_).c_str()), path(path_), | 42 | |
| 43 | std::string RealVfsFilesystem::GetName() const { | ||
| 44 | return "Real"; | ||
| 45 | } | ||
| 46 | |||
| 47 | bool RealVfsFilesystem::IsReadable() const { | ||
| 48 | return true; | ||
| 49 | } | ||
| 50 | |||
| 51 | bool RealVfsFilesystem::IsWritable() const { | ||
| 52 | return true; | ||
| 53 | } | ||
| 54 | |||
| 55 | VfsEntryType RealVfsFilesystem::GetEntryType(std::string_view path_) const { | ||
| 56 | const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 57 | if (!FileUtil::Exists(path)) | ||
| 58 | return VfsEntryType::None; | ||
| 59 | if (FileUtil::IsDirectory(path)) | ||
| 60 | return VfsEntryType::Directory; | ||
| 61 | |||
| 62 | return VfsEntryType::File; | ||
| 63 | } | ||
| 64 | |||
| 65 | VirtualFile RealVfsFilesystem::OpenFile(std::string_view path_, Mode perms) { | ||
| 66 | const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 67 | if (cache.find(path) != cache.end()) { | ||
| 68 | auto weak = cache[path]; | ||
| 69 | if (!weak.expired()) { | ||
| 70 | return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, weak.lock(), path, perms)); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 74 | if (!FileUtil::Exists(path) && (perms & Mode::WriteAppend) != 0) | ||
| 75 | FileUtil::CreateEmptyFile(path); | ||
| 76 | |||
| 77 | auto backing = std::make_shared<FileUtil::IOFile>(path, ModeFlagsToString(perms).c_str()); | ||
| 78 | cache[path] = backing; | ||
| 79 | |||
| 80 | // Cannot use make_shared as RealVfsFile constructor is private | ||
| 81 | return std::shared_ptr<RealVfsFile>(new RealVfsFile(*this, backing, path, perms)); | ||
| 82 | } | ||
| 83 | |||
| 84 | VirtualFile RealVfsFilesystem::CreateFile(std::string_view path_, Mode perms) { | ||
| 85 | const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 86 | if (!FileUtil::Exists(path) && !FileUtil::CreateEmptyFile(path)) | ||
| 87 | return nullptr; | ||
| 88 | return OpenFile(path, perms); | ||
| 89 | } | ||
| 90 | |||
| 91 | VirtualFile RealVfsFilesystem::CopyFile(std::string_view old_path_, std::string_view new_path_) { | ||
| 92 | const auto old_path = | ||
| 93 | FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 94 | const auto new_path = | ||
| 95 | FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 96 | |||
| 97 | if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || | ||
| 98 | FileUtil::IsDirectory(old_path) || !FileUtil::Copy(old_path, new_path)) | ||
| 99 | return nullptr; | ||
| 100 | return OpenFile(new_path, Mode::ReadWrite); | ||
| 101 | } | ||
| 102 | |||
| 103 | VirtualFile RealVfsFilesystem::MoveFile(std::string_view old_path_, std::string_view new_path_) { | ||
| 104 | const auto old_path = | ||
| 105 | FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 106 | const auto new_path = | ||
| 107 | FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 108 | |||
| 109 | if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || | ||
| 110 | FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) | ||
| 111 | return nullptr; | ||
| 112 | |||
| 113 | if (cache.find(old_path) != cache.end()) { | ||
| 114 | auto cached = cache[old_path]; | ||
| 115 | if (!cached.expired()) { | ||
| 116 | auto file = cached.lock(); | ||
| 117 | file->Open(new_path, "r+b"); | ||
| 118 | cache.erase(old_path); | ||
| 119 | cache[new_path] = file; | ||
| 120 | } | ||
| 121 | } | ||
| 122 | return OpenFile(new_path, Mode::ReadWrite); | ||
| 123 | } | ||
| 124 | |||
| 125 | bool RealVfsFilesystem::DeleteFile(std::string_view path_) { | ||
| 126 | const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 127 | if (cache.find(path) != cache.end()) { | ||
| 128 | if (!cache[path].expired()) | ||
| 129 | cache[path].lock()->Close(); | ||
| 130 | cache.erase(path); | ||
| 131 | } | ||
| 132 | return FileUtil::Delete(path); | ||
| 133 | } | ||
| 134 | |||
| 135 | VirtualDir RealVfsFilesystem::OpenDirectory(std::string_view path_, Mode perms) { | ||
| 136 | const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 137 | // Cannot use make_shared as RealVfsDirectory constructor is private | ||
| 138 | return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms)); | ||
| 139 | } | ||
| 140 | |||
| 141 | VirtualDir RealVfsFilesystem::CreateDirectory(std::string_view path_, Mode perms) { | ||
| 142 | const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 143 | if (!FileUtil::Exists(path) && !FileUtil::CreateDir(path)) | ||
| 144 | return nullptr; | ||
| 145 | // Cannot use make_shared as RealVfsDirectory constructor is private | ||
| 146 | return std::shared_ptr<RealVfsDirectory>(new RealVfsDirectory(*this, path, perms)); | ||
| 147 | } | ||
| 148 | |||
| 149 | VirtualDir RealVfsFilesystem::CopyDirectory(std::string_view old_path_, | ||
| 150 | std::string_view new_path_) { | ||
| 151 | const auto old_path = | ||
| 152 | FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 153 | const auto new_path = | ||
| 154 | FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 155 | if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || | ||
| 156 | !FileUtil::IsDirectory(old_path)) | ||
| 157 | return nullptr; | ||
| 158 | FileUtil::CopyDir(old_path, new_path); | ||
| 159 | return OpenDirectory(new_path, Mode::ReadWrite); | ||
| 160 | } | ||
| 161 | |||
| 162 | VirtualDir RealVfsFilesystem::MoveDirectory(std::string_view old_path_, | ||
| 163 | std::string_view new_path_) { | ||
| 164 | const auto old_path = | ||
| 165 | FileUtil::SanitizePath(old_path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 166 | const auto new_path = | ||
| 167 | FileUtil::SanitizePath(new_path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 168 | if (!FileUtil::Exists(old_path) || FileUtil::Exists(new_path) || | ||
| 169 | FileUtil::IsDirectory(old_path) || !FileUtil::Rename(old_path, new_path)) | ||
| 170 | return nullptr; | ||
| 171 | |||
| 172 | for (auto& kv : cache) { | ||
| 173 | // Path in cache starts with old_path | ||
| 174 | if (kv.first.rfind(old_path, 0) == 0) { | ||
| 175 | const auto file_old_path = | ||
| 176 | FileUtil::SanitizePath(kv.first, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 177 | const auto file_new_path = | ||
| 178 | FileUtil::SanitizePath(new_path + DIR_SEP + kv.first.substr(old_path.size()), | ||
| 179 | FileUtil::DirectorySeparator::PlatformDefault); | ||
| 180 | auto cached = cache[file_old_path]; | ||
| 181 | if (!cached.expired()) { | ||
| 182 | auto file = cached.lock(); | ||
| 183 | file->Open(file_new_path, "r+b"); | ||
| 184 | cache.erase(file_old_path); | ||
| 185 | cache[file_new_path] = file; | ||
| 186 | } | ||
| 187 | } | ||
| 188 | } | ||
| 189 | |||
| 190 | return OpenDirectory(new_path, Mode::ReadWrite); | ||
| 191 | } | ||
| 192 | |||
| 193 | bool RealVfsFilesystem::DeleteDirectory(std::string_view path_) { | ||
| 194 | const auto path = FileUtil::SanitizePath(path_, FileUtil::DirectorySeparator::PlatformDefault); | ||
| 195 | for (auto& kv : cache) { | ||
| 196 | // Path in cache starts with old_path | ||
| 197 | if (kv.first.rfind(path, 0) == 0) { | ||
| 198 | if (!cache[kv.first].expired()) | ||
| 199 | cache[kv.first].lock()->Close(); | ||
| 200 | cache.erase(kv.first); | ||
| 201 | } | ||
| 202 | } | ||
| 203 | return FileUtil::DeleteDirRecursively(path); | ||
| 204 | } | ||
| 205 | |||
| 206 | RealVfsFile::RealVfsFile(RealVfsFilesystem& base_, std::shared_ptr<FileUtil::IOFile> backing_, | ||
| 207 | const std::string& path_, Mode perms_) | ||
| 208 | : base(base_), backing(std::move(backing_)), path(path_), | ||
| 41 | parent_path(FileUtil::GetParentPath(path_)), | 209 | parent_path(FileUtil::GetParentPath(path_)), |
| 42 | path_components(FileUtil::SplitPathComponents(path_)), | 210 | path_components(FileUtil::SplitPathComponents(path_)), |
| 43 | parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), | 211 | parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), |
| @@ -48,15 +216,15 @@ std::string RealVfsFile::GetName() const { | |||
| 48 | } | 216 | } |
| 49 | 217 | ||
| 50 | size_t RealVfsFile::GetSize() const { | 218 | size_t RealVfsFile::GetSize() const { |
| 51 | return backing.GetSize(); | 219 | return backing->GetSize(); |
| 52 | } | 220 | } |
| 53 | 221 | ||
| 54 | bool RealVfsFile::Resize(size_t new_size) { | 222 | bool RealVfsFile::Resize(size_t new_size) { |
| 55 | return backing.Resize(new_size); | 223 | return backing->Resize(new_size); |
| 56 | } | 224 | } |
| 57 | 225 | ||
| 58 | std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const { | 226 | std::shared_ptr<VfsDirectory> RealVfsFile::GetContainingDirectory() const { |
| 59 | return std::make_shared<RealVfsDirectory>(parent_path, perms); | 227 | return base.OpenDirectory(parent_path, perms); |
| 60 | } | 228 | } |
| 61 | 229 | ||
| 62 | bool RealVfsFile::IsWritable() const { | 230 | bool RealVfsFile::IsWritable() const { |
| @@ -68,62 +236,118 @@ bool RealVfsFile::IsReadable() const { | |||
| 68 | } | 236 | } |
| 69 | 237 | ||
| 70 | size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const { | 238 | size_t RealVfsFile::Read(u8* data, size_t length, size_t offset) const { |
| 71 | if (!backing.Seek(offset, SEEK_SET)) | 239 | if (!backing->Seek(offset, SEEK_SET)) |
| 72 | return 0; | 240 | return 0; |
| 73 | return backing.ReadBytes(data, length); | 241 | return backing->ReadBytes(data, length); |
| 74 | } | 242 | } |
| 75 | 243 | ||
| 76 | size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) { | 244 | size_t RealVfsFile::Write(const u8* data, size_t length, size_t offset) { |
| 77 | if (!backing.Seek(offset, SEEK_SET)) | 245 | if (!backing->Seek(offset, SEEK_SET)) |
| 78 | return 0; | 246 | return 0; |
| 79 | return backing.WriteBytes(data, length); | 247 | return backing->WriteBytes(data, length); |
| 80 | } | 248 | } |
| 81 | 249 | ||
| 82 | bool RealVfsFile::Rename(std::string_view name) { | 250 | bool RealVfsFile::Rename(std::string_view name) { |
| 83 | std::string name_str(name.begin(), name.end()); | 251 | return base.MoveFile(path, parent_path + DIR_SEP + std::string(name)) != nullptr; |
| 84 | const auto out = FileUtil::Rename(GetName(), name_str); | 252 | } |
| 253 | |||
| 254 | bool RealVfsFile::Close() { | ||
| 255 | return backing->Close(); | ||
| 256 | } | ||
| 85 | 257 | ||
| 86 | path = (parent_path + DIR_SEP).append(name); | 258 | // TODO(DarkLordZach): MSVC would not let me combine the following two functions using 'if |
| 87 | path_components = parent_components; | 259 | // constexpr' because there is a compile error in the branch not used. |
| 88 | path_components.push_back(std::move(name_str)); | 260 | |
| 89 | backing = FileUtil::IOFile(path, ModeFlagsToString(perms).c_str()); | 261 | template <> |
| 262 | std::vector<VirtualFile> RealVfsDirectory::IterateEntries<RealVfsFile, VfsFile>() const { | ||
| 263 | if (perms == Mode::Append) | ||
| 264 | return {}; | ||
| 265 | |||
| 266 | std::vector<VirtualFile> out; | ||
| 267 | FileUtil::ForeachDirectoryEntry( | ||
| 268 | nullptr, path, | ||
| 269 | [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) { | ||
| 270 | const std::string full_path = directory + DIR_SEP + filename; | ||
| 271 | if (!FileUtil::IsDirectory(full_path)) | ||
| 272 | out.emplace_back(base.OpenFile(full_path, perms)); | ||
| 273 | return true; | ||
| 274 | }); | ||
| 90 | 275 | ||
| 91 | return out; | 276 | return out; |
| 92 | } | 277 | } |
| 93 | 278 | ||
| 94 | bool RealVfsFile::Close() { | 279 | template <> |
| 95 | return backing.Close(); | 280 | std::vector<VirtualDir> RealVfsDirectory::IterateEntries<RealVfsDirectory, VfsDirectory>() const { |
| 281 | if (perms == Mode::Append) | ||
| 282 | return {}; | ||
| 283 | |||
| 284 | std::vector<VirtualDir> out; | ||
| 285 | FileUtil::ForeachDirectoryEntry( | ||
| 286 | nullptr, path, | ||
| 287 | [&out, this](u64* entries_out, const std::string& directory, const std::string& filename) { | ||
| 288 | const std::string full_path = directory + DIR_SEP + filename; | ||
| 289 | if (FileUtil::IsDirectory(full_path)) | ||
| 290 | out.emplace_back(base.OpenDirectory(full_path, perms)); | ||
| 291 | return true; | ||
| 292 | }); | ||
| 293 | |||
| 294 | return out; | ||
| 96 | } | 295 | } |
| 97 | 296 | ||
| 98 | RealVfsDirectory::RealVfsDirectory(const std::string& path_, Mode perms_) | 297 | RealVfsDirectory::RealVfsDirectory(RealVfsFilesystem& base_, const std::string& path_, Mode perms_) |
| 99 | : path(FileUtil::RemoveTrailingSlash(path_)), parent_path(FileUtil::GetParentPath(path)), | 298 | : base(base_), path(FileUtil::RemoveTrailingSlash(path_)), |
| 299 | parent_path(FileUtil::GetParentPath(path)), | ||
| 100 | path_components(FileUtil::SplitPathComponents(path)), | 300 | path_components(FileUtil::SplitPathComponents(path)), |
| 101 | parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), | 301 | parent_components(FileUtil::SliceVector(path_components, 0, path_components.size() - 1)), |
| 102 | perms(perms_) { | 302 | perms(perms_) { |
| 103 | if (!FileUtil::Exists(path) && perms & Mode::WriteAppend) | 303 | if (!FileUtil::Exists(path) && perms & Mode::WriteAppend) |
| 104 | FileUtil::CreateDir(path); | 304 | FileUtil::CreateDir(path); |
| 305 | } | ||
| 105 | 306 | ||
| 106 | if (perms == Mode::Append) | 307 | std::shared_ptr<VfsFile> RealVfsDirectory::GetFileRelative(std::string_view path) const { |
| 107 | return; | 308 | const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); |
| 309 | if (!FileUtil::Exists(full_path)) | ||
| 310 | return nullptr; | ||
| 311 | return base.OpenFile(full_path, perms); | ||
| 312 | } | ||
| 108 | 313 | ||
| 109 | FileUtil::ForeachDirectoryEntry( | 314 | std::shared_ptr<VfsDirectory> RealVfsDirectory::GetDirectoryRelative(std::string_view path) const { |
| 110 | nullptr, path, | 315 | const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); |
| 111 | [this](u64* entries_out, const std::string& directory, const std::string& filename) { | 316 | if (!FileUtil::Exists(full_path)) |
| 112 | std::string full_path = directory + DIR_SEP + filename; | 317 | return nullptr; |
| 113 | if (FileUtil::IsDirectory(full_path)) | 318 | return base.OpenDirectory(full_path, perms); |
| 114 | subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(full_path, perms)); | 319 | } |
| 115 | else | 320 | |
| 116 | files.emplace_back(std::make_shared<RealVfsFile>(full_path, perms)); | 321 | std::shared_ptr<VfsFile> RealVfsDirectory::GetFile(std::string_view name) const { |
| 117 | return true; | 322 | return GetFileRelative(name); |
| 118 | }); | 323 | } |
| 324 | |||
| 325 | std::shared_ptr<VfsDirectory> RealVfsDirectory::GetSubdirectory(std::string_view name) const { | ||
| 326 | return GetDirectoryRelative(name); | ||
| 327 | } | ||
| 328 | |||
| 329 | std::shared_ptr<VfsFile> RealVfsDirectory::CreateFileRelative(std::string_view path) { | ||
| 330 | const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); | ||
| 331 | return base.CreateFile(full_path, perms); | ||
| 332 | } | ||
| 333 | |||
| 334 | std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateDirectoryRelative(std::string_view path) { | ||
| 335 | const auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(path)); | ||
| 336 | auto parent = std::string(FileUtil::GetParentPath(full_path)); | ||
| 337 | return base.CreateDirectory(full_path, perms); | ||
| 338 | } | ||
| 339 | |||
| 340 | bool RealVfsDirectory::DeleteSubdirectoryRecursive(std::string_view name) { | ||
| 341 | auto full_path = FileUtil::SanitizePath(this->path + DIR_SEP + std::string(name)); | ||
| 342 | return base.DeleteDirectory(full_path); | ||
| 119 | } | 343 | } |
| 120 | 344 | ||
| 121 | std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const { | 345 | std::vector<std::shared_ptr<VfsFile>> RealVfsDirectory::GetFiles() const { |
| 122 | return files; | 346 | return IterateEntries<RealVfsFile, VfsFile>(); |
| 123 | } | 347 | } |
| 124 | 348 | ||
| 125 | std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const { | 349 | std::vector<std::shared_ptr<VfsDirectory>> RealVfsDirectory::GetSubdirectories() const { |
| 126 | return subdirectories; | 350 | return IterateEntries<RealVfsDirectory, VfsDirectory>(); |
| 127 | } | 351 | } |
| 128 | 352 | ||
| 129 | bool RealVfsDirectory::IsWritable() const { | 353 | bool RealVfsDirectory::IsWritable() const { |
| @@ -142,57 +366,32 @@ std::shared_ptr<VfsDirectory> RealVfsDirectory::GetParentDirectory() const { | |||
| 142 | if (path_components.size() <= 1) | 366 | if (path_components.size() <= 1) |
| 143 | return nullptr; | 367 | return nullptr; |
| 144 | 368 | ||
| 145 | return std::make_shared<RealVfsDirectory>(parent_path, perms); | 369 | return base.OpenDirectory(parent_path, perms); |
| 146 | } | 370 | } |
| 147 | 371 | ||
| 148 | std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(std::string_view name) { | 372 | std::shared_ptr<VfsDirectory> RealVfsDirectory::CreateSubdirectory(std::string_view name) { |
| 149 | const std::string subdir_path = (path + DIR_SEP).append(name); | 373 | const std::string subdir_path = (path + DIR_SEP).append(name); |
| 150 | 374 | return base.CreateDirectory(subdir_path, perms); | |
| 151 | if (!FileUtil::CreateDir(subdir_path)) { | ||
| 152 | return nullptr; | ||
| 153 | } | ||
| 154 | |||
| 155 | subdirectories.emplace_back(std::make_shared<RealVfsDirectory>(subdir_path, perms)); | ||
| 156 | return subdirectories.back(); | ||
| 157 | } | 375 | } |
| 158 | 376 | ||
| 159 | std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(std::string_view name) { | 377 | std::shared_ptr<VfsFile> RealVfsDirectory::CreateFile(std::string_view name) { |
| 160 | const std::string file_path = (path + DIR_SEP).append(name); | 378 | const std::string file_path = (path + DIR_SEP).append(name); |
| 161 | 379 | return base.CreateFile(file_path, perms); | |
| 162 | if (!FileUtil::CreateEmptyFile(file_path)) { | ||
| 163 | return nullptr; | ||
| 164 | } | ||
| 165 | |||
| 166 | files.emplace_back(std::make_shared<RealVfsFile>(file_path, perms)); | ||
| 167 | return files.back(); | ||
| 168 | } | 380 | } |
| 169 | 381 | ||
| 170 | bool RealVfsDirectory::DeleteSubdirectory(std::string_view name) { | 382 | bool RealVfsDirectory::DeleteSubdirectory(std::string_view name) { |
| 171 | const std::string subdir_path = (path + DIR_SEP).append(name); | 383 | const std::string subdir_path = (path + DIR_SEP).append(name); |
| 172 | 384 | return base.DeleteDirectory(subdir_path); | |
| 173 | return FileUtil::DeleteDirRecursively(subdir_path); | ||
| 174 | } | 385 | } |
| 175 | 386 | ||
| 176 | bool RealVfsDirectory::DeleteFile(std::string_view name) { | 387 | bool RealVfsDirectory::DeleteFile(std::string_view name) { |
| 177 | const auto file = GetFile(name); | ||
| 178 | |||
| 179 | if (file == nullptr) { | ||
| 180 | return false; | ||
| 181 | } | ||
| 182 | |||
| 183 | files.erase(std::find(files.begin(), files.end(), file)); | ||
| 184 | |||
| 185 | auto real_file = std::static_pointer_cast<RealVfsFile>(file); | ||
| 186 | real_file->Close(); | ||
| 187 | |||
| 188 | const std::string file_path = (path + DIR_SEP).append(name); | 388 | const std::string file_path = (path + DIR_SEP).append(name); |
| 189 | return FileUtil::Delete(file_path); | 389 | return base.DeleteFile(file_path); |
| 190 | } | 390 | } |
| 191 | 391 | ||
| 192 | bool RealVfsDirectory::Rename(std::string_view name) { | 392 | bool RealVfsDirectory::Rename(std::string_view name) { |
| 193 | const std::string new_name = (parent_path + DIR_SEP).append(name); | 393 | const std::string new_name = (parent_path + DIR_SEP).append(name); |
| 194 | 394 | return base.MoveFile(path, new_name) != nullptr; | |
| 195 | return FileUtil::Rename(path, new_name); | ||
| 196 | } | 395 | } |
| 197 | 396 | ||
| 198 | std::string RealVfsDirectory::GetFullPath() const { | 397 | std::string RealVfsDirectory::GetFullPath() const { |
| @@ -202,16 +401,6 @@ std::string RealVfsDirectory::GetFullPath() const { | |||
| 202 | } | 401 | } |
| 203 | 402 | ||
| 204 | bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { | 403 | bool RealVfsDirectory::ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) { |
| 205 | const auto iter = std::find(files.begin(), files.end(), file); | 404 | return false; |
| 206 | if (iter == files.end()) | ||
| 207 | return false; | ||
| 208 | |||
| 209 | const std::ptrdiff_t offset = std::distance(files.begin(), iter); | ||
| 210 | files[offset] = files.back(); | ||
| 211 | files.pop_back(); | ||
| 212 | |||
| 213 | subdirectories.emplace_back(std::move(dir)); | ||
| 214 | |||
| 215 | return true; | ||
| 216 | } | 405 | } |
| 217 | } // namespace FileSys | 406 | } // namespace FileSys |
diff --git a/src/core/file_sys/vfs_real.h b/src/core/file_sys/vfs_real.h index 243d58576..8a1e79ef6 100644 --- a/src/core/file_sys/vfs_real.h +++ b/src/core/file_sys/vfs_real.h | |||
| @@ -6,18 +6,45 @@ | |||
| 6 | 6 | ||
| 7 | #include <string_view> | 7 | #include <string_view> |
| 8 | 8 | ||
| 9 | #include <boost/container/flat_map.hpp> | ||
| 9 | #include "common/file_util.h" | 10 | #include "common/file_util.h" |
| 10 | #include "core/file_sys/mode.h" | 11 | #include "core/file_sys/mode.h" |
| 11 | #include "core/file_sys/vfs.h" | 12 | #include "core/file_sys/vfs.h" |
| 12 | 13 | ||
| 13 | namespace FileSys { | 14 | namespace FileSys { |
| 14 | 15 | ||
| 16 | class RealVfsFilesystem : public VfsFilesystem { | ||
| 17 | public: | ||
| 18 | RealVfsFilesystem(); | ||
| 19 | |||
| 20 | std::string GetName() const override; | ||
| 21 | bool IsReadable() const override; | ||
| 22 | bool IsWritable() const override; | ||
| 23 | VfsEntryType GetEntryType(std::string_view path) const override; | ||
| 24 | VirtualFile OpenFile(std::string_view path, Mode perms = Mode::Read) override; | ||
| 25 | VirtualFile CreateFile(std::string_view path, Mode perms = Mode::ReadWrite) override; | ||
| 26 | VirtualFile CopyFile(std::string_view old_path, std::string_view new_path) override; | ||
| 27 | VirtualFile MoveFile(std::string_view old_path, std::string_view new_path) override; | ||
| 28 | bool DeleteFile(std::string_view path) override; | ||
| 29 | VirtualDir OpenDirectory(std::string_view path, Mode perms = Mode::Read) override; | ||
| 30 | VirtualDir CreateDirectory(std::string_view path, Mode perms = Mode::ReadWrite) override; | ||
| 31 | VirtualDir CopyDirectory(std::string_view old_path, std::string_view new_path) override; | ||
| 32 | VirtualDir MoveDirectory(std::string_view old_path, std::string_view new_path) override; | ||
| 33 | bool DeleteDirectory(std::string_view path) override; | ||
| 34 | |||
| 35 | private: | ||
| 36 | boost::container::flat_map<std::string, std::weak_ptr<FileUtil::IOFile>> cache; | ||
| 37 | }; | ||
| 38 | |||
| 15 | // An implmentation of VfsFile that represents a file on the user's computer. | 39 | // An implmentation of VfsFile that represents a file on the user's computer. |
| 16 | struct RealVfsFile : public VfsFile { | 40 | class RealVfsFile : public VfsFile { |
| 17 | friend struct RealVfsDirectory; | 41 | friend class RealVfsDirectory; |
| 42 | friend class RealVfsFilesystem; | ||
| 18 | 43 | ||
| 19 | RealVfsFile(const std::string& name, Mode perms = Mode::Read); | 44 | RealVfsFile(RealVfsFilesystem& base, std::shared_ptr<FileUtil::IOFile> backing, |
| 45 | const std::string& path, Mode perms = Mode::Read); | ||
| 20 | 46 | ||
| 47 | public: | ||
| 21 | std::string GetName() const override; | 48 | std::string GetName() const override; |
| 22 | size_t GetSize() const override; | 49 | size_t GetSize() const override; |
| 23 | bool Resize(size_t new_size) override; | 50 | bool Resize(size_t new_size) override; |
| @@ -31,7 +58,8 @@ struct RealVfsFile : public VfsFile { | |||
| 31 | private: | 58 | private: |
| 32 | bool Close(); | 59 | bool Close(); |
| 33 | 60 | ||
| 34 | FileUtil::IOFile backing; | 61 | RealVfsFilesystem& base; |
| 62 | std::shared_ptr<FileUtil::IOFile> backing; | ||
| 35 | std::string path; | 63 | std::string path; |
| 36 | std::string parent_path; | 64 | std::string parent_path; |
| 37 | std::vector<std::string> path_components; | 65 | std::vector<std::string> path_components; |
| @@ -40,9 +68,19 @@ private: | |||
| 40 | }; | 68 | }; |
| 41 | 69 | ||
| 42 | // An implementation of VfsDirectory that represents a directory on the user's computer. | 70 | // An implementation of VfsDirectory that represents a directory on the user's computer. |
| 43 | struct RealVfsDirectory : public VfsDirectory { | 71 | class RealVfsDirectory : public VfsDirectory { |
| 44 | RealVfsDirectory(const std::string& path, Mode perms = Mode::Read); | 72 | friend class RealVfsFilesystem; |
| 45 | 73 | ||
| 74 | RealVfsDirectory(RealVfsFilesystem& base, const std::string& path, Mode perms = Mode::Read); | ||
| 75 | |||
| 76 | public: | ||
| 77 | std::shared_ptr<VfsFile> GetFileRelative(std::string_view path) const override; | ||
| 78 | std::shared_ptr<VfsDirectory> GetDirectoryRelative(std::string_view path) const override; | ||
| 79 | std::shared_ptr<VfsFile> GetFile(std::string_view name) const override; | ||
| 80 | std::shared_ptr<VfsDirectory> GetSubdirectory(std::string_view name) const override; | ||
| 81 | std::shared_ptr<VfsFile> CreateFileRelative(std::string_view path) override; | ||
| 82 | std::shared_ptr<VfsDirectory> CreateDirectoryRelative(std::string_view path) override; | ||
| 83 | bool DeleteSubdirectoryRecursive(std::string_view name) override; | ||
| 46 | std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; | 84 | std::vector<std::shared_ptr<VfsFile>> GetFiles() const override; |
| 47 | std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; | 85 | std::vector<std::shared_ptr<VfsDirectory>> GetSubdirectories() const override; |
| 48 | bool IsWritable() const override; | 86 | bool IsWritable() const override; |
| @@ -60,13 +98,15 @@ protected: | |||
| 60 | bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; | 98 | bool ReplaceFileWithSubdirectory(VirtualFile file, VirtualDir dir) override; |
| 61 | 99 | ||
| 62 | private: | 100 | private: |
| 101 | template <typename T, typename R> | ||
| 102 | std::vector<std::shared_ptr<R>> IterateEntries() const; | ||
| 103 | |||
| 104 | RealVfsFilesystem& base; | ||
| 63 | std::string path; | 105 | std::string path; |
| 64 | std::string parent_path; | 106 | std::string parent_path; |
| 65 | std::vector<std::string> path_components; | 107 | std::vector<std::string> path_components; |
| 66 | std::vector<std::string> parent_components; | 108 | std::vector<std::string> parent_components; |
| 67 | Mode perms; | 109 | Mode perms; |
| 68 | std::vector<std::shared_ptr<VfsFile>> files; | ||
| 69 | std::vector<std::shared_ptr<VfsDirectory>> subdirectories; | ||
| 70 | }; | 110 | }; |
| 71 | 111 | ||
| 72 | } // namespace FileSys | 112 | } // namespace FileSys |
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp index 5dd1b68d7..82a3fb5a8 100644 --- a/src/core/hle/kernel/hle_ipc.cpp +++ b/src/core/hle/kernel/hle_ipc.cpp | |||
| @@ -201,7 +201,7 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdb | |||
| 201 | return RESULT_SUCCESS; | 201 | return RESULT_SUCCESS; |
| 202 | } | 202 | } |
| 203 | 203 | ||
| 204 | ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) { | 204 | ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread) { |
| 205 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf; | 205 | std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf; |
| 206 | Memory::ReadBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), | 206 | Memory::ReadBlock(*thread.owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(), |
| 207 | dst_cmdbuf.size() * sizeof(u32)); | 207 | dst_cmdbuf.size() * sizeof(u32)); |
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h index 9ce52db24..f0d07f1b6 100644 --- a/src/core/hle/kernel/hle_ipc.h +++ b/src/core/hle/kernel/hle_ipc.h | |||
| @@ -132,7 +132,7 @@ public: | |||
| 132 | ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process, | 132 | ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process, |
| 133 | HandleTable& src_table); | 133 | HandleTable& src_table); |
| 134 | /// Writes data from this context back to the requesting process/thread. | 134 | /// Writes data from this context back to the requesting process/thread. |
| 135 | ResultCode WriteToOutgoingCommandBuffer(Thread& thread); | 135 | ResultCode WriteToOutgoingCommandBuffer(const Thread& thread); |
| 136 | 136 | ||
| 137 | u32_le GetCommand() const { | 137 | u32_le GetCommand() const { |
| 138 | return command; | 138 | return command; |
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index 0a6cac5b7..e74379a24 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -38,7 +38,7 @@ public: | |||
| 38 | {0, &IProfile::Get, "Get"}, | 38 | {0, &IProfile::Get, "Get"}, |
| 39 | {1, &IProfile::GetBase, "GetBase"}, | 39 | {1, &IProfile::GetBase, "GetBase"}, |
| 40 | {10, nullptr, "GetImageSize"}, | 40 | {10, nullptr, "GetImageSize"}, |
| 41 | {11, nullptr, "LoadImage"}, | 41 | {11, &IProfile::LoadImage, "LoadImage"}, |
| 42 | }; | 42 | }; |
| 43 | RegisterHandlers(functions); | 43 | RegisterHandlers(functions); |
| 44 | } | 44 | } |
| @@ -72,6 +72,27 @@ private: | |||
| 72 | } | 72 | } |
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | void LoadImage(Kernel::HLERequestContext& ctx) { | ||
| 76 | LOG_WARNING(Service_ACC, "(STUBBED) called"); | ||
| 77 | // smallest jpeg https://github.com/mathiasbynens/small/blob/master/jpeg.jpg | ||
| 78 | // TODO(mailwl): load actual profile image from disk, width 256px, max size 0x20000 | ||
| 79 | const u32 jpeg_size = 107; | ||
| 80 | static const std::array<u8, jpeg_size> jpeg{ | ||
| 81 | 0xff, 0xd8, 0xff, 0xdb, 0x00, 0x43, 0x00, 0x03, 0x02, 0x02, 0x02, 0x02, 0x02, 0x03, | ||
| 82 | 0x02, 0x02, 0x02, 0x03, 0x03, 0x03, 0x03, 0x04, 0x06, 0x04, 0x04, 0x04, 0x04, 0x04, | ||
| 83 | 0x08, 0x06, 0x06, 0x05, 0x06, 0x09, 0x08, 0x0a, 0x0a, 0x09, 0x08, 0x09, 0x09, 0x0a, | ||
| 84 | 0x0c, 0x0f, 0x0c, 0x0a, 0x0b, 0x0e, 0x0b, 0x09, 0x09, 0x0d, 0x11, 0x0d, 0x0e, 0x0f, | ||
| 85 | 0x10, 0x10, 0x11, 0x10, 0x0a, 0x0c, 0x12, 0x13, 0x12, 0x10, 0x13, 0x0f, 0x10, 0x10, | ||
| 86 | 0x10, 0xff, 0xc9, 0x00, 0x0b, 0x08, 0x00, 0x01, 0x00, 0x01, 0x01, 0x01, 0x11, 0x00, | ||
| 87 | 0xff, 0xcc, 0x00, 0x06, 0x00, 0x10, 0x10, 0x05, 0xff, 0xda, 0x00, 0x08, 0x01, 0x01, | ||
| 88 | 0x00, 0x00, 0x3f, 0x00, 0xd2, 0xcf, 0x20, 0xff, 0xd9, | ||
| 89 | }; | ||
| 90 | ctx.WriteBuffer(jpeg.data(), jpeg_size); | ||
| 91 | IPC::ResponseBuilder rb{ctx, 3}; | ||
| 92 | rb.Push(RESULT_SUCCESS); | ||
| 93 | rb.Push<u32>(jpeg_size); | ||
| 94 | } | ||
| 95 | |||
| 75 | ProfileManager& profile_manager; | 96 | ProfileManager& profile_manager; |
| 76 | UUID user_id; ///< The user id this profile refers to. | 97 | UUID user_id; ///< The user id this profile refers to. |
| 77 | }; | 98 | }; |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 9404d6b8c..762763463 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -136,7 +136,7 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger | |||
| 136 | {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, | 136 | {16, &ISelfController::SetOutOfFocusSuspendingEnabled, "SetOutOfFocusSuspendingEnabled"}, |
| 137 | {17, nullptr, "SetControllerFirmwareUpdateSection"}, | 137 | {17, nullptr, "SetControllerFirmwareUpdateSection"}, |
| 138 | {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, | 138 | {18, nullptr, "SetRequiresCaptureButtonShortPressedMessage"}, |
| 139 | {19, nullptr, "SetScreenShotImageOrientation"}, | 139 | {19, &ISelfController::SetScreenShotImageOrientation, "SetScreenShotImageOrientation"}, |
| 140 | {20, nullptr, "SetDesirableKeyboardLayout"}, | 140 | {20, nullptr, "SetDesirableKeyboardLayout"}, |
| 141 | {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, | 141 | {40, &ISelfController::CreateManagedDisplayLayer, "CreateManagedDisplayLayer"}, |
| 142 | {41, nullptr, "IsSystemBufferSharingEnabled"}, | 142 | {41, nullptr, "IsSystemBufferSharingEnabled"}, |
| @@ -254,6 +254,13 @@ void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& | |||
| 254 | LOG_WARNING(Service_AM, "(STUBBED) called"); | 254 | LOG_WARNING(Service_AM, "(STUBBED) called"); |
| 255 | } | 255 | } |
| 256 | 256 | ||
| 257 | void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { | ||
| 258 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 259 | rb.Push(RESULT_SUCCESS); | ||
| 260 | |||
| 261 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 262 | } | ||
| 263 | |||
| 257 | void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { | 264 | void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { |
| 258 | // TODO(Subv): Find out how AM determines the display to use, for now just create the layer | 265 | // TODO(Subv): Find out how AM determines the display to use, for now just create the layer |
| 259 | // in the Default display. | 266 | // in the Default display. |
diff --git a/src/core/hle/service/am/am.h b/src/core/hle/service/am/am.h index 8f4f98346..862f338ac 100644 --- a/src/core/hle/service/am/am.h +++ b/src/core/hle/service/am/am.h | |||
| @@ -83,6 +83,7 @@ private: | |||
| 83 | void LockExit(Kernel::HLERequestContext& ctx); | 83 | void LockExit(Kernel::HLERequestContext& ctx); |
| 84 | void UnlockExit(Kernel::HLERequestContext& ctx); | 84 | void UnlockExit(Kernel::HLERequestContext& ctx); |
| 85 | void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx); | 85 | void GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx); |
| 86 | void SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx); | ||
| 86 | void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx); | 87 | void CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx); |
| 87 | void SetScreenShotPermission(Kernel::HLERequestContext& ctx); | 88 | void SetScreenShotPermission(Kernel::HLERequestContext& ctx); |
| 88 | void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx); | 89 | void SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index e17d637e4..5e416cde2 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -59,7 +59,7 @@ ResultCode VfsDirectoryServiceWrapper::CreateFile(const std::string& path_, u64 | |||
| 59 | ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const { | 59 | ResultCode VfsDirectoryServiceWrapper::DeleteFile(const std::string& path_) const { |
| 60 | std::string path(FileUtil::SanitizePath(path_)); | 60 | std::string path(FileUtil::SanitizePath(path_)); |
| 61 | auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); | 61 | auto dir = GetDirectoryRelativeWrapped(backing, FileUtil::GetParentPath(path)); |
| 62 | if (path == "/" || path == "\\") { | 62 | if (path.empty()) { |
| 63 | // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but... | 63 | // TODO(DarkLordZach): Why do games call this and what should it do? Works as is but... |
| 64 | return RESULT_SUCCESS; | 64 | return RESULT_SUCCESS; |
| 65 | } | 65 | } |
| @@ -281,15 +281,15 @@ ResultVal<FileSys::VirtualDir> OpenSDMC() { | |||
| 281 | return sdmc_factory->Open(); | 281 | return sdmc_factory->Open(); |
| 282 | } | 282 | } |
| 283 | 283 | ||
| 284 | void RegisterFileSystems() { | 284 | void RegisterFileSystems(const FileSys::VirtualFilesystem& vfs) { |
| 285 | romfs_factory = nullptr; | 285 | romfs_factory = nullptr; |
| 286 | save_data_factory = nullptr; | 286 | save_data_factory = nullptr; |
| 287 | sdmc_factory = nullptr; | 287 | sdmc_factory = nullptr; |
| 288 | 288 | ||
| 289 | auto nand_directory = std::make_shared<FileSys::RealVfsDirectory>( | 289 | auto nand_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), |
| 290 | FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), FileSys::Mode::ReadWrite); | 290 | FileSys::Mode::ReadWrite); |
| 291 | auto sd_directory = std::make_shared<FileSys::RealVfsDirectory>( | 291 | auto sd_directory = vfs->OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), |
| 292 | FileUtil::GetUserPath(FileUtil::UserPath::SDMCDir), FileSys::Mode::ReadWrite); | 292 | FileSys::Mode::ReadWrite); |
| 293 | 293 | ||
| 294 | auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); | 294 | auto savedata = std::make_unique<FileSys::SaveDataFactory>(std::move(nand_directory)); |
| 295 | save_data_factory = std::move(savedata); | 295 | save_data_factory = std::move(savedata); |
| @@ -298,8 +298,8 @@ void RegisterFileSystems() { | |||
| 298 | sdmc_factory = std::move(sdcard); | 298 | sdmc_factory = std::move(sdcard); |
| 299 | } | 299 | } |
| 300 | 300 | ||
| 301 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 301 | void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs) { |
| 302 | RegisterFileSystems(); | 302 | RegisterFileSystems(vfs); |
| 303 | std::make_shared<FSP_LDR>()->InstallAsService(service_manager); | 303 | std::make_shared<FSP_LDR>()->InstallAsService(service_manager); |
| 304 | std::make_shared<FSP_PR>()->InstallAsService(service_manager); | 304 | std::make_shared<FSP_PR>()->InstallAsService(service_manager); |
| 305 | std::make_shared<FSP_SRV>()->InstallAsService(service_manager); | 305 | std::make_shared<FSP_SRV>()->InstallAsService(service_manager); |
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index d4483daa5..462c13f20 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h | |||
| @@ -36,7 +36,7 @@ ResultVal<FileSys::VirtualDir> OpenSDMC(); | |||
| 36 | // ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS(); | 36 | // ResultVal<std::unique_ptr<FileSys::FileSystemBackend>> OpenBIS(); |
| 37 | 37 | ||
| 38 | /// Registers all Filesystem services with the specified service manager. | 38 | /// Registers all Filesystem services with the specified service manager. |
| 39 | void InstallInterfaces(SM::ServiceManager& service_manager); | 39 | void InstallInterfaces(SM::ServiceManager& service_manager, const FileSys::VirtualFilesystem& vfs); |
| 40 | 40 | ||
| 41 | // A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of | 41 | // A class that wraps a VfsDirectory with methods that return ResultVal and ResultCode instead of |
| 42 | // pointers and booleans. This makes using a VfsDirectory with switch services much easier and | 42 | // pointers and booleans. This makes using a VfsDirectory with switch services much easier and |
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index e7ffb6bd1..1470f9017 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -193,13 +193,10 @@ private: | |||
| 193 | template <typename T> | 193 | template <typename T> |
| 194 | static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data, | 194 | static void BuildEntryIndex(std::vector<FileSys::Entry>& entries, const std::vector<T>& new_data, |
| 195 | FileSys::EntryType type) { | 195 | FileSys::EntryType type) { |
| 196 | entries.reserve(entries.size() + new_data.size()); | ||
| 197 | |||
| 196 | for (const auto& new_entry : new_data) { | 198 | for (const auto& new_entry : new_data) { |
| 197 | FileSys::Entry entry; | 199 | entries.emplace_back(new_entry->GetName(), type, new_entry->GetSize()); |
| 198 | entry.filename[0] = '\0'; | ||
| 199 | std::strncat(entry.filename, new_entry->GetName().c_str(), FileSys::FILENAME_LENGTH - 1); | ||
| 200 | entry.type = type; | ||
| 201 | entry.file_size = new_entry->GetSize(); | ||
| 202 | entries.emplace_back(std::move(entry)); | ||
| 203 | } | 200 | } |
| 204 | } | 201 | } |
| 205 | 202 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 116dabedb..4cdf7f613 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -147,7 +147,7 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 147 | } | 147 | } |
| 148 | params.fence_out.id = 0; | 148 | params.fence_out.id = 0; |
| 149 | params.fence_out.value = 0; | 149 | params.fence_out.value = 0; |
| 150 | std::memcpy(output.data(), ¶ms, output.size()); | 150 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); |
| 151 | return 0; | 151 | return 0; |
| 152 | } | 152 | } |
| 153 | 153 | ||
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index e8b30921a..427f4b574 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -16,19 +16,18 @@ | |||
| 16 | #include "core/hle/service/nvdrv/interface.h" | 16 | #include "core/hle/service/nvdrv/interface.h" |
| 17 | #include "core/hle/service/nvdrv/nvdrv.h" | 17 | #include "core/hle/service/nvdrv/nvdrv.h" |
| 18 | #include "core/hle/service/nvdrv/nvmemp.h" | 18 | #include "core/hle/service/nvdrv/nvmemp.h" |
| 19 | #include "core/hle/service/nvflinger/nvflinger.h" | ||
| 19 | 20 | ||
| 20 | namespace Service::Nvidia { | 21 | namespace Service::Nvidia { |
| 21 | 22 | ||
| 22 | std::weak_ptr<Module> nvdrv; | 23 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger) { |
| 23 | |||
| 24 | void InstallInterfaces(SM::ServiceManager& service_manager) { | ||
| 25 | auto module_ = std::make_shared<Module>(); | 24 | auto module_ = std::make_shared<Module>(); |
| 26 | std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager); | 25 | std::make_shared<NVDRV>(module_, "nvdrv")->InstallAsService(service_manager); |
| 27 | std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager); | 26 | std::make_shared<NVDRV>(module_, "nvdrv:a")->InstallAsService(service_manager); |
| 28 | std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager); | 27 | std::make_shared<NVDRV>(module_, "nvdrv:s")->InstallAsService(service_manager); |
| 29 | std::make_shared<NVDRV>(module_, "nvdrv:t")->InstallAsService(service_manager); | 28 | std::make_shared<NVDRV>(module_, "nvdrv:t")->InstallAsService(service_manager); |
| 30 | std::make_shared<NVMEMP>()->InstallAsService(service_manager); | 29 | std::make_shared<NVMEMP>()->InstallAsService(service_manager); |
| 31 | nvdrv = module_; | 30 | nvflinger.SetNVDrvInstance(module_); |
| 32 | } | 31 | } |
| 33 | 32 | ||
| 34 | Module::Module() { | 33 | Module::Module() { |
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h index 184f3c9fc..99eb1128a 100644 --- a/src/core/hle/service/nvdrv/nvdrv.h +++ b/src/core/hle/service/nvdrv/nvdrv.h | |||
| @@ -10,6 +10,10 @@ | |||
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/service/service.h" | 11 | #include "core/hle/service/service.h" |
| 12 | 12 | ||
| 13 | namespace Service::NVFlinger { | ||
| 14 | class NVFlinger; | ||
| 15 | } | ||
| 16 | |||
| 13 | namespace Service::Nvidia { | 17 | namespace Service::Nvidia { |
| 14 | 18 | ||
| 15 | namespace Devices { | 19 | namespace Devices { |
| @@ -56,8 +60,6 @@ private: | |||
| 56 | }; | 60 | }; |
| 57 | 61 | ||
| 58 | /// Registers all NVDRV services with the specified service manager. | 62 | /// Registers all NVDRV services with the specified service manager. |
| 59 | void InstallInterfaces(SM::ServiceManager& service_manager); | 63 | void InstallInterfaces(SM::ServiceManager& service_manager, NVFlinger::NVFlinger& nvflinger); |
| 60 | |||
| 61 | extern std::weak_ptr<Module> nvdrv; | ||
| 62 | 64 | ||
| 63 | } // namespace Service::Nvidia | 65 | } // namespace Service::Nvidia |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index adf180509..ef5713a71 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -16,7 +16,7 @@ BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { | |||
| 16 | Kernel::Event::Create(Kernel::ResetType::Sticky, "BufferQueue NativeHandle"); | 16 | Kernel::Event::Create(Kernel::ResetType::Sticky, "BufferQueue NativeHandle"); |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | void BufferQueue::SetPreallocatedBuffer(u32 slot, IGBPBuffer& igbp_buffer) { | 19 | void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { |
| 20 | Buffer buffer{}; | 20 | Buffer buffer{}; |
| 21 | buffer.slot = slot; | 21 | buffer.slot = slot; |
| 22 | buffer.igbp_buffer = igbp_buffer; | 22 | buffer.igbp_buffer = igbp_buffer; |
diff --git a/src/core/hle/service/nvflinger/buffer_queue.h b/src/core/hle/service/nvflinger/buffer_queue.h index 004170538..f86e1056c 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.h +++ b/src/core/hle/service/nvflinger/buffer_queue.h | |||
| @@ -72,7 +72,7 @@ public: | |||
| 72 | MathUtil::Rectangle<int> crop_rect; | 72 | MathUtil::Rectangle<int> crop_rect; |
| 73 | }; | 73 | }; |
| 74 | 74 | ||
| 75 | void SetPreallocatedBuffer(u32 slot, IGBPBuffer& buffer); | 75 | void SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer); |
| 76 | boost::optional<u32> DequeueBuffer(u32 width, u32 height); | 76 | boost::optional<u32> DequeueBuffer(u32 width, u32 height); |
| 77 | const IGBPBuffer& RequestBuffer(u32 slot) const; | 77 | const IGBPBuffer& RequestBuffer(u32 slot) const; |
| 78 | void QueueBuffer(u32 slot, BufferTransformFlags transform, | 78 | void QueueBuffer(u32 slot, BufferTransformFlags transform, |
diff --git a/src/core/hle/service/nvflinger/nvflinger.cpp b/src/core/hle/service/nvflinger/nvflinger.cpp index 570aa8493..a26a5f812 100644 --- a/src/core/hle/service/nvflinger/nvflinger.cpp +++ b/src/core/hle/service/nvflinger/nvflinger.cpp | |||
| @@ -46,6 +46,10 @@ NVFlinger::~NVFlinger() { | |||
| 46 | CoreTiming::UnscheduleEvent(composition_event, 0); | 46 | CoreTiming::UnscheduleEvent(composition_event, 0); |
| 47 | } | 47 | } |
| 48 | 48 | ||
| 49 | void NVFlinger::SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance) { | ||
| 50 | nvdrv = std::move(instance); | ||
| 51 | } | ||
| 52 | |||
| 49 | u64 NVFlinger::OpenDisplay(std::string_view name) { | 53 | u64 NVFlinger::OpenDisplay(std::string_view name) { |
| 50 | LOG_WARNING(Service, "Opening display {}", name); | 54 | LOG_WARNING(Service, "Opening display {}", name); |
| 51 | 55 | ||
| @@ -141,9 +145,6 @@ void NVFlinger::Compose() { | |||
| 141 | auto& igbp_buffer = buffer->igbp_buffer; | 145 | auto& igbp_buffer = buffer->igbp_buffer; |
| 142 | 146 | ||
| 143 | // Now send the buffer to the GPU for drawing. | 147 | // Now send the buffer to the GPU for drawing. |
| 144 | auto nvdrv = Nvidia::nvdrv.lock(); | ||
| 145 | ASSERT(nvdrv); | ||
| 146 | |||
| 147 | // TODO(Subv): Support more than just disp0. The display device selection is probably based | 148 | // TODO(Subv): Support more than just disp0. The display device selection is probably based |
| 148 | // on which display we're drawing (Default, Internal, External, etc) | 149 | // on which display we're drawing (Default, Internal, External, etc) |
| 149 | auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); | 150 | auto nvdisp = nvdrv->GetDevice<Nvidia::Devices::nvdisp_disp0>("/dev/nvdisp_disp0"); |
diff --git a/src/core/hle/service/nvflinger/nvflinger.h b/src/core/hle/service/nvflinger/nvflinger.h index 5374df175..f7112949f 100644 --- a/src/core/hle/service/nvflinger/nvflinger.h +++ b/src/core/hle/service/nvflinger/nvflinger.h | |||
| @@ -16,6 +16,10 @@ namespace CoreTiming { | |||
| 16 | struct EventType; | 16 | struct EventType; |
| 17 | } | 17 | } |
| 18 | 18 | ||
| 19 | namespace Service::Nvidia { | ||
| 20 | class Module; | ||
| 21 | } | ||
| 22 | |||
| 19 | namespace Service::NVFlinger { | 23 | namespace Service::NVFlinger { |
| 20 | 24 | ||
| 21 | class BufferQueue; | 25 | class BufferQueue; |
| @@ -44,6 +48,9 @@ public: | |||
| 44 | NVFlinger(); | 48 | NVFlinger(); |
| 45 | ~NVFlinger(); | 49 | ~NVFlinger(); |
| 46 | 50 | ||
| 51 | /// Sets the NVDrv module instance to use to send buffers to the GPU. | ||
| 52 | void SetNVDrvInstance(std::shared_ptr<Nvidia::Module> instance); | ||
| 53 | |||
| 47 | /// Opens the specified display and returns the id. | 54 | /// Opens the specified display and returns the id. |
| 48 | u64 OpenDisplay(std::string_view name); | 55 | u64 OpenDisplay(std::string_view name); |
| 49 | 56 | ||
| @@ -70,6 +77,8 @@ private: | |||
| 70 | /// Returns the layer identified by the specified id in the desired display. | 77 | /// Returns the layer identified by the specified id in the desired display. |
| 71 | Layer& GetLayer(u64 display_id, u64 layer_id); | 78 | Layer& GetLayer(u64 display_id, u64 layer_id); |
| 72 | 79 | ||
| 80 | std::shared_ptr<Nvidia::Module> nvdrv; | ||
| 81 | |||
| 73 | std::vector<Display> displays; | 82 | std::vector<Display> displays; |
| 74 | std::vector<std::shared_ptr<BufferQueue>> buffer_queues; | 83 | std::vector<std::shared_ptr<BufferQueue>> buffer_queues; |
| 75 | 84 | ||
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp index 889cdd41a..11951adaf 100644 --- a/src/core/hle/service/service.cpp +++ b/src/core/hle/service/service.cpp | |||
| @@ -198,7 +198,7 @@ void AddNamedPort(std::string name, SharedPtr<ClientPort> port) { | |||
| 198 | } | 198 | } |
| 199 | 199 | ||
| 200 | /// Initialize ServiceManager | 200 | /// Initialize ServiceManager |
| 201 | void Init(std::shared_ptr<SM::ServiceManager>& sm) { | 201 | void Init(std::shared_ptr<SM::ServiceManager>& sm, const FileSys::VirtualFilesystem& rfs) { |
| 202 | // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it | 202 | // NVFlinger needs to be accessed by several services like Vi and AppletOE so we instantiate it |
| 203 | // here and pass it into the respective InstallInterfaces functions. | 203 | // here and pass it into the respective InstallInterfaces functions. |
| 204 | auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(); | 204 | auto nv_flinger = std::make_shared<NVFlinger::NVFlinger>(); |
| @@ -221,7 +221,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) { | |||
| 221 | EUPLD::InstallInterfaces(*sm); | 221 | EUPLD::InstallInterfaces(*sm); |
| 222 | Fatal::InstallInterfaces(*sm); | 222 | Fatal::InstallInterfaces(*sm); |
| 223 | FGM::InstallInterfaces(*sm); | 223 | FGM::InstallInterfaces(*sm); |
| 224 | FileSystem::InstallInterfaces(*sm); | 224 | FileSystem::InstallInterfaces(*sm, rfs); |
| 225 | Friend::InstallInterfaces(*sm); | 225 | Friend::InstallInterfaces(*sm); |
| 226 | GRC::InstallInterfaces(*sm); | 226 | GRC::InstallInterfaces(*sm); |
| 227 | HID::InstallInterfaces(*sm); | 227 | HID::InstallInterfaces(*sm); |
| @@ -238,7 +238,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm) { | |||
| 238 | NIFM::InstallInterfaces(*sm); | 238 | NIFM::InstallInterfaces(*sm); |
| 239 | NIM::InstallInterfaces(*sm); | 239 | NIM::InstallInterfaces(*sm); |
| 240 | NS::InstallInterfaces(*sm); | 240 | NS::InstallInterfaces(*sm); |
| 241 | Nvidia::InstallInterfaces(*sm); | 241 | Nvidia::InstallInterfaces(*sm, *nv_flinger); |
| 242 | PCIe::InstallInterfaces(*sm); | 242 | PCIe::InstallInterfaces(*sm); |
| 243 | PCTL::InstallInterfaces(*sm); | 243 | PCTL::InstallInterfaces(*sm); |
| 244 | PCV::InstallInterfaces(*sm); | 244 | PCV::InstallInterfaces(*sm); |
diff --git a/src/core/hle/service/service.h b/src/core/hle/service/service.h index 046c5e18d..8a294c0f2 100644 --- a/src/core/hle/service/service.h +++ b/src/core/hle/service/service.h | |||
| @@ -22,6 +22,10 @@ class ServerSession; | |||
| 22 | class HLERequestContext; | 22 | class HLERequestContext; |
| 23 | } // namespace Kernel | 23 | } // namespace Kernel |
| 24 | 24 | ||
| 25 | namespace FileSys { | ||
| 26 | struct VfsFilesystem; | ||
| 27 | } | ||
| 28 | |||
| 25 | namespace Service { | 29 | namespace Service { |
| 26 | 30 | ||
| 27 | namespace SM { | 31 | namespace SM { |
| @@ -177,7 +181,8 @@ private: | |||
| 177 | }; | 181 | }; |
| 178 | 182 | ||
| 179 | /// Initialize ServiceManager | 183 | /// Initialize ServiceManager |
| 180 | void Init(std::shared_ptr<SM::ServiceManager>& sm); | 184 | void Init(std::shared_ptr<SM::ServiceManager>& sm, |
| 185 | const std::shared_ptr<FileSys::VfsFilesystem>& vfs); | ||
| 181 | 186 | ||
| 182 | /// Shutdown ServiceManager | 187 | /// Shutdown ServiceManager |
| 183 | void Shutdown(); | 188 | void Shutdown(); |
diff --git a/src/core/loader/deconstructed_rom_directory.cpp b/src/core/loader/deconstructed_rom_directory.cpp index 9a8cdd0ff..915d525b0 100644 --- a/src/core/loader/deconstructed_rom_directory.cpp +++ b/src/core/loader/deconstructed_rom_directory.cpp | |||
| @@ -7,6 +7,7 @@ | |||
| 7 | #include "common/file_util.h" | 7 | #include "common/file_util.h" |
| 8 | #include "common/logging/log.h" | 8 | #include "common/logging/log.h" |
| 9 | #include "core/file_sys/content_archive.h" | 9 | #include "core/file_sys/content_archive.h" |
| 10 | #include "core/file_sys/control_metadata.h" | ||
| 10 | #include "core/gdbstub/gdbstub.h" | 11 | #include "core/gdbstub/gdbstub.h" |
| 11 | #include "core/hle/kernel/process.h" | 12 | #include "core/hle/kernel/process.h" |
| 12 | #include "core/hle/kernel/resource_limit.h" | 13 | #include "core/hle/kernel/resource_limit.h" |
| @@ -17,8 +18,50 @@ | |||
| 17 | 18 | ||
| 18 | namespace Loader { | 19 | namespace Loader { |
| 19 | 20 | ||
| 20 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file) | 21 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory(FileSys::VirtualFile file_) |
| 21 | : AppLoader(std::move(file)) {} | 22 | : AppLoader(std::move(file_)) { |
| 23 | const auto dir = file->GetContainingDirectory(); | ||
| 24 | |||
| 25 | // Icon | ||
| 26 | FileSys::VirtualFile icon_file = nullptr; | ||
| 27 | for (const auto& language : FileSys::LANGUAGE_NAMES) { | ||
| 28 | icon_file = dir->GetFile("icon_" + std::string(language) + ".dat"); | ||
| 29 | if (icon_file != nullptr) { | ||
| 30 | icon_data = icon_file->ReadAllBytes(); | ||
| 31 | break; | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | if (icon_data.empty()) { | ||
| 36 | // Any png, jpeg, or bmp file | ||
| 37 | const auto& files = dir->GetFiles(); | ||
| 38 | const auto icon_iter = | ||
| 39 | std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { | ||
| 40 | return file->GetExtension() == "png" || file->GetExtension() == "jpg" || | ||
| 41 | file->GetExtension() == "bmp" || file->GetExtension() == "jpeg"; | ||
| 42 | }); | ||
| 43 | if (icon_iter != files.end()) | ||
| 44 | icon_data = (*icon_iter)->ReadAllBytes(); | ||
| 45 | } | ||
| 46 | |||
| 47 | // Metadata | ||
| 48 | FileSys::VirtualFile nacp_file = dir->GetFile("control.nacp"); | ||
| 49 | if (nacp_file == nullptr) { | ||
| 50 | const auto& files = dir->GetFiles(); | ||
| 51 | const auto nacp_iter = | ||
| 52 | std::find_if(files.begin(), files.end(), [](const FileSys::VirtualFile& file) { | ||
| 53 | return file->GetExtension() == "nacp"; | ||
| 54 | }); | ||
| 55 | if (nacp_iter != files.end()) | ||
| 56 | nacp_file = *nacp_iter; | ||
| 57 | } | ||
| 58 | |||
| 59 | if (nacp_file != nullptr) { | ||
| 60 | FileSys::NACP nacp(nacp_file); | ||
| 61 | title_id = nacp.GetTitleId(); | ||
| 62 | name = nacp.GetApplicationName(); | ||
| 63 | } | ||
| 64 | } | ||
| 22 | 65 | ||
| 23 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory( | 66 | AppLoader_DeconstructedRomDirectory::AppLoader_DeconstructedRomDirectory( |
| 24 | FileSys::VirtualDir directory) | 67 | FileSys::VirtualDir directory) |
| @@ -105,4 +148,25 @@ ResultStatus AppLoader_DeconstructedRomDirectory::ReadRomFS(FileSys::VirtualFile | |||
| 105 | return ResultStatus::Success; | 148 | return ResultStatus::Success; |
| 106 | } | 149 | } |
| 107 | 150 | ||
| 151 | ResultStatus AppLoader_DeconstructedRomDirectory::ReadIcon(std::vector<u8>& buffer) { | ||
| 152 | if (icon_data.empty()) | ||
| 153 | return ResultStatus::ErrorNotUsed; | ||
| 154 | buffer = icon_data; | ||
| 155 | return ResultStatus::Success; | ||
| 156 | } | ||
| 157 | |||
| 158 | ResultStatus AppLoader_DeconstructedRomDirectory::ReadProgramId(u64& out_program_id) { | ||
| 159 | if (name.empty()) | ||
| 160 | return ResultStatus::ErrorNotUsed; | ||
| 161 | out_program_id = title_id; | ||
| 162 | return ResultStatus::Success; | ||
| 163 | } | ||
| 164 | |||
| 165 | ResultStatus AppLoader_DeconstructedRomDirectory::ReadTitle(std::string& title) { | ||
| 166 | if (name.empty()) | ||
| 167 | return ResultStatus::ErrorNotUsed; | ||
| 168 | title = name; | ||
| 169 | return ResultStatus::Success; | ||
| 170 | } | ||
| 171 | |||
| 108 | } // namespace Loader | 172 | } // namespace Loader |
diff --git a/src/core/loader/deconstructed_rom_directory.h b/src/core/loader/deconstructed_rom_directory.h index 7d5433563..b20804f75 100644 --- a/src/core/loader/deconstructed_rom_directory.h +++ b/src/core/loader/deconstructed_rom_directory.h | |||
| @@ -39,11 +39,18 @@ public: | |||
| 39 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 39 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; |
| 40 | 40 | ||
| 41 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 41 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 42 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | ||
| 43 | ResultStatus ReadProgramId(u64& out_program_id) override; | ||
| 44 | ResultStatus ReadTitle(std::string& title) override; | ||
| 42 | 45 | ||
| 43 | private: | 46 | private: |
| 44 | FileSys::ProgramMetadata metadata; | 47 | FileSys::ProgramMetadata metadata; |
| 45 | FileSys::VirtualFile romfs; | 48 | FileSys::VirtualFile romfs; |
| 46 | FileSys::VirtualDir dir; | 49 | FileSys::VirtualDir dir; |
| 50 | |||
| 51 | std::vector<u8> icon_data; | ||
| 52 | std::string name; | ||
| 53 | u64 title_id{}; | ||
| 47 | }; | 54 | }; |
| 48 | 55 | ||
| 49 | } // namespace Loader | 56 | } // namespace Loader |
diff --git a/src/core/loader/loader.cpp b/src/core/loader/loader.cpp index 57e6c0365..a288654df 100644 --- a/src/core/loader/loader.cpp +++ b/src/core/loader/loader.cpp | |||
| @@ -43,10 +43,6 @@ FileType IdentifyFile(FileSys::VirtualFile file) { | |||
| 43 | return FileType::Unknown; | 43 | return FileType::Unknown; |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | FileType IdentifyFile(const std::string& file_name) { | ||
| 47 | return IdentifyFile(std::make_shared<FileSys::RealVfsFile>(file_name)); | ||
| 48 | } | ||
| 49 | |||
| 50 | FileType GuessFromFilename(const std::string& name) { | 46 | FileType GuessFromFilename(const std::string& name) { |
| 51 | if (name == "main") | 47 | if (name == "main") |
| 52 | return FileType::DeconstructedRomDirectory; | 48 | return FileType::DeconstructedRomDirectory; |
| @@ -68,7 +64,7 @@ FileType GuessFromFilename(const std::string& name) { | |||
| 68 | return FileType::Unknown; | 64 | return FileType::Unknown; |
| 69 | } | 65 | } |
| 70 | 66 | ||
| 71 | const char* GetFileTypeString(FileType type) { | 67 | std::string GetFileTypeString(FileType type) { |
| 72 | switch (type) { | 68 | switch (type) { |
| 73 | case FileType::ELF: | 69 | case FileType::ELF: |
| 74 | return "ELF"; | 70 | return "ELF"; |
diff --git a/src/core/loader/loader.h b/src/core/loader/loader.h index e69ab85ef..6a9e5a68b 100644 --- a/src/core/loader/loader.h +++ b/src/core/loader/loader.h | |||
| @@ -43,14 +43,6 @@ enum class FileType { | |||
| 43 | FileType IdentifyFile(FileSys::VirtualFile file); | 43 | FileType IdentifyFile(FileSys::VirtualFile file); |
| 44 | 44 | ||
| 45 | /** | 45 | /** |
| 46 | * Identifies the type of a bootable file based on the magic value in its header. | ||
| 47 | * @param file_name path to file | ||
| 48 | * @return FileType of file. Note: this will return FileType::Unknown if it is unable to determine | ||
| 49 | * a filetype, and will never return FileType::Error. | ||
| 50 | */ | ||
| 51 | FileType IdentifyFile(const std::string& file_name); | ||
| 52 | |||
| 53 | /** | ||
| 54 | * Guess the type of a bootable file from its name | 46 | * Guess the type of a bootable file from its name |
| 55 | * @param name String name of bootable file | 47 | * @param name String name of bootable file |
| 56 | * @return FileType of file. Note: this will return FileType::Unknown if it is unable to determine | 48 | * @return FileType of file. Note: this will return FileType::Unknown if it is unable to determine |
| @@ -61,7 +53,7 @@ FileType GuessFromFilename(const std::string& name); | |||
| 61 | /** | 53 | /** |
| 62 | * Convert a FileType into a string which can be displayed to the user. | 54 | * Convert a FileType into a string which can be displayed to the user. |
| 63 | */ | 55 | */ |
| 64 | const char* GetFileTypeString(FileType type); | 56 | std::string GetFileTypeString(FileType type); |
| 65 | 57 | ||
| 66 | /// Return type for functions in Loader namespace | 58 | /// Return type for functions in Loader namespace |
| 67 | enum class ResultStatus { | 59 | enum class ResultStatus { |
diff --git a/src/core/loader/nca.cpp b/src/core/loader/nca.cpp index dbc67c0b5..46f5cd393 100644 --- a/src/core/loader/nca.cpp +++ b/src/core/loader/nca.cpp | |||
| @@ -77,8 +77,8 @@ ResultStatus AppLoader_NCA::ReadRomFS(FileSys::VirtualFile& dir) { | |||
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { | 79 | ResultStatus AppLoader_NCA::ReadProgramId(u64& out_program_id) { |
| 80 | if (nca == nullptr) | 80 | if (nca == nullptr || nca->GetStatus() != ResultStatus::Success) |
| 81 | return ResultStatus::ErrorNotLoaded; | 81 | return ResultStatus::ErrorInvalidFormat; |
| 82 | out_program_id = nca->GetTitleId(); | 82 | out_program_id = nca->GetTitleId(); |
| 83 | return ResultStatus::Success; | 83 | return ResultStatus::Success; |
| 84 | } | 84 | } |
diff --git a/src/core/loader/nca.h b/src/core/loader/nca.h index 0fd2d0417..7f7d8ea0b 100644 --- a/src/core/loader/nca.h +++ b/src/core/loader/nca.h | |||
| @@ -33,7 +33,6 @@ public: | |||
| 33 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; | 33 | ResultStatus Load(Kernel::SharedPtr<Kernel::Process>& process) override; |
| 34 | 34 | ||
| 35 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 35 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 36 | |||
| 37 | ResultStatus ReadProgramId(u64& out_program_id) override; | 36 | ResultStatus ReadProgramId(u64& out_program_id) override; |
| 38 | 37 | ||
| 39 | ~AppLoader_NCA(); | 38 | ~AppLoader_NCA(); |
| @@ -41,6 +40,7 @@ public: | |||
| 41 | private: | 40 | private: |
| 42 | FileSys::ProgramMetadata metadata; | 41 | FileSys::ProgramMetadata metadata; |
| 43 | 42 | ||
| 43 | FileSys::NCAHeader header; | ||
| 44 | std::unique_ptr<FileSys::NCA> nca; | 44 | std::unique_ptr<FileSys::NCA> nca; |
| 45 | std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader; | 45 | std::unique_ptr<AppLoader_DeconstructedRomDirectory> directory_loader; |
| 46 | }; | 46 | }; |
diff --git a/src/core/loader/xci.cpp b/src/core/loader/xci.cpp index eb4dee2c2..d3fe24419 100644 --- a/src/core/loader/xci.cpp +++ b/src/core/loader/xci.cpp | |||
| @@ -26,7 +26,25 @@ namespace Loader { | |||
| 26 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) | 26 | AppLoader_XCI::AppLoader_XCI(FileSys::VirtualFile file) |
| 27 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), | 27 | : AppLoader(file), xci(std::make_unique<FileSys::XCI>(file)), |
| 28 | nca_loader(std::make_unique<AppLoader_NCA>( | 28 | nca_loader(std::make_unique<AppLoader_NCA>( |
| 29 | xci->GetNCAFileByType(FileSys::NCAContentType::Program))) {} | 29 | xci->GetNCAFileByType(FileSys::NCAContentType::Program))) { |
| 30 | if (xci->GetStatus() != ResultStatus::Success) | ||
| 31 | return; | ||
| 32 | const auto control_nca = xci->GetNCAByType(FileSys::NCAContentType::Control); | ||
| 33 | if (control_nca == nullptr || control_nca->GetStatus() != ResultStatus::Success) | ||
| 34 | return; | ||
| 35 | const auto romfs = FileSys::ExtractRomFS(control_nca->GetRomFS()); | ||
| 36 | if (romfs == nullptr) | ||
| 37 | return; | ||
| 38 | for (const auto& language : FileSys::LANGUAGE_NAMES) { | ||
| 39 | icon_file = romfs->GetFile("icon_" + std::string(language) + ".dat"); | ||
| 40 | if (icon_file != nullptr) | ||
| 41 | break; | ||
| 42 | } | ||
| 43 | const auto nacp_raw = romfs->GetFile("control.nacp"); | ||
| 44 | if (nacp_raw == nullptr) | ||
| 45 | return; | ||
| 46 | nacp_file = std::make_shared<FileSys::NACP>(nacp_raw); | ||
| 47 | } | ||
| 30 | 48 | ||
| 31 | AppLoader_XCI::~AppLoader_XCI() = default; | 49 | AppLoader_XCI::~AppLoader_XCI() = default; |
| 32 | 50 | ||
| @@ -71,4 +89,17 @@ ResultStatus AppLoader_XCI::ReadProgramId(u64& out_program_id) { | |||
| 71 | return nca_loader->ReadProgramId(out_program_id); | 89 | return nca_loader->ReadProgramId(out_program_id); |
| 72 | } | 90 | } |
| 73 | 91 | ||
| 92 | ResultStatus AppLoader_XCI::ReadIcon(std::vector<u8>& buffer) { | ||
| 93 | if (icon_file == nullptr) | ||
| 94 | return ResultStatus::ErrorInvalidFormat; | ||
| 95 | buffer = icon_file->ReadAllBytes(); | ||
| 96 | return ResultStatus::Success; | ||
| 97 | } | ||
| 98 | |||
| 99 | ResultStatus AppLoader_XCI::ReadTitle(std::string& title) { | ||
| 100 | if (nacp_file == nullptr) | ||
| 101 | return ResultStatus::ErrorInvalidFormat; | ||
| 102 | title = nacp_file->GetApplicationName(); | ||
| 103 | return ResultStatus::Success; | ||
| 104 | } | ||
| 74 | } // namespace Loader | 105 | } // namespace Loader |
diff --git a/src/core/loader/xci.h b/src/core/loader/xci.h index 0dbcfbdf8..973833050 100644 --- a/src/core/loader/xci.h +++ b/src/core/loader/xci.h | |||
| @@ -33,12 +33,17 @@ public: | |||
| 33 | 33 | ||
| 34 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; | 34 | ResultStatus ReadRomFS(FileSys::VirtualFile& dir) override; |
| 35 | ResultStatus ReadProgramId(u64& out_program_id) override; | 35 | ResultStatus ReadProgramId(u64& out_program_id) override; |
| 36 | ResultStatus ReadIcon(std::vector<u8>& buffer) override; | ||
| 37 | ResultStatus ReadTitle(std::string& title) override; | ||
| 36 | 38 | ||
| 37 | private: | 39 | private: |
| 38 | FileSys::ProgramMetadata metadata; | 40 | FileSys::ProgramMetadata metadata; |
| 39 | 41 | ||
| 40 | std::unique_ptr<FileSys::XCI> xci; | 42 | std::unique_ptr<FileSys::XCI> xci; |
| 41 | std::unique_ptr<AppLoader_NCA> nca_loader; | 43 | std::unique_ptr<AppLoader_NCA> nca_loader; |
| 44 | |||
| 45 | FileSys::VirtualFile icon_file; | ||
| 46 | std::shared_ptr<FileSys::NACP> nacp_file; | ||
| 42 | }; | 47 | }; |
| 43 | 48 | ||
| 44 | } // namespace Loader | 49 | } // namespace Loader |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 5c0ae8009..a46ed4bd7 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -23,12 +23,17 @@ Maxwell3D::Maxwell3D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& | |||
| 23 | : memory_manager(memory_manager), rasterizer{rasterizer}, macro_interpreter(*this) {} | 23 | : memory_manager(memory_manager), rasterizer{rasterizer}, macro_interpreter(*this) {} |
| 24 | 24 | ||
| 25 | void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { | 25 | void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { |
| 26 | auto macro_code = uploaded_macros.find(method); | 26 | // Reset the current macro. |
| 27 | executing_macro = 0; | ||
| 28 | |||
| 27 | // The requested macro must have been uploaded already. | 29 | // The requested macro must have been uploaded already. |
| 28 | ASSERT_MSG(macro_code != uploaded_macros.end(), "Macro %08X was not uploaded", method); | 30 | auto macro_code = uploaded_macros.find(method); |
| 31 | if (macro_code == uploaded_macros.end()) { | ||
| 32 | LOG_ERROR(HW_GPU, "Macro {:04X} was not uploaded", method); | ||
| 33 | return; | ||
| 34 | } | ||
| 29 | 35 | ||
| 30 | // Reset the current macro and execute it. | 36 | // Execute the current macro. |
| 31 | executing_macro = 0; | ||
| 32 | macro_interpreter.Execute(macro_code->second, std::move(parameters)); | 37 | macro_interpreter.Execute(macro_code->second, std::move(parameters)); |
| 33 | } | 38 | } |
| 34 | 39 | ||
| @@ -238,6 +243,8 @@ void Maxwell3D::ProcessCBBind(Regs::ShaderStage stage) { | |||
| 238 | 243 | ||
| 239 | auto& buffer = shader.const_buffers[bind_data.index]; | 244 | auto& buffer = shader.const_buffers[bind_data.index]; |
| 240 | 245 | ||
| 246 | ASSERT(bind_data.index < Regs::MaxConstBuffers); | ||
| 247 | |||
| 241 | buffer.enabled = bind_data.valid.Value() != 0; | 248 | buffer.enabled = bind_data.valid.Value() != 0; |
| 242 | buffer.index = bind_data.index; | 249 | buffer.index = bind_data.index; |
| 243 | buffer.address = regs.const_buffer.BufferAddress(); | 250 | buffer.address = regs.const_buffer.BufferAddress(); |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 4d0ff96a5..0506ac8fe 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -44,7 +44,7 @@ public: | |||
| 44 | static constexpr size_t MaxShaderProgram = 6; | 44 | static constexpr size_t MaxShaderProgram = 6; |
| 45 | static constexpr size_t MaxShaderStage = 5; | 45 | static constexpr size_t MaxShaderStage = 5; |
| 46 | // Maximum number of const buffers per shader stage. | 46 | // Maximum number of const buffers per shader stage. |
| 47 | static constexpr size_t MaxConstBuffers = 16; | 47 | static constexpr size_t MaxConstBuffers = 18; |
| 48 | 48 | ||
| 49 | enum class QueryMode : u32 { | 49 | enum class QueryMode : u32 { |
| 50 | Write = 0, | 50 | Write = 0, |
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index c7e3fb4b1..3d4557b7e 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -78,6 +78,8 @@ union Attribute { | |||
| 78 | // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval | 78 | // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval |
| 79 | // shader. | 79 | // shader. |
| 80 | TessCoordInstanceIDVertexID = 47, | 80 | TessCoordInstanceIDVertexID = 47, |
| 81 | // TODO(bunnei): Figure out what this is used for. Super Mario Odyssey uses this. | ||
| 82 | Unknown_63 = 63, | ||
| 81 | }; | 83 | }; |
| 82 | 84 | ||
| 83 | union { | 85 | union { |
| @@ -254,20 +256,15 @@ union Instruction { | |||
| 254 | BitField<56, 1, u64> invert_b; | 256 | BitField<56, 1, u64> invert_b; |
| 255 | } lop32i; | 257 | } lop32i; |
| 256 | 258 | ||
| 257 | float GetImm20_19() const { | 259 | u32 GetImm20_19() const { |
| 258 | float result{}; | ||
| 259 | u32 imm{static_cast<u32>(imm20_19)}; | 260 | u32 imm{static_cast<u32>(imm20_19)}; |
| 260 | imm <<= 12; | 261 | imm <<= 12; |
| 261 | imm |= negate_imm ? 0x80000000 : 0; | 262 | imm |= negate_imm ? 0x80000000 : 0; |
| 262 | std::memcpy(&result, &imm, sizeof(imm)); | 263 | return imm; |
| 263 | return result; | ||
| 264 | } | 264 | } |
| 265 | 265 | ||
| 266 | float GetImm20_32() const { | 266 | u32 GetImm20_32() const { |
| 267 | float result{}; | 267 | return static_cast<u32>(imm20_32); |
| 268 | s32 imm{static_cast<s32>(imm20_32)}; | ||
| 269 | std::memcpy(&result, &imm, sizeof(imm)); | ||
| 270 | return result; | ||
| 271 | } | 268 | } |
| 272 | 269 | ||
| 273 | s32 GetSignedImm20_20() const { | 270 | s32 GetSignedImm20_20() const { |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index b2a83ce0b..4ff4d71c5 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -42,6 +42,7 @@ u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { | |||
| 42 | case RenderTargetFormat::RGB10_A2_UNORM: | 42 | case RenderTargetFormat::RGB10_A2_UNORM: |
| 43 | case RenderTargetFormat::BGRA8_UNORM: | 43 | case RenderTargetFormat::BGRA8_UNORM: |
| 44 | case RenderTargetFormat::R32_FLOAT: | 44 | case RenderTargetFormat::R32_FLOAT: |
| 45 | case RenderTargetFormat::R11G11B10_FLOAT: | ||
| 45 | return 4; | 46 | return 4; |
| 46 | default: | 47 | default: |
| 47 | UNIMPLEMENTED_MSG("Unimplemented render target format {}", static_cast<u32>(format)); | 48 | UNIMPLEMENTED_MSG("Unimplemented render target format {}", static_cast<u32>(format)); |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 440505c9d..874eddd78 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -34,6 +34,7 @@ enum class RenderTargetFormat : u32 { | |||
| 34 | RG16_FLOAT = 0xDE, | 34 | RG16_FLOAT = 0xDE, |
| 35 | R11G11B10_FLOAT = 0xE0, | 35 | R11G11B10_FLOAT = 0xE0, |
| 36 | R32_FLOAT = 0xE5, | 36 | R32_FLOAT = 0xE5, |
| 37 | B5G6R5_UNORM = 0xE8, | ||
| 37 | R16_FLOAT = 0xF2, | 38 | R16_FLOAT = 0xF2, |
| 38 | R8_UNORM = 0xF3, | 39 | R8_UNORM = 0xF3, |
| 39 | }; | 40 | }; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index c2a931469..8360feb5d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -161,7 +161,7 @@ std::pair<u8*, GLintptr> RasterizerOpenGL::SetupVertexArrays(u8* array_ptr, | |||
| 161 | // assume every shader uses them all. | 161 | // assume every shader uses them all. |
| 162 | for (unsigned index = 0; index < 16; ++index) { | 162 | for (unsigned index = 0; index < 16; ++index) { |
| 163 | auto& attrib = regs.vertex_attrib_format[index]; | 163 | auto& attrib = regs.vertex_attrib_format[index]; |
| 164 | LOG_DEBUG(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}", | 164 | LOG_TRACE(HW_GPU, "vertex attrib {}, count={}, size={}, type={}, offset={}, normalize={}", |
| 165 | index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(), | 165 | index, attrib.ComponentCount(), attrib.SizeString(), attrib.TypeString(), |
| 166 | attrib.offset.Value(), attrib.IsNormalized()); | 166 | attrib.offset.Value(), attrib.IsNormalized()); |
| 167 | 167 | ||
| @@ -324,11 +324,14 @@ std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_c | |||
| 324 | bool using_depth_fb) { | 324 | bool using_depth_fb) { |
| 325 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 325 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 326 | 326 | ||
| 327 | if (regs.rt[0].format == Tegra::RenderTargetFormat::NONE) { | ||
| 328 | LOG_ERROR(HW_GPU, "RenderTargetFormat is not configured"); | ||
| 329 | using_color_fb = false; | ||
| 330 | } | ||
| 331 | |||
| 327 | // TODO(bunnei): Implement this | 332 | // TODO(bunnei): Implement this |
| 328 | const bool has_stencil = false; | 333 | const bool has_stencil = false; |
| 329 | 334 | ||
| 330 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; | ||
| 331 | |||
| 332 | const bool write_color_fb = | 335 | const bool write_color_fb = |
| 333 | state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE || | 336 | state.color_mask.red_enabled == GL_TRUE || state.color_mask.green_enabled == GL_TRUE || |
| 334 | state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE; | 337 | state.color_mask.blue_enabled == GL_TRUE || state.color_mask.alpha_enabled == GL_TRUE; |
| @@ -341,9 +344,10 @@ std::pair<Surface, Surface> RasterizerOpenGL::ConfigureFramebuffers(bool using_c | |||
| 341 | Surface depth_surface; | 344 | Surface depth_surface; |
| 342 | MathUtil::Rectangle<u32> surfaces_rect; | 345 | MathUtil::Rectangle<u32> surfaces_rect; |
| 343 | std::tie(color_surface, depth_surface, surfaces_rect) = | 346 | std::tie(color_surface, depth_surface, surfaces_rect) = |
| 344 | res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb, viewport_rect); | 347 | res_cache.GetFramebufferSurfaces(using_color_fb, using_depth_fb); |
| 345 | 348 | ||
| 346 | MathUtil::Rectangle<u32> draw_rect{ | 349 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[0].GetRect()}; |
| 350 | const MathUtil::Rectangle<u32> draw_rect{ | ||
| 347 | static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left, | 351 | static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.left) + viewport_rect.left, |
| 348 | surfaces_rect.left, surfaces_rect.right)), // Left | 352 | surfaces_rect.left, surfaces_rect.right)), // Left |
| 349 | static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top, | 353 | static_cast<u32>(std::clamp<s32>(static_cast<s32>(surfaces_rect.bottom) + viewport_rect.top, |
| @@ -659,7 +663,10 @@ u32 RasterizerOpenGL::SetupConstBuffers(Maxwell::ShaderStage stage, GLuint progr | |||
| 659 | auto& buffer_draw_state = | 663 | auto& buffer_draw_state = |
| 660 | state.draw.const_buffers[static_cast<size_t>(stage)][used_buffer.GetIndex()]; | 664 | state.draw.const_buffers[static_cast<size_t>(stage)][used_buffer.GetIndex()]; |
| 661 | 665 | ||
| 662 | ASSERT_MSG(buffer.enabled, "Attempted to upload disabled constbuffer"); | 666 | if (!buffer.enabled) { |
| 667 | continue; | ||
| 668 | } | ||
| 669 | |||
| 663 | buffer_draw_state.enabled = true; | 670 | buffer_draw_state.enabled = true; |
| 664 | buffer_draw_state.bindpoint = current_bindpoint + bindpoint; | 671 | buffer_draw_state.bindpoint = current_bindpoint + bindpoint; |
| 665 | 672 | ||
| @@ -804,9 +811,7 @@ void RasterizerOpenGL::SyncClipCoef() { | |||
| 804 | void RasterizerOpenGL::SyncCullMode() { | 811 | void RasterizerOpenGL::SyncCullMode() { |
| 805 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 812 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 806 | 813 | ||
| 807 | // TODO(bunnei): Enable the below once more things work - until then, this may hide regressions | 814 | state.cull.enabled = regs.cull.enabled != 0; |
| 808 | // state.cull.enabled = regs.cull.enabled != 0; | ||
| 809 | state.cull.enabled = false; | ||
| 810 | 815 | ||
| 811 | if (state.cull.enabled) { | 816 | if (state.cull.enabled) { |
| 812 | state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face); | 817 | state.cull.front_face = MaxwellToGL::FrontFace(regs.cull.front_face); |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 257aa9571..9fb734b77 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -109,6 +109,9 @@ static constexpr std::array<FormatTuple, SurfaceParams::MaxPixelFormat> tex_form | |||
| 109 | {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | 109 | {GL_COMPRESSED_RGBA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, |
| 110 | true}, // DXT45 | 110 | true}, // DXT45 |
| 111 | {GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, true}, // DXN1 | 111 | {GL_COMPRESSED_RED_RGTC1, GL_RED, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, true}, // DXN1 |
| 112 | {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | ||
| 113 | true}, // DXN2UNORM | ||
| 114 | {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM | ||
| 112 | {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | 115 | {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, |
| 113 | true}, // BC7U | 116 | true}, // BC7U |
| 114 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4 | 117 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4 |
| @@ -180,36 +183,49 @@ MathUtil::Rectangle<u32> SurfaceParams::GetRect() const { | |||
| 180 | return {0, actual_height, width, 0}; | 183 | return {0, actual_height, width, 0}; |
| 181 | } | 184 | } |
| 182 | 185 | ||
| 186 | /// Returns true if the specified PixelFormat is a BCn format, e.g. DXT or DXN | ||
| 187 | static bool IsFormatBCn(PixelFormat format) { | ||
| 188 | switch (format) { | ||
| 189 | case PixelFormat::DXT1: | ||
| 190 | case PixelFormat::DXT23: | ||
| 191 | case PixelFormat::DXT45: | ||
| 192 | case PixelFormat::DXN1: | ||
| 193 | case PixelFormat::DXN2SNORM: | ||
| 194 | case PixelFormat::DXN2UNORM: | ||
| 195 | case PixelFormat::BC7U: | ||
| 196 | return true; | ||
| 197 | } | ||
| 198 | return false; | ||
| 199 | } | ||
| 200 | |||
| 183 | template <bool morton_to_gl, PixelFormat format> | 201 | template <bool morton_to_gl, PixelFormat format> |
| 184 | void MortonCopy(u32 stride, u32 block_height, u32 height, u8* gl_buffer, Tegra::GPUVAddr addr) { | 202 | void MortonCopy(u32 stride, u32 block_height, u32 height, std::vector<u8>& gl_buffer, |
| 203 | Tegra::GPUVAddr addr) { | ||
| 185 | constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT; | 204 | constexpr u32 bytes_per_pixel = SurfaceParams::GetFormatBpp(format) / CHAR_BIT; |
| 186 | constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); | 205 | constexpr u32 gl_bytes_per_pixel = CachedSurface::GetGLBytesPerPixel(format); |
| 187 | const auto& gpu = Core::System::GetInstance().GPU(); | 206 | const auto& gpu = Core::System::GetInstance().GPU(); |
| 188 | 207 | ||
| 189 | if (morton_to_gl) { | 208 | if (morton_to_gl) { |
| 190 | if (SurfaceParams::GetFormatType(format) == SurfaceType::ColorTexture) { | 209 | // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual |
| 191 | auto data = Tegra::Texture::UnswizzleTexture( | 210 | // pixel values. |
| 192 | *gpu.memory_manager->GpuToCpuAddress(addr), | 211 | const u32 tile_size{IsFormatBCn(format) ? 4U : 1U}; |
| 193 | SurfaceParams::TextureFormatFromPixelFormat(format), stride, height, block_height); | 212 | const std::vector<u8> data = |
| 194 | std::memcpy(gl_buffer, data.data(), data.size()); | 213 | Tegra::Texture::UnswizzleTexture(*gpu.memory_manager->GpuToCpuAddress(addr), tile_size, |
| 195 | } else { | 214 | bytes_per_pixel, stride, height, block_height); |
| 196 | auto data = Tegra::Texture::UnswizzleDepthTexture( | 215 | const size_t size_to_copy{std::min(gl_buffer.size(), data.size())}; |
| 197 | *gpu.memory_manager->GpuToCpuAddress(addr), | 216 | gl_buffer.assign(data.begin(), data.begin() + size_to_copy); |
| 198 | SurfaceParams::DepthFormatFromPixelFormat(format), stride, height, block_height); | ||
| 199 | std::memcpy(gl_buffer, data.data(), data.size()); | ||
| 200 | } | ||
| 201 | } else { | 217 | } else { |
| 202 | // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should | 218 | // TODO(bunnei): Assumes the default rendering GOB size of 16 (128 lines). We should |
| 203 | // check the configuration for this and perform more generic un/swizzle | 219 | // check the configuration for this and perform more generic un/swizzle |
| 204 | LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); | 220 | LOG_WARNING(Render_OpenGL, "need to use correct swizzle/GOB parameters!"); |
| 205 | VideoCore::MortonCopyPixels128( | 221 | VideoCore::MortonCopyPixels128( |
| 206 | stride, height, bytes_per_pixel, gl_bytes_per_pixel, | 222 | stride, height, bytes_per_pixel, gl_bytes_per_pixel, |
| 207 | Memory::GetPointer(*gpu.memory_manager->GpuToCpuAddress(addr)), gl_buffer, | 223 | Memory::GetPointer(*gpu.memory_manager->GpuToCpuAddress(addr)), gl_buffer.data(), |
| 208 | morton_to_gl); | 224 | morton_to_gl); |
| 209 | } | 225 | } |
| 210 | } | 226 | } |
| 211 | 227 | ||
| 212 | static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr), | 228 | static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr), |
| 213 | SurfaceParams::MaxPixelFormat> | 229 | SurfaceParams::MaxPixelFormat> |
| 214 | morton_to_gl_fns = { | 230 | morton_to_gl_fns = { |
| 215 | MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>, | 231 | MortonCopy<true, PixelFormat::ABGR8>, MortonCopy<true, PixelFormat::B5G6R5>, |
| @@ -218,6 +234,7 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr), | |||
| 218 | MortonCopy<true, PixelFormat::R11FG11FB10F>, MortonCopy<true, PixelFormat::RGBA32UI>, | 234 | MortonCopy<true, PixelFormat::R11FG11FB10F>, MortonCopy<true, PixelFormat::RGBA32UI>, |
| 219 | MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>, | 235 | MortonCopy<true, PixelFormat::DXT1>, MortonCopy<true, PixelFormat::DXT23>, |
| 220 | MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>, | 236 | MortonCopy<true, PixelFormat::DXT45>, MortonCopy<true, PixelFormat::DXN1>, |
| 237 | MortonCopy<true, PixelFormat::DXN2UNORM>, MortonCopy<true, PixelFormat::DXN2SNORM>, | ||
| 221 | MortonCopy<true, PixelFormat::BC7U>, MortonCopy<true, PixelFormat::ASTC_2D_4X4>, | 238 | MortonCopy<true, PixelFormat::BC7U>, MortonCopy<true, PixelFormat::ASTC_2D_4X4>, |
| 222 | MortonCopy<true, PixelFormat::G8R8>, MortonCopy<true, PixelFormat::BGRA8>, | 239 | MortonCopy<true, PixelFormat::G8R8>, MortonCopy<true, PixelFormat::BGRA8>, |
| 223 | MortonCopy<true, PixelFormat::RGBA32F>, MortonCopy<true, PixelFormat::RG32F>, | 240 | MortonCopy<true, PixelFormat::RGBA32F>, MortonCopy<true, PixelFormat::RG32F>, |
| @@ -231,7 +248,7 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr), | |||
| 231 | MortonCopy<true, PixelFormat::Z32FS8>, | 248 | MortonCopy<true, PixelFormat::Z32FS8>, |
| 232 | }; | 249 | }; |
| 233 | 250 | ||
| 234 | static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr), | 251 | static constexpr std::array<void (*)(u32, u32, u32, std::vector<u8>&, Tegra::GPUVAddr), |
| 235 | SurfaceParams::MaxPixelFormat> | 252 | SurfaceParams::MaxPixelFormat> |
| 236 | gl_to_morton_fns = { | 253 | gl_to_morton_fns = { |
| 237 | MortonCopy<false, PixelFormat::ABGR8>, | 254 | MortonCopy<false, PixelFormat::ABGR8>, |
| @@ -242,7 +259,10 @@ static constexpr std::array<void (*)(u32, u32, u32, u8*, Tegra::GPUVAddr), | |||
| 242 | MortonCopy<false, PixelFormat::RGBA16F>, | 259 | MortonCopy<false, PixelFormat::RGBA16F>, |
| 243 | MortonCopy<false, PixelFormat::R11FG11FB10F>, | 260 | MortonCopy<false, PixelFormat::R11FG11FB10F>, |
| 244 | MortonCopy<false, PixelFormat::RGBA32UI>, | 261 | MortonCopy<false, PixelFormat::RGBA32UI>, |
| 245 | // TODO(Subv): Swizzling DXT1/DXT23/DXT45/DXN1/BC7U/ASTC_2D_4X4 formats is not supported | 262 | // TODO(Subv): Swizzling DXT1/DXT23/DXT45/DXN1/DXN2/BC7U/ASTC_2D_4X4 formats is not |
| 263 | // supported | ||
| 264 | nullptr, | ||
| 265 | nullptr, | ||
| 246 | nullptr, | 266 | nullptr, |
| 247 | nullptr, | 267 | nullptr, |
| 248 | nullptr, | 268 | nullptr, |
| @@ -447,22 +467,24 @@ MICROPROFILE_DEFINE(OpenGL_SurfaceLoad, "OpenGL", "Surface Load", MP_RGB(128, 64 | |||
| 447 | void CachedSurface::LoadGLBuffer() { | 467 | void CachedSurface::LoadGLBuffer() { |
| 448 | ASSERT(params.type != SurfaceType::Fill); | 468 | ASSERT(params.type != SurfaceType::Fill); |
| 449 | 469 | ||
| 450 | u8* const texture_src_data = Memory::GetPointer(params.GetCpuAddr()); | 470 | const u8* const texture_src_data = Memory::GetPointer(params.GetCpuAddr()); |
| 451 | 471 | ||
| 452 | ASSERT(texture_src_data); | 472 | ASSERT(texture_src_data); |
| 453 | 473 | ||
| 454 | gl_buffer.resize(params.width * params.height * GetGLBytesPerPixel(params.pixel_format)); | 474 | const u32 bytes_per_pixel = GetGLBytesPerPixel(params.pixel_format); |
| 475 | const u32 copy_size = params.width * params.height * bytes_per_pixel; | ||
| 455 | 476 | ||
| 456 | MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); | 477 | MICROPROFILE_SCOPE(OpenGL_SurfaceLoad); |
| 457 | 478 | ||
| 458 | if (!params.is_tiled) { | 479 | if (params.is_tiled) { |
| 459 | const u32 bytes_per_pixel{params.GetFormatBpp() >> 3}; | 480 | gl_buffer.resize(copy_size); |
| 460 | 481 | ||
| 461 | std::memcpy(gl_buffer.data(), texture_src_data, | ||
| 462 | bytes_per_pixel * params.width * params.height); | ||
| 463 | } else { | ||
| 464 | morton_to_gl_fns[static_cast<size_t>(params.pixel_format)]( | 482 | morton_to_gl_fns[static_cast<size_t>(params.pixel_format)]( |
| 465 | params.width, params.block_height, params.height, gl_buffer.data(), params.addr); | 483 | params.width, params.block_height, params.height, gl_buffer, params.addr); |
| 484 | } else { | ||
| 485 | const u8* const texture_src_data_end = texture_src_data + copy_size; | ||
| 486 | |||
| 487 | gl_buffer.assign(texture_src_data, texture_src_data_end); | ||
| 466 | } | 488 | } |
| 467 | 489 | ||
| 468 | ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer, params.pixel_format, params.width, params.height); | 490 | ConvertFormatAsNeeded_LoadGLBuffer(gl_buffer, params.pixel_format, params.width, params.height); |
| @@ -485,7 +507,7 @@ void CachedSurface::FlushGLBuffer() { | |||
| 485 | std::memcpy(dst_buffer, gl_buffer.data(), params.size_in_bytes); | 507 | std::memcpy(dst_buffer, gl_buffer.data(), params.size_in_bytes); |
| 486 | } else { | 508 | } else { |
| 487 | gl_to_morton_fns[static_cast<size_t>(params.pixel_format)]( | 509 | gl_to_morton_fns[static_cast<size_t>(params.pixel_format)]( |
| 488 | params.width, params.block_height, params.height, gl_buffer.data(), params.addr); | 510 | params.width, params.block_height, params.height, gl_buffer, params.addr); |
| 489 | } | 511 | } |
| 490 | } | 512 | } |
| 491 | 513 | ||
| @@ -600,8 +622,8 @@ Surface RasterizerCacheOpenGL::GetTextureSurface(const Tegra::Texture::FullTextu | |||
| 600 | return GetSurface(SurfaceParams::CreateForTexture(config)); | 622 | return GetSurface(SurfaceParams::CreateForTexture(config)); |
| 601 | } | 623 | } |
| 602 | 624 | ||
| 603 | SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces( | 625 | SurfaceSurfaceRect_Tuple RasterizerCacheOpenGL::GetFramebufferSurfaces(bool using_color_fb, |
| 604 | bool using_color_fb, bool using_depth_fb, const MathUtil::Rectangle<s32>& viewport) { | 626 | bool using_depth_fb) { |
| 605 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 627 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 606 | 628 | ||
| 607 | // TODO(bunnei): This is hard corded to use just the first render buffer | 629 | // TODO(bunnei): This is hard corded to use just the first render buffer |
| @@ -757,10 +779,12 @@ void RasterizerCacheOpenGL::FlushRegion(Tegra::GPUVAddr /*addr*/, size_t /*size* | |||
| 757 | } | 779 | } |
| 758 | 780 | ||
| 759 | void RasterizerCacheOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, size_t size) { | 781 | void RasterizerCacheOpenGL::InvalidateRegion(Tegra::GPUVAddr addr, size_t size) { |
| 760 | for (const auto& pair : surface_cache) { | 782 | for (auto iter = surface_cache.cbegin(); iter != surface_cache.cend();) { |
| 761 | const auto& surface{pair.second}; | 783 | const auto& surface{iter->second}; |
| 762 | const auto& params{surface->GetSurfaceParams()}; | 784 | const auto& params{surface->GetSurfaceParams()}; |
| 763 | 785 | ||
| 786 | ++iter; | ||
| 787 | |||
| 764 | if (params.IsOverlappingRegion(addr, size)) { | 788 | if (params.IsOverlappingRegion(addr, size)) { |
| 765 | UnregisterSurface(surface); | 789 | UnregisterSurface(surface); |
| 766 | } | 790 | } |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 0c6652c7a..829a76dfe 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h | |||
| @@ -35,31 +35,33 @@ struct SurfaceParams { | |||
| 35 | DXT23 = 9, | 35 | DXT23 = 9, |
| 36 | DXT45 = 10, | 36 | DXT45 = 10, |
| 37 | DXN1 = 11, // This is also known as BC4 | 37 | DXN1 = 11, // This is also known as BC4 |
| 38 | BC7U = 12, | 38 | DXN2UNORM = 12, |
| 39 | ASTC_2D_4X4 = 13, | 39 | DXN2SNORM = 13, |
| 40 | G8R8 = 14, | 40 | BC7U = 14, |
| 41 | BGRA8 = 15, | 41 | ASTC_2D_4X4 = 15, |
| 42 | RGBA32F = 16, | 42 | G8R8 = 16, |
| 43 | RG32F = 17, | 43 | BGRA8 = 17, |
| 44 | R32F = 18, | 44 | RGBA32F = 18, |
| 45 | R16F = 19, | 45 | RG32F = 19, |
| 46 | R16UNORM = 20, | 46 | R32F = 20, |
| 47 | RG16 = 21, | 47 | R16F = 21, |
| 48 | RG16F = 22, | 48 | R16UNORM = 22, |
| 49 | RG16UI = 23, | 49 | RG16 = 23, |
| 50 | RG16I = 24, | 50 | RG16F = 24, |
| 51 | RG16S = 25, | 51 | RG16UI = 25, |
| 52 | RGB32F = 26, | 52 | RG16I = 26, |
| 53 | SRGBA8 = 27, | 53 | RG16S = 27, |
| 54 | RGB32F = 28, | ||
| 55 | SRGBA8 = 29, | ||
| 54 | 56 | ||
| 55 | MaxColorFormat, | 57 | MaxColorFormat, |
| 56 | 58 | ||
| 57 | // DepthStencil formats | 59 | // DepthStencil formats |
| 58 | Z24S8 = 28, | 60 | Z24S8 = 30, |
| 59 | S8Z24 = 29, | 61 | S8Z24 = 31, |
| 60 | Z32F = 30, | 62 | Z32F = 32, |
| 61 | Z16 = 31, | 63 | Z16 = 33, |
| 62 | Z32FS8 = 32, | 64 | Z32FS8 = 34, |
| 63 | 65 | ||
| 64 | MaxDepthStencilFormat, | 66 | MaxDepthStencilFormat, |
| 65 | 67 | ||
| @@ -109,6 +111,8 @@ struct SurfaceParams { | |||
| 109 | 4, // DXT23 | 111 | 4, // DXT23 |
| 110 | 4, // DXT45 | 112 | 4, // DXT45 |
| 111 | 4, // DXN1 | 113 | 4, // DXN1 |
| 114 | 4, // DXN2UNORM | ||
| 115 | 4, // DXN2SNORM | ||
| 112 | 4, // BC7U | 116 | 4, // BC7U |
| 113 | 4, // ASTC_2D_4X4 | 117 | 4, // ASTC_2D_4X4 |
| 114 | 1, // G8R8 | 118 | 1, // G8R8 |
| @@ -153,6 +157,8 @@ struct SurfaceParams { | |||
| 153 | 128, // DXT23 | 157 | 128, // DXT23 |
| 154 | 128, // DXT45 | 158 | 128, // DXT45 |
| 155 | 64, // DXN1 | 159 | 64, // DXN1 |
| 160 | 128, // DXN2UNORM | ||
| 161 | 128, // DXN2SNORM | ||
| 156 | 128, // BC7U | 162 | 128, // BC7U |
| 157 | 32, // ASTC_2D_4X4 | 163 | 32, // ASTC_2D_4X4 |
| 158 | 16, // G8R8 | 164 | 16, // G8R8 |
| @@ -221,6 +227,8 @@ struct SurfaceParams { | |||
| 221 | return PixelFormat::RG32F; | 227 | return PixelFormat::RG32F; |
| 222 | case Tegra::RenderTargetFormat::R11G11B10_FLOAT: | 228 | case Tegra::RenderTargetFormat::R11G11B10_FLOAT: |
| 223 | return PixelFormat::R11FG11FB10F; | 229 | return PixelFormat::R11FG11FB10F; |
| 230 | case Tegra::RenderTargetFormat::B5G6R5_UNORM: | ||
| 231 | return PixelFormat::B5G6R5; | ||
| 224 | case Tegra::RenderTargetFormat::RGBA32_UINT: | 232 | case Tegra::RenderTargetFormat::RGBA32_UINT: |
| 225 | return PixelFormat::RGBA32UI; | 233 | return PixelFormat::RGBA32UI; |
| 226 | case Tegra::RenderTargetFormat::R8_UNORM: | 234 | case Tegra::RenderTargetFormat::R8_UNORM: |
| @@ -303,6 +311,16 @@ struct SurfaceParams { | |||
| 303 | return PixelFormat::DXT45; | 311 | return PixelFormat::DXT45; |
| 304 | case Tegra::Texture::TextureFormat::DXN1: | 312 | case Tegra::Texture::TextureFormat::DXN1: |
| 305 | return PixelFormat::DXN1; | 313 | return PixelFormat::DXN1; |
| 314 | case Tegra::Texture::TextureFormat::DXN2: | ||
| 315 | switch (component_type) { | ||
| 316 | case Tegra::Texture::ComponentType::UNORM: | ||
| 317 | return PixelFormat::DXN2UNORM; | ||
| 318 | case Tegra::Texture::ComponentType::SNORM: | ||
| 319 | return PixelFormat::DXN2SNORM; | ||
| 320 | } | ||
| 321 | LOG_CRITICAL(HW_GPU, "Unimplemented component_type={}", | ||
| 322 | static_cast<u32>(component_type)); | ||
| 323 | UNREACHABLE(); | ||
| 306 | case Tegra::Texture::TextureFormat::BC7U: | 324 | case Tegra::Texture::TextureFormat::BC7U: |
| 307 | return PixelFormat::BC7U; | 325 | return PixelFormat::BC7U; |
| 308 | case Tegra::Texture::TextureFormat::ASTC_2D_4X4: | 326 | case Tegra::Texture::TextureFormat::ASTC_2D_4X4: |
| @@ -330,89 +348,6 @@ struct SurfaceParams { | |||
| 330 | } | 348 | } |
| 331 | } | 349 | } |
| 332 | 350 | ||
| 333 | static Tegra::Texture::TextureFormat TextureFormatFromPixelFormat(PixelFormat format) { | ||
| 334 | // TODO(Subv): Properly implement this | ||
| 335 | switch (format) { | ||
| 336 | case PixelFormat::ABGR8: | ||
| 337 | case PixelFormat::SRGBA8: | ||
| 338 | return Tegra::Texture::TextureFormat::A8R8G8B8; | ||
| 339 | case PixelFormat::B5G6R5: | ||
| 340 | return Tegra::Texture::TextureFormat::B5G6R5; | ||
| 341 | case PixelFormat::A2B10G10R10: | ||
| 342 | return Tegra::Texture::TextureFormat::A2B10G10R10; | ||
| 343 | case PixelFormat::A1B5G5R5: | ||
| 344 | return Tegra::Texture::TextureFormat::A1B5G5R5; | ||
| 345 | case PixelFormat::R8: | ||
| 346 | return Tegra::Texture::TextureFormat::R8; | ||
| 347 | case PixelFormat::G8R8: | ||
| 348 | return Tegra::Texture::TextureFormat::G8R8; | ||
| 349 | case PixelFormat::RGBA16F: | ||
| 350 | return Tegra::Texture::TextureFormat::R16_G16_B16_A16; | ||
| 351 | case PixelFormat::R11FG11FB10F: | ||
| 352 | return Tegra::Texture::TextureFormat::BF10GF11RF11; | ||
| 353 | case PixelFormat::RGBA32UI: | ||
| 354 | return Tegra::Texture::TextureFormat::R32_G32_B32_A32; | ||
| 355 | case PixelFormat::DXT1: | ||
| 356 | return Tegra::Texture::TextureFormat::DXT1; | ||
| 357 | case PixelFormat::DXT23: | ||
| 358 | return Tegra::Texture::TextureFormat::DXT23; | ||
| 359 | case PixelFormat::DXT45: | ||
| 360 | return Tegra::Texture::TextureFormat::DXT45; | ||
| 361 | case PixelFormat::DXN1: | ||
| 362 | return Tegra::Texture::TextureFormat::DXN1; | ||
| 363 | case PixelFormat::BC7U: | ||
| 364 | return Tegra::Texture::TextureFormat::BC7U; | ||
| 365 | case PixelFormat::ASTC_2D_4X4: | ||
| 366 | return Tegra::Texture::TextureFormat::ASTC_2D_4X4; | ||
| 367 | case PixelFormat::BGRA8: | ||
| 368 | // TODO(bunnei): This is fine for unswizzling (since we just need the right component | ||
| 369 | // sizes), but could be a bug if we used this function in different ways. | ||
| 370 | return Tegra::Texture::TextureFormat::A8R8G8B8; | ||
| 371 | case PixelFormat::RGBA32F: | ||
| 372 | return Tegra::Texture::TextureFormat::R32_G32_B32_A32; | ||
| 373 | case PixelFormat::RGB32F: | ||
| 374 | return Tegra::Texture::TextureFormat::R32_G32_B32; | ||
| 375 | case PixelFormat::RG32F: | ||
| 376 | return Tegra::Texture::TextureFormat::R32_G32; | ||
| 377 | case PixelFormat::R32F: | ||
| 378 | return Tegra::Texture::TextureFormat::R32; | ||
| 379 | case PixelFormat::R16F: | ||
| 380 | case PixelFormat::R16UNORM: | ||
| 381 | return Tegra::Texture::TextureFormat::R16; | ||
| 382 | case PixelFormat::Z32F: | ||
| 383 | return Tegra::Texture::TextureFormat::ZF32; | ||
| 384 | case PixelFormat::Z24S8: | ||
| 385 | return Tegra::Texture::TextureFormat::Z24S8; | ||
| 386 | case PixelFormat::RG16F: | ||
| 387 | case PixelFormat::RG16: | ||
| 388 | case PixelFormat::RG16UI: | ||
| 389 | case PixelFormat::RG16I: | ||
| 390 | case PixelFormat::RG16S: | ||
| 391 | return Tegra::Texture::TextureFormat::R16_G16; | ||
| 392 | default: | ||
| 393 | LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); | ||
| 394 | UNREACHABLE(); | ||
| 395 | } | ||
| 396 | } | ||
| 397 | |||
| 398 | static Tegra::DepthFormat DepthFormatFromPixelFormat(PixelFormat format) { | ||
| 399 | switch (format) { | ||
| 400 | case PixelFormat::S8Z24: | ||
| 401 | return Tegra::DepthFormat::S8_Z24_UNORM; | ||
| 402 | case PixelFormat::Z24S8: | ||
| 403 | return Tegra::DepthFormat::Z24_S8_UNORM; | ||
| 404 | case PixelFormat::Z32F: | ||
| 405 | return Tegra::DepthFormat::Z32_FLOAT; | ||
| 406 | case PixelFormat::Z16: | ||
| 407 | return Tegra::DepthFormat::Z16_UNORM; | ||
| 408 | case PixelFormat::Z32FS8: | ||
| 409 | return Tegra::DepthFormat::Z32_S8_X24_FLOAT; | ||
| 410 | default: | ||
| 411 | LOG_CRITICAL(HW_GPU, "Unimplemented format={}", static_cast<u32>(format)); | ||
| 412 | UNREACHABLE(); | ||
| 413 | } | ||
| 414 | } | ||
| 415 | |||
| 416 | static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) { | 351 | static ComponentType ComponentTypeFromTexture(Tegra::Texture::ComponentType type) { |
| 417 | // TODO(Subv): Implement more component types | 352 | // TODO(Subv): Implement more component types |
| 418 | switch (type) { | 353 | switch (type) { |
| @@ -441,6 +376,7 @@ struct SurfaceParams { | |||
| 441 | case Tegra::RenderTargetFormat::RGB10_A2_UNORM: | 376 | case Tegra::RenderTargetFormat::RGB10_A2_UNORM: |
| 442 | case Tegra::RenderTargetFormat::R8_UNORM: | 377 | case Tegra::RenderTargetFormat::R8_UNORM: |
| 443 | case Tegra::RenderTargetFormat::RG16_UNORM: | 378 | case Tegra::RenderTargetFormat::RG16_UNORM: |
| 379 | case Tegra::RenderTargetFormat::B5G6R5_UNORM: | ||
| 444 | return ComponentType::UNorm; | 380 | return ComponentType::UNorm; |
| 445 | case Tegra::RenderTargetFormat::RG16_SNORM: | 381 | case Tegra::RenderTargetFormat::RG16_SNORM: |
| 446 | return ComponentType::SNorm; | 382 | return ComponentType::SNorm; |
| @@ -612,8 +548,7 @@ public: | |||
| 612 | Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config); | 548 | Surface GetTextureSurface(const Tegra::Texture::FullTextureInfo& config); |
| 613 | 549 | ||
| 614 | /// Get the color and depth surfaces based on the framebuffer configuration | 550 | /// Get the color and depth surfaces based on the framebuffer configuration |
| 615 | SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb, | 551 | SurfaceSurfaceRect_Tuple GetFramebufferSurfaces(bool using_color_fb, bool using_depth_fb); |
| 616 | const MathUtil::Rectangle<s32>& viewport); | ||
| 617 | 552 | ||
| 618 | /// Flushes the surface to Switch memory | 553 | /// Flushes the surface to Switch memory |
| 619 | void FlushSurface(const Surface& surface); | 554 | void FlushSurface(const Surface& surface); |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index e3217db81..32f06f409 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -507,6 +507,8 @@ private: | |||
| 507 | 507 | ||
| 508 | /// Build the GLSL register list. | 508 | /// Build the GLSL register list. |
| 509 | void BuildRegisterList() { | 509 | void BuildRegisterList() { |
| 510 | regs.reserve(Register::NumRegisters); | ||
| 511 | |||
| 510 | for (size_t index = 0; index < Register::NumRegisters; ++index) { | 512 | for (size_t index = 0; index < Register::NumRegisters; ++index) { |
| 511 | regs.emplace_back(index, suffix); | 513 | regs.emplace_back(index, suffix); |
| 512 | } | 514 | } |
| @@ -523,6 +525,11 @@ private: | |||
| 523 | // shader. | 525 | // shader. |
| 524 | ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex); | 526 | ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex); |
| 525 | return "vec4(0, 0, uintBitsToFloat(gl_InstanceID), uintBitsToFloat(gl_VertexID))"; | 527 | return "vec4(0, 0, uintBitsToFloat(gl_InstanceID), uintBitsToFloat(gl_VertexID))"; |
| 528 | case Attribute::Index::Unknown_63: | ||
| 529 | // TODO(bunnei): Figure out what this is used for. Super Mario Odyssey uses this. | ||
| 530 | LOG_CRITICAL(HW_GPU, "Unhandled input attribute Unknown_63"); | ||
| 531 | UNREACHABLE(); | ||
| 532 | break; | ||
| 526 | default: | 533 | default: |
| 527 | const u32 index{static_cast<u32>(attribute) - | 534 | const u32 index{static_cast<u32>(attribute) - |
| 528 | static_cast<u32>(Attribute::Index::Attribute_0)}; | 535 | static_cast<u32>(Attribute::Index::Attribute_0)}; |
| @@ -534,6 +541,8 @@ private: | |||
| 534 | LOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index); | 541 | LOG_CRITICAL(HW_GPU, "Unhandled input attribute: {}", index); |
| 535 | UNREACHABLE(); | 542 | UNREACHABLE(); |
| 536 | } | 543 | } |
| 544 | |||
| 545 | return "vec4(0, 0, 0, 0)"; | ||
| 537 | } | 546 | } |
| 538 | 547 | ||
| 539 | /// Generates code representing an output attribute register. | 548 | /// Generates code representing an output attribute register. |
| @@ -602,12 +611,12 @@ private: | |||
| 602 | 611 | ||
| 603 | /// Generates code representing a 19-bit immediate value | 612 | /// Generates code representing a 19-bit immediate value |
| 604 | static std::string GetImmediate19(const Instruction& instr) { | 613 | static std::string GetImmediate19(const Instruction& instr) { |
| 605 | return std::to_string(instr.alu.GetImm20_19()); | 614 | return fmt::format("uintBitsToFloat({})", instr.alu.GetImm20_19()); |
| 606 | } | 615 | } |
| 607 | 616 | ||
| 608 | /// Generates code representing a 32-bit immediate value | 617 | /// Generates code representing a 32-bit immediate value |
| 609 | static std::string GetImmediate32(const Instruction& instr) { | 618 | static std::string GetImmediate32(const Instruction& instr) { |
| 610 | return std::to_string(instr.alu.GetImm20_32()); | 619 | return fmt::format("uintBitsToFloat({})", instr.alu.GetImm20_32()); |
| 611 | } | 620 | } |
| 612 | 621 | ||
| 613 | /// Generates code representing a texture sampler. | 622 | /// Generates code representing a texture sampler. |
| @@ -650,16 +659,17 @@ private: | |||
| 650 | * @param instr Instruction to generate the if condition for. | 659 | * @param instr Instruction to generate the if condition for. |
| 651 | * @returns string containing the predicate condition. | 660 | * @returns string containing the predicate condition. |
| 652 | */ | 661 | */ |
| 653 | std::string GetPredicateCondition(u64 index, bool negate) const { | 662 | std::string GetPredicateCondition(u64 index, bool negate) { |
| 654 | using Tegra::Shader::Pred; | 663 | using Tegra::Shader::Pred; |
| 655 | std::string variable; | 664 | std::string variable; |
| 656 | 665 | ||
| 657 | // Index 7 is used as an 'Always True' condition. | 666 | // Index 7 is used as an 'Always True' condition. |
| 658 | if (index == static_cast<u64>(Pred::UnusedIndex)) | 667 | if (index == static_cast<u64>(Pred::UnusedIndex)) { |
| 659 | variable = "true"; | 668 | variable = "true"; |
| 660 | else | 669 | } else { |
| 661 | variable = 'p' + std::to_string(index) + '_' + suffix; | 670 | variable = 'p' + std::to_string(index) + '_' + suffix; |
| 662 | 671 | declr_predicates.insert(variable); | |
| 672 | } | ||
| 663 | if (negate) { | 673 | if (negate) { |
| 664 | return "!(" + variable + ')'; | 674 | return "!(" + variable + ')'; |
| 665 | } | 675 | } |
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index 24b1d956b..5c7b636e4 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -7,6 +7,10 @@ | |||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <glad/glad.h> | 8 | #include <glad/glad.h> |
| 9 | 9 | ||
| 10 | #include "video_core/engines/maxwell_3d.h" | ||
| 11 | |||
| 12 | using Regs = Tegra::Engines::Maxwell3D::Regs; | ||
| 13 | |||
| 10 | namespace TextureUnits { | 14 | namespace TextureUnits { |
| 11 | 15 | ||
| 12 | struct TextureUnit { | 16 | struct TextureUnit { |
| @@ -120,7 +124,7 @@ public: | |||
| 120 | GLuint bindpoint; | 124 | GLuint bindpoint; |
| 121 | GLuint ssbo; | 125 | GLuint ssbo; |
| 122 | }; | 126 | }; |
| 123 | std::array<std::array<ConstBufferConfig, 16>, 5> const_buffers{}; | 127 | std::array<std::array<ConstBufferConfig, Regs::MaxConstBuffers>, 5> const_buffers; |
| 124 | } draw; | 128 | } draw; |
| 125 | 129 | ||
| 126 | struct { | 130 | struct { |
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 16b1bd606..c439446b1 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -27,9 +27,11 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { | |||
| 27 | case Maxwell::VertexAttribute::Type::UnsignedNorm: { | 27 | case Maxwell::VertexAttribute::Type::UnsignedNorm: { |
| 28 | 28 | ||
| 29 | switch (attrib.size) { | 29 | switch (attrib.size) { |
| 30 | case Maxwell::VertexAttribute::Size::Size_8_8: | ||
| 30 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | 31 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: |
| 31 | return GL_UNSIGNED_BYTE; | 32 | return GL_UNSIGNED_BYTE; |
| 32 | case Maxwell::VertexAttribute::Size::Size_16_16: | 33 | case Maxwell::VertexAttribute::Size::Size_16_16: |
| 34 | case Maxwell::VertexAttribute::Size::Size_16_16_16_16: | ||
| 33 | return GL_UNSIGNED_SHORT; | 35 | return GL_UNSIGNED_SHORT; |
| 34 | case Maxwell::VertexAttribute::Size::Size_10_10_10_2: | 36 | case Maxwell::VertexAttribute::Size::Size_10_10_10_2: |
| 35 | return GL_UNSIGNED_INT_2_10_10_10_REV; | 37 | return GL_UNSIGNED_INT_2_10_10_10_REV; |
| @@ -43,6 +45,9 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) { | |||
| 43 | case Maxwell::VertexAttribute::Type::SignedNorm: { | 45 | case Maxwell::VertexAttribute::Type::SignedNorm: { |
| 44 | 46 | ||
| 45 | switch (attrib.size) { | 47 | switch (attrib.size) { |
| 48 | case Maxwell::VertexAttribute::Size::Size_32_32_32: | ||
| 49 | return GL_INT; | ||
| 50 | case Maxwell::VertexAttribute::Size::Size_8_8: | ||
| 46 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: | 51 | case Maxwell::VertexAttribute::Size::Size_8_8_8_8: |
| 47 | return GL_BYTE; | 52 | return GL_BYTE; |
| 48 | case Maxwell::VertexAttribute::Size::Size_16_16: | 53 | case Maxwell::VertexAttribute::Size::Size_16_16: |
| @@ -84,6 +89,8 @@ inline GLenum IndexFormat(Maxwell::IndexFormat index_format) { | |||
| 84 | 89 | ||
| 85 | inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) { | 90 | inline GLenum PrimitiveTopology(Maxwell::PrimitiveTopology topology) { |
| 86 | switch (topology) { | 91 | switch (topology) { |
| 92 | case Maxwell::PrimitiveTopology::Points: | ||
| 93 | return GL_POINTS; | ||
| 87 | case Maxwell::PrimitiveTopology::Triangles: | 94 | case Maxwell::PrimitiveTopology::Triangles: |
| 88 | return GL_TRIANGLES; | 95 | return GL_TRIANGLES; |
| 89 | case Maxwell::PrimitiveTopology::TriangleStrip: | 96 | case Maxwell::PrimitiveTopology::TriangleStrip: |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index bf9131193..899865e3b 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -430,7 +430,7 @@ static void APIENTRY DebugHandler(GLenum source, GLenum type, GLuint id, GLenum | |||
| 430 | break; | 430 | break; |
| 431 | case GL_DEBUG_SEVERITY_NOTIFICATION: | 431 | case GL_DEBUG_SEVERITY_NOTIFICATION: |
| 432 | case GL_DEBUG_SEVERITY_LOW: | 432 | case GL_DEBUG_SEVERITY_LOW: |
| 433 | LOG_DEBUG(Render_OpenGL, format, str_source, str_type, id, message); | 433 | LOG_TRACE(Render_OpenGL, format, str_source, str_type, id, message); |
| 434 | break; | 434 | break; |
| 435 | } | 435 | } |
| 436 | } | 436 | } |
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 65db84ad3..70746a34e 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp | |||
| @@ -54,6 +54,7 @@ u32 BytesPerPixel(TextureFormat format) { | |||
| 54 | return 8; | 54 | return 8; |
| 55 | case TextureFormat::DXT23: | 55 | case TextureFormat::DXT23: |
| 56 | case TextureFormat::DXT45: | 56 | case TextureFormat::DXT45: |
| 57 | case TextureFormat::DXN2: | ||
| 57 | case TextureFormat::BC7U: | 58 | case TextureFormat::BC7U: |
| 58 | // In this case a 'pixel' actually refers to a 4x4 tile. | 59 | // In this case a 'pixel' actually refers to a 4x4 tile. |
| 59 | return 16; | 60 | return 16; |
| @@ -85,87 +86,11 @@ u32 BytesPerPixel(TextureFormat format) { | |||
| 85 | } | 86 | } |
| 86 | } | 87 | } |
| 87 | 88 | ||
| 88 | static u32 DepthBytesPerPixel(DepthFormat format) { | 89 | std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, |
| 89 | switch (format) { | 90 | u32 height, u32 block_height) { |
| 90 | case DepthFormat::Z16_UNORM: | ||
| 91 | return 2; | ||
| 92 | case DepthFormat::S8_Z24_UNORM: | ||
| 93 | case DepthFormat::Z24_S8_UNORM: | ||
| 94 | case DepthFormat::Z32_FLOAT: | ||
| 95 | return 4; | ||
| 96 | case DepthFormat::Z32_S8_X24_FLOAT: | ||
| 97 | return 8; | ||
| 98 | default: | ||
| 99 | UNIMPLEMENTED_MSG("Format not implemented"); | ||
| 100 | break; | ||
| 101 | } | ||
| 102 | } | ||
| 103 | |||
| 104 | std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height, | ||
| 105 | u32 block_height) { | ||
| 106 | u8* data = Memory::GetPointer(address); | ||
| 107 | u32 bytes_per_pixel = BytesPerPixel(format); | ||
| 108 | |||
| 109 | std::vector<u8> unswizzled_data(width * height * bytes_per_pixel); | 91 | std::vector<u8> unswizzled_data(width * height * bytes_per_pixel); |
| 110 | 92 | CopySwizzledData(width / tile_size, height / tile_size, bytes_per_pixel, bytes_per_pixel, | |
| 111 | switch (format) { | 93 | Memory::GetPointer(address), unswizzled_data.data(), true, block_height); |
| 112 | case TextureFormat::DXT1: | ||
| 113 | case TextureFormat::DXT23: | ||
| 114 | case TextureFormat::DXT45: | ||
| 115 | case TextureFormat::DXN1: | ||
| 116 | case TextureFormat::BC7U: | ||
| 117 | // In the DXT and DXN formats, each 4x4 tile is swizzled instead of just individual pixel | ||
| 118 | // values. | ||
| 119 | CopySwizzledData(width / 4, height / 4, bytes_per_pixel, bytes_per_pixel, data, | ||
| 120 | unswizzled_data.data(), true, block_height); | ||
| 121 | break; | ||
| 122 | case TextureFormat::A8R8G8B8: | ||
| 123 | case TextureFormat::A2B10G10R10: | ||
| 124 | case TextureFormat::A1B5G5R5: | ||
| 125 | case TextureFormat::B5G6R5: | ||
| 126 | case TextureFormat::R8: | ||
| 127 | case TextureFormat::G8R8: | ||
| 128 | case TextureFormat::R16_G16_B16_A16: | ||
| 129 | case TextureFormat::R32_G32_B32_A32: | ||
| 130 | case TextureFormat::R32_G32: | ||
| 131 | case TextureFormat::R32: | ||
| 132 | case TextureFormat::R16: | ||
| 133 | case TextureFormat::R16_G16: | ||
| 134 | case TextureFormat::BF10GF11RF11: | ||
| 135 | case TextureFormat::ASTC_2D_4X4: | ||
| 136 | case TextureFormat::R32_G32_B32: | ||
| 137 | CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data, | ||
| 138 | unswizzled_data.data(), true, block_height); | ||
| 139 | break; | ||
| 140 | default: | ||
| 141 | UNIMPLEMENTED_MSG("Format not implemented"); | ||
| 142 | break; | ||
| 143 | } | ||
| 144 | |||
| 145 | return unswizzled_data; | ||
| 146 | } | ||
| 147 | |||
| 148 | std::vector<u8> UnswizzleDepthTexture(VAddr address, DepthFormat format, u32 width, u32 height, | ||
| 149 | u32 block_height) { | ||
| 150 | u8* data = Memory::GetPointer(address); | ||
| 151 | u32 bytes_per_pixel = DepthBytesPerPixel(format); | ||
| 152 | |||
| 153 | std::vector<u8> unswizzled_data(width * height * bytes_per_pixel); | ||
| 154 | |||
| 155 | switch (format) { | ||
| 156 | case DepthFormat::Z16_UNORM: | ||
| 157 | case DepthFormat::S8_Z24_UNORM: | ||
| 158 | case DepthFormat::Z24_S8_UNORM: | ||
| 159 | case DepthFormat::Z32_FLOAT: | ||
| 160 | case DepthFormat::Z32_S8_X24_FLOAT: | ||
| 161 | CopySwizzledData(width, height, bytes_per_pixel, bytes_per_pixel, data, | ||
| 162 | unswizzled_data.data(), true, block_height); | ||
| 163 | break; | ||
| 164 | default: | ||
| 165 | UNIMPLEMENTED_MSG("Format not implemented"); | ||
| 166 | break; | ||
| 167 | } | ||
| 168 | |||
| 169 | return unswizzled_data; | 94 | return unswizzled_data; |
| 170 | } | 95 | } |
| 171 | 96 | ||
| @@ -179,6 +104,7 @@ std::vector<u8> DecodeTexture(const std::vector<u8>& texture_data, TextureFormat | |||
| 179 | case TextureFormat::DXT23: | 104 | case TextureFormat::DXT23: |
| 180 | case TextureFormat::DXT45: | 105 | case TextureFormat::DXT45: |
| 181 | case TextureFormat::DXN1: | 106 | case TextureFormat::DXN1: |
| 107 | case TextureFormat::DXN2: | ||
| 182 | case TextureFormat::BC7U: | 108 | case TextureFormat::BC7U: |
| 183 | case TextureFormat::ASTC_2D_4X4: | 109 | case TextureFormat::ASTC_2D_4X4: |
| 184 | case TextureFormat::A8R8G8B8: | 110 | case TextureFormat::A8R8G8B8: |
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h index 73a4924d1..1f7b731be 100644 --- a/src/video_core/textures/decoders.h +++ b/src/video_core/textures/decoders.h | |||
| @@ -13,8 +13,8 @@ namespace Tegra::Texture { | |||
| 13 | /** | 13 | /** |
| 14 | * Unswizzles a swizzled texture without changing its format. | 14 | * Unswizzles a swizzled texture without changing its format. |
| 15 | */ | 15 | */ |
| 16 | std::vector<u8> UnswizzleTexture(VAddr address, TextureFormat format, u32 width, u32 height, | 16 | std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size, u32 bytes_per_pixel, u32 width, |
| 17 | u32 block_height = TICEntry::DefaultBlockHeight); | 17 | u32 height, u32 block_height = TICEntry::DefaultBlockHeight); |
| 18 | 18 | ||
| 19 | /** | 19 | /** |
| 20 | * Unswizzles a swizzled depth texture without changing its format. | 20 | * Unswizzles a swizzled depth texture without changing its format. |
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt index 475556806..46ed232d8 100644 --- a/src/yuzu/CMakeLists.txt +++ b/src/yuzu/CMakeLists.txt | |||
| @@ -17,6 +17,8 @@ add_executable(yuzu | |||
| 17 | configuration/configure_debug.h | 17 | configuration/configure_debug.h |
| 18 | configuration/configure_dialog.cpp | 18 | configuration/configure_dialog.cpp |
| 19 | configuration/configure_dialog.h | 19 | configuration/configure_dialog.h |
| 20 | configuration/configure_gamelist.cpp | ||
| 21 | configuration/configure_gamelist.h | ||
| 20 | configuration/configure_general.cpp | 22 | configuration/configure_general.cpp |
| 21 | configuration/configure_general.h | 23 | configuration/configure_general.h |
| 22 | configuration/configure_graphics.cpp | 24 | configuration/configure_graphics.cpp |
| @@ -59,6 +61,7 @@ set(UIS | |||
| 59 | configuration/configure.ui | 61 | configuration/configure.ui |
| 60 | configuration/configure_audio.ui | 62 | configuration/configure_audio.ui |
| 61 | configuration/configure_debug.ui | 63 | configuration/configure_debug.ui |
| 64 | configuration/configure_gamelist.ui | ||
| 62 | configuration/configure_general.ui | 65 | configuration/configure_general.ui |
| 63 | configuration/configure_graphics.ui | 66 | configuration/configure_graphics.ui |
| 64 | configuration/configure_input.ui | 67 | configuration/configure_input.ui |
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index bf469ee73..0bd46dbac 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -122,6 +122,13 @@ void Config::ReadValues() { | |||
| 122 | qt_config->beginGroup("UI"); | 122 | qt_config->beginGroup("UI"); |
| 123 | UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString(); | 123 | UISettings::values.theme = qt_config->value("theme", UISettings::themes[0].second).toString(); |
| 124 | 124 | ||
| 125 | qt_config->beginGroup("UIGameList"); | ||
| 126 | UISettings::values.show_unknown = qt_config->value("show_unknown", true).toBool(); | ||
| 127 | UISettings::values.icon_size = qt_config->value("icon_size", 48).toUInt(); | ||
| 128 | UISettings::values.row_1_text_id = qt_config->value("row_1_text_id", 0).toUInt(); | ||
| 129 | UISettings::values.row_2_text_id = qt_config->value("row_2_text_id", 3).toUInt(); | ||
| 130 | qt_config->endGroup(); | ||
| 131 | |||
| 125 | qt_config->beginGroup("UILayout"); | 132 | qt_config->beginGroup("UILayout"); |
| 126 | UISettings::values.geometry = qt_config->value("geometry").toByteArray(); | 133 | UISettings::values.geometry = qt_config->value("geometry").toByteArray(); |
| 127 | UISettings::values.state = qt_config->value("state").toByteArray(); | 134 | UISettings::values.state = qt_config->value("state").toByteArray(); |
| @@ -234,6 +241,13 @@ void Config::SaveValues() { | |||
| 234 | qt_config->beginGroup("UI"); | 241 | qt_config->beginGroup("UI"); |
| 235 | qt_config->setValue("theme", UISettings::values.theme); | 242 | qt_config->setValue("theme", UISettings::values.theme); |
| 236 | 243 | ||
| 244 | qt_config->beginGroup("UIGameList"); | ||
| 245 | qt_config->setValue("show_unknown", UISettings::values.show_unknown); | ||
| 246 | qt_config->setValue("icon_size", UISettings::values.icon_size); | ||
| 247 | qt_config->setValue("row_1_text_id", UISettings::values.row_1_text_id); | ||
| 248 | qt_config->setValue("row_2_text_id", UISettings::values.row_2_text_id); | ||
| 249 | qt_config->endGroup(); | ||
| 250 | |||
| 237 | qt_config->beginGroup("UILayout"); | 251 | qt_config->beginGroup("UILayout"); |
| 238 | qt_config->setValue("geometry", UISettings::values.geometry); | 252 | qt_config->setValue("geometry", UISettings::values.geometry); |
| 239 | qt_config->setValue("state", UISettings::values.state); | 253 | qt_config->setValue("state", UISettings::values.state); |
diff --git a/src/yuzu/configuration/configure.ui b/src/yuzu/configuration/configure.ui index c8e0b88af..20f120134 100644 --- a/src/yuzu/configuration/configure.ui +++ b/src/yuzu/configuration/configure.ui | |||
| @@ -24,6 +24,11 @@ | |||
| 24 | <string>General</string> | 24 | <string>General</string> |
| 25 | </attribute> | 25 | </attribute> |
| 26 | </widget> | 26 | </widget> |
| 27 | <widget class="ConfigureGameList" name="gameListTab"> | ||
| 28 | <attribute name="title"> | ||
| 29 | <string>Game List</string> | ||
| 30 | </attribute> | ||
| 31 | </widget> | ||
| 27 | <widget class="ConfigureSystem" name="systemTab"> | 32 | <widget class="ConfigureSystem" name="systemTab"> |
| 28 | <attribute name="title"> | 33 | <attribute name="title"> |
| 29 | <string>System</string> | 34 | <string>System</string> |
| @@ -67,6 +72,12 @@ | |||
| 67 | <header>configuration/configure_general.h</header> | 72 | <header>configuration/configure_general.h</header> |
| 68 | <container>1</container> | 73 | <container>1</container> |
| 69 | </customwidget> | 74 | </customwidget> |
| 75 | <customwidget> | ||
| 76 | <class>ConfigureGameList</class> | ||
| 77 | <extends>QWidget</extends> | ||
| 78 | <header>configuration/configure_gamelist.h</header> | ||
| 79 | <container>1</container> | ||
| 80 | </customwidget> | ||
| 70 | <customwidget> | 81 | <customwidget> |
| 71 | <class>ConfigureSystem</class> | 82 | <class>ConfigureSystem</class> |
| 72 | <extends>QWidget</extends> | 83 | <extends>QWidget</extends> |
diff --git a/src/yuzu/configuration/configure_dialog.cpp b/src/yuzu/configuration/configure_dialog.cpp index cc4b326ae..daa4cc0d9 100644 --- a/src/yuzu/configuration/configure_dialog.cpp +++ b/src/yuzu/configuration/configure_dialog.cpp | |||
| @@ -21,6 +21,7 @@ void ConfigureDialog::setConfiguration() {} | |||
| 21 | 21 | ||
| 22 | void ConfigureDialog::applyConfiguration() { | 22 | void ConfigureDialog::applyConfiguration() { |
| 23 | ui->generalTab->applyConfiguration(); | 23 | ui->generalTab->applyConfiguration(); |
| 24 | ui->gameListTab->applyConfiguration(); | ||
| 24 | ui->systemTab->applyConfiguration(); | 25 | ui->systemTab->applyConfiguration(); |
| 25 | ui->inputTab->applyConfiguration(); | 26 | ui->inputTab->applyConfiguration(); |
| 26 | ui->graphicsTab->applyConfiguration(); | 27 | ui->graphicsTab->applyConfiguration(); |
diff --git a/src/yuzu/configuration/configure_gamelist.cpp b/src/yuzu/configuration/configure_gamelist.cpp new file mode 100644 index 000000000..1ae3423cf --- /dev/null +++ b/src/yuzu/configuration/configure_gamelist.cpp | |||
| @@ -0,0 +1,63 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "core/core.h" | ||
| 6 | #include "core/settings.h" | ||
| 7 | #include "ui_configure_gamelist.h" | ||
| 8 | #include "ui_settings.h" | ||
| 9 | #include "yuzu/configuration/configure_gamelist.h" | ||
| 10 | |||
| 11 | ConfigureGameList::ConfigureGameList(QWidget* parent) | ||
| 12 | : QWidget(parent), ui(new Ui::ConfigureGameList) { | ||
| 13 | ui->setupUi(this); | ||
| 14 | |||
| 15 | static const std::vector<std::pair<u32, std::string>> default_icon_sizes{ | ||
| 16 | std::make_pair(0, "None"), std::make_pair(32, "Small"), | ||
| 17 | std::make_pair(64, "Standard"), std::make_pair(128, "Large"), | ||
| 18 | std::make_pair(256, "Full Size"), | ||
| 19 | }; | ||
| 20 | |||
| 21 | for (const auto& size : default_icon_sizes) { | ||
| 22 | ui->icon_size_combobox->addItem(QString::fromStdString(size.second + " (" + | ||
| 23 | std::to_string(size.first) + "x" + | ||
| 24 | std::to_string(size.first) + ")"), | ||
| 25 | size.first); | ||
| 26 | } | ||
| 27 | |||
| 28 | static const std::vector<std::string> row_text_names{ | ||
| 29 | "Filename", | ||
| 30 | "Filetype", | ||
| 31 | "Title ID", | ||
| 32 | "Title Name", | ||
| 33 | }; | ||
| 34 | |||
| 35 | for (size_t i = 0; i < row_text_names.size(); ++i) { | ||
| 36 | ui->row_1_text_combobox->addItem(QString::fromStdString(row_text_names[i]), | ||
| 37 | QVariant::fromValue(i)); | ||
| 38 | ui->row_2_text_combobox->addItem(QString::fromStdString(row_text_names[i]), | ||
| 39 | QVariant::fromValue(i)); | ||
| 40 | } | ||
| 41 | |||
| 42 | this->setConfiguration(); | ||
| 43 | } | ||
| 44 | |||
| 45 | ConfigureGameList::~ConfigureGameList() {} | ||
| 46 | |||
| 47 | void ConfigureGameList::setConfiguration() { | ||
| 48 | ui->show_unknown->setChecked(UISettings::values.show_unknown); | ||
| 49 | ui->icon_size_combobox->setCurrentIndex( | ||
| 50 | ui->icon_size_combobox->findData(UISettings::values.icon_size)); | ||
| 51 | ui->row_1_text_combobox->setCurrentIndex( | ||
| 52 | ui->row_1_text_combobox->findData(UISettings::values.row_1_text_id)); | ||
| 53 | ui->row_2_text_combobox->setCurrentIndex( | ||
| 54 | ui->row_2_text_combobox->findData(UISettings::values.row_2_text_id)); | ||
| 55 | } | ||
| 56 | |||
| 57 | void ConfigureGameList::applyConfiguration() { | ||
| 58 | UISettings::values.show_unknown = ui->show_unknown->isChecked(); | ||
| 59 | UISettings::values.icon_size = ui->icon_size_combobox->currentData().toUInt(); | ||
| 60 | UISettings::values.row_1_text_id = ui->row_1_text_combobox->currentData().toUInt(); | ||
| 61 | UISettings::values.row_2_text_id = ui->row_2_text_combobox->currentData().toUInt(); | ||
| 62 | Settings::Apply(); | ||
| 63 | } | ||
diff --git a/src/yuzu/configuration/configure_gamelist.h b/src/yuzu/configuration/configure_gamelist.h new file mode 100644 index 000000000..94fba6373 --- /dev/null +++ b/src/yuzu/configuration/configure_gamelist.h | |||
| @@ -0,0 +1,28 @@ | |||
| 1 | // Copyright 2016 Citra Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <memory> | ||
| 8 | #include <QWidget> | ||
| 9 | |||
| 10 | namespace Ui { | ||
| 11 | class ConfigureGameList; | ||
| 12 | } | ||
| 13 | |||
| 14 | class ConfigureGameList : public QWidget { | ||
| 15 | Q_OBJECT | ||
| 16 | |||
| 17 | public: | ||
| 18 | explicit ConfigureGameList(QWidget* parent = nullptr); | ||
| 19 | ~ConfigureGameList(); | ||
| 20 | |||
| 21 | void applyConfiguration(); | ||
| 22 | |||
| 23 | private: | ||
| 24 | void setConfiguration(); | ||
| 25 | |||
| 26 | private: | ||
| 27 | std::unique_ptr<Ui::ConfigureGameList> ui; | ||
| 28 | }; | ||
diff --git a/src/yuzu/configuration/configure_gamelist.ui b/src/yuzu/configuration/configure_gamelist.ui new file mode 100644 index 000000000..7471fdb60 --- /dev/null +++ b/src/yuzu/configuration/configure_gamelist.ui | |||
| @@ -0,0 +1,126 @@ | |||
| 1 | <?xml version="1.0" encoding="UTF-8"?> | ||
| 2 | <ui version="4.0"> | ||
| 3 | <class>ConfigureGameList</class> | ||
| 4 | <widget class="QWidget" name="ConfigureGeneral"> | ||
| 5 | <property name="geometry"> | ||
| 6 | <rect> | ||
| 7 | <x>0</x> | ||
| 8 | <y>0</y> | ||
| 9 | <width>300</width> | ||
| 10 | <height>377</height> | ||
| 11 | </rect> | ||
| 12 | </property> | ||
| 13 | <property name="windowTitle"> | ||
| 14 | <string>Form</string> | ||
| 15 | </property> | ||
| 16 | <layout class="QHBoxLayout" name="HorizontalLayout"> | ||
| 17 | <item> | ||
| 18 | <layout class="QVBoxLayout" name="VerticalLayout"> | ||
| 19 | <item> | ||
| 20 | <widget class="QGroupBox" name="GeneralGroupBox"> | ||
| 21 | <property name="title"> | ||
| 22 | <string>General</string> | ||
| 23 | </property> | ||
| 24 | <layout class="QHBoxLayout" name="GeneralHorizontalLayout"> | ||
| 25 | <item> | ||
| 26 | <layout class="QVBoxLayout" name="GeneralVerticalLayout"> | ||
| 27 | <item> | ||
| 28 | <widget class="QCheckBox" name="show_unknown"> | ||
| 29 | <property name="text"> | ||
| 30 | <string>Show files with type 'Unknown'</string> | ||
| 31 | </property> | ||
| 32 | </widget> | ||
| 33 | </item> | ||
| 34 | </layout> | ||
| 35 | </item> | ||
| 36 | </layout> | ||
| 37 | </widget> | ||
| 38 | </item> | ||
| 39 | <item> | ||
| 40 | <widget class="QGroupBox" name="IconSizeGroupBox"> | ||
| 41 | <property name="title"> | ||
| 42 | <string>Icon Size</string> | ||
| 43 | </property> | ||
| 44 | <layout class="QHBoxLayout" name="icon_size_qhbox_layout"> | ||
| 45 | <item> | ||
| 46 | <layout class="QVBoxLayout" name="icon_size_qvbox_layout"> | ||
| 47 | <item> | ||
| 48 | <layout class="QHBoxLayout" name="icon_size_qhbox_layout_2"> | ||
| 49 | <item> | ||
| 50 | <widget class="QLabel" name="icon_size_label"> | ||
| 51 | <property name="text"> | ||
| 52 | <string>Icon Size:</string> | ||
| 53 | </property> | ||
| 54 | </widget> | ||
| 55 | </item> | ||
| 56 | <item> | ||
| 57 | <widget class="QComboBox" name="icon_size_combobox"/> | ||
| 58 | </item> | ||
| 59 | </layout> | ||
| 60 | </item> | ||
| 61 | </layout> | ||
| 62 | </item> | ||
| 63 | </layout> | ||
| 64 | </widget> | ||
| 65 | </item> | ||
| 66 | <item> | ||
| 67 | <widget class="QGroupBox" name="RowGroupBox"> | ||
| 68 | <property name="title"> | ||
| 69 | <string>Row Text</string> | ||
| 70 | </property> | ||
| 71 | <layout class="QHBoxLayout" name="RowHorizontalLayout"> | ||
| 72 | <item> | ||
| 73 | <layout class="QVBoxLayout" name="RowVerticalLayout"> | ||
| 74 | <item> | ||
| 75 | <layout class="QHBoxLayout" name="row_1_qhbox_layout"> | ||
| 76 | <item> | ||
| 77 | <widget class="QLabel" name="row_1_label"> | ||
| 78 | <property name="text"> | ||
| 79 | <string>Row 1 Text:</string> | ||
| 80 | </property> | ||
| 81 | </widget> | ||
| 82 | </item> | ||
| 83 | <item> | ||
| 84 | <widget class="QComboBox" name="row_1_text_combobox"/> | ||
| 85 | </item> | ||
| 86 | </layout> | ||
| 87 | </item> | ||
| 88 | <item> | ||
| 89 | <layout class="QHBoxLayout" name="row_2_qhbox_layout"> | ||
| 90 | <item> | ||
| 91 | <widget class="QLabel" name="row_2_label"> | ||
| 92 | <property name="text"> | ||
| 93 | <string>Row 2 Text:</string> | ||
| 94 | </property> | ||
| 95 | </widget> | ||
| 96 | </item> | ||
| 97 | <item> | ||
| 98 | <widget class="QComboBox" name="row_2_text_combobox"/> | ||
| 99 | </item> | ||
| 100 | </layout> | ||
| 101 | </item> | ||
| 102 | </layout> | ||
| 103 | </item> | ||
| 104 | </layout> | ||
| 105 | </widget> | ||
| 106 | </item> | ||
| 107 | <item> | ||
| 108 | <spacer name="verticalSpacer"> | ||
| 109 | <property name="orientation"> | ||
| 110 | <enum>Qt::Vertical</enum> | ||
| 111 | </property> | ||
| 112 | <property name="sizeHint" stdset="0"> | ||
| 113 | <size> | ||
| 114 | <width>20</width> | ||
| 115 | <height>40</height> | ||
| 116 | </size> | ||
| 117 | </property> | ||
| 118 | </spacer> | ||
| 119 | </item> | ||
| 120 | </layout> | ||
| 121 | </item> | ||
| 122 | </layout> | ||
| 123 | </widget> | ||
| 124 | <resources/> | ||
| 125 | <connections/> | ||
| 126 | </ui> | ||
diff --git a/src/yuzu/debugger/graphics/graphics_surface.cpp b/src/yuzu/debugger/graphics/graphics_surface.cpp index 3f7103ab9..e037223c2 100644 --- a/src/yuzu/debugger/graphics/graphics_surface.cpp +++ b/src/yuzu/debugger/graphics/graphics_surface.cpp | |||
| @@ -383,8 +383,10 @@ void GraphicsSurfaceWidget::OnUpdate() { | |||
| 383 | QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32); | 383 | QImage decoded_image(surface_width, surface_height, QImage::Format_ARGB32); |
| 384 | boost::optional<VAddr> address = gpu.memory_manager->GpuToCpuAddress(surface_address); | 384 | boost::optional<VAddr> address = gpu.memory_manager->GpuToCpuAddress(surface_address); |
| 385 | 385 | ||
| 386 | auto unswizzled_data = | 386 | // TODO(bunnei): Will not work with BCn formats that swizzle 4x4 tiles. |
| 387 | Tegra::Texture::UnswizzleTexture(*address, surface_format, surface_width, surface_height); | 387 | // Needs to be fixed if we plan to use this feature more, otherwise we may remove it. |
| 388 | auto unswizzled_data = Tegra::Texture::UnswizzleTexture( | ||
| 389 | *address, 1, Tegra::Texture::BytesPerPixel(surface_format), surface_width, surface_height); | ||
| 388 | 390 | ||
| 389 | auto texture_data = Tegra::Texture::DecodeTexture(unswizzled_data, surface_format, | 391 | auto texture_data = Tegra::Texture::DecodeTexture(unswizzled_data, surface_format, |
| 390 | surface_width, surface_height); | 392 | surface_width, surface_height); |
diff --git a/src/yuzu/game_list.cpp b/src/yuzu/game_list.cpp index 24f38a3c7..1c738d2a4 100644 --- a/src/yuzu/game_list.cpp +++ b/src/yuzu/game_list.cpp | |||
| @@ -9,9 +9,13 @@ | |||
| 9 | #include <QKeyEvent> | 9 | #include <QKeyEvent> |
| 10 | #include <QMenu> | 10 | #include <QMenu> |
| 11 | #include <QThreadPool> | 11 | #include <QThreadPool> |
| 12 | #include <boost/container/flat_map.hpp> | ||
| 12 | #include "common/common_paths.h" | 13 | #include "common/common_paths.h" |
| 13 | #include "common/logging/log.h" | 14 | #include "common/logging/log.h" |
| 14 | #include "common/string_util.h" | 15 | #include "common/string_util.h" |
| 16 | #include "core/file_sys/content_archive.h" | ||
| 17 | #include "core/file_sys/control_metadata.h" | ||
| 18 | #include "core/file_sys/romfs.h" | ||
| 15 | #include "core/file_sys/vfs_real.h" | 19 | #include "core/file_sys/vfs_real.h" |
| 16 | #include "core/loader/loader.h" | 20 | #include "core/loader/loader.h" |
| 17 | #include "game_list.h" | 21 | #include "game_list.h" |
| @@ -194,7 +198,8 @@ void GameList::onFilterCloseClicked() { | |||
| 194 | main_window->filterBarSetChecked(false); | 198 | main_window->filterBarSetChecked(false); |
| 195 | } | 199 | } |
| 196 | 200 | ||
| 197 | GameList::GameList(GMainWindow* parent) : QWidget{parent} { | 201 | GameList::GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent) |
| 202 | : QWidget{parent}, vfs(std::move(vfs)) { | ||
| 198 | watcher = new QFileSystemWatcher(this); | 203 | watcher = new QFileSystemWatcher(this); |
| 199 | connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); | 204 | connect(watcher, &QFileSystemWatcher::directoryChanged, this, &GameList::RefreshGameDirectory); |
| 200 | 205 | ||
| @@ -338,7 +343,7 @@ void GameList::PopulateAsync(const QString& dir_path, bool deep_scan) { | |||
| 338 | 343 | ||
| 339 | emit ShouldCancelWorker(); | 344 | emit ShouldCancelWorker(); |
| 340 | 345 | ||
| 341 | GameListWorker* worker = new GameListWorker(dir_path, deep_scan); | 346 | GameListWorker* worker = new GameListWorker(vfs, dir_path, deep_scan); |
| 342 | 347 | ||
| 343 | connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection); | 348 | connect(worker, &GameListWorker::EntryReady, this, &GameList::AddEntry, Qt::QueuedConnection); |
| 344 | connect(worker, &GameListWorker::Finished, this, &GameList::DonePopulating, | 349 | connect(worker, &GameListWorker::Finished, this, &GameList::DonePopulating, |
| @@ -398,8 +403,32 @@ void GameList::RefreshGameDirectory() { | |||
| 398 | } | 403 | } |
| 399 | 404 | ||
| 400 | void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { | 405 | void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsigned int recursion) { |
| 401 | const auto callback = [this, recursion](u64* num_entries_out, const std::string& directory, | 406 | boost::container::flat_map<u64, std::shared_ptr<FileSys::NCA>> nca_control_map; |
| 402 | const std::string& virtual_name) -> bool { | 407 | |
| 408 | const auto nca_control_callback = | ||
| 409 | [this, &nca_control_map](u64* num_entries_out, const std::string& directory, | ||
| 410 | const std::string& virtual_name) -> bool { | ||
| 411 | std::string physical_name = directory + DIR_SEP + virtual_name; | ||
| 412 | |||
| 413 | if (stop_processing) | ||
| 414 | return false; // Breaks the callback loop. | ||
| 415 | |||
| 416 | bool is_dir = FileUtil::IsDirectory(physical_name); | ||
| 417 | QFileInfo file_info(physical_name.c_str()); | ||
| 418 | if (!is_dir && file_info.suffix().toStdString() == "nca") { | ||
| 419 | auto nca = | ||
| 420 | std::make_shared<FileSys::NCA>(vfs->OpenFile(physical_name, FileSys::Mode::Read)); | ||
| 421 | if (nca->GetType() == FileSys::NCAContentType::Control) | ||
| 422 | nca_control_map.insert_or_assign(nca->GetTitleId(), nca); | ||
| 423 | } | ||
| 424 | return true; | ||
| 425 | }; | ||
| 426 | |||
| 427 | FileUtil::ForeachDirectoryEntry(nullptr, dir_path, nca_control_callback); | ||
| 428 | |||
| 429 | const auto callback = [this, recursion, | ||
| 430 | &nca_control_map](u64* num_entries_out, const std::string& directory, | ||
| 431 | const std::string& virtual_name) -> bool { | ||
| 403 | std::string physical_name = directory + DIR_SEP + virtual_name; | 432 | std::string physical_name = directory + DIR_SEP + virtual_name; |
| 404 | 433 | ||
| 405 | if (stop_processing) | 434 | if (stop_processing) |
| @@ -409,18 +438,51 @@ void GameListWorker::AddFstEntriesToGameList(const std::string& dir_path, unsign | |||
| 409 | if (!is_dir && | 438 | if (!is_dir && |
| 410 | (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { | 439 | (HasSupportedFileExtension(physical_name) || IsExtractedNCAMain(physical_name))) { |
| 411 | std::unique_ptr<Loader::AppLoader> loader = | 440 | std::unique_ptr<Loader::AppLoader> loader = |
| 412 | Loader::GetLoader(std::make_shared<FileSys::RealVfsFile>(physical_name)); | 441 | Loader::GetLoader(vfs->OpenFile(physical_name, FileSys::Mode::Read)); |
| 413 | if (!loader) | 442 | if (!loader || ((loader->GetFileType() == Loader::FileType::Unknown || |
| 443 | loader->GetFileType() == Loader::FileType::Error) && | ||
| 444 | !UISettings::values.show_unknown)) | ||
| 414 | return true; | 445 | return true; |
| 415 | 446 | ||
| 416 | std::vector<u8> smdh; | 447 | std::vector<u8> icon; |
| 417 | loader->ReadIcon(smdh); | 448 | const auto res1 = loader->ReadIcon(icon); |
| 418 | 449 | ||
| 419 | u64 program_id = 0; | 450 | u64 program_id; |
| 420 | loader->ReadProgramId(program_id); | 451 | const auto res2 = loader->ReadProgramId(program_id); |
| 452 | |||
| 453 | std::string name = " "; | ||
| 454 | const auto res3 = loader->ReadTitle(name); | ||
| 455 | |||
| 456 | if ((res1 == Loader::ResultStatus::ErrorNotUsed || | ||
| 457 | res1 == Loader::ResultStatus::ErrorNotImplemented) && | ||
| 458 | (res3 == Loader::ResultStatus::ErrorNotUsed || | ||
| 459 | res3 == Loader::ResultStatus::ErrorNotImplemented) && | ||
| 460 | res2 == Loader::ResultStatus::Success) { | ||
| 461 | // Use from metadata pool. | ||
| 462 | if (nca_control_map.find(program_id) != nca_control_map.end()) { | ||
| 463 | const auto nca = nca_control_map[program_id]; | ||
| 464 | const auto control_dir = FileSys::ExtractRomFS(nca->GetRomFS()); | ||
| 465 | |||
| 466 | const auto nacp_file = control_dir->GetFile("control.nacp"); | ||
| 467 | FileSys::NACP nacp(nacp_file); | ||
| 468 | name = nacp.GetApplicationName(); | ||
| 469 | |||
| 470 | FileSys::VirtualFile icon_file = nullptr; | ||
| 471 | for (const auto& language : FileSys::LANGUAGE_NAMES) { | ||
| 472 | icon_file = control_dir->GetFile("icon_" + std::string(language) + ".dat"); | ||
| 473 | if (icon_file != nullptr) { | ||
| 474 | icon = icon_file->ReadAllBytes(); | ||
| 475 | break; | ||
| 476 | } | ||
| 477 | } | ||
| 478 | } | ||
| 479 | } | ||
| 421 | 480 | ||
| 422 | emit EntryReady({ | 481 | emit EntryReady({ |
| 423 | new GameListItemPath(FormatGameName(physical_name), smdh, program_id), | 482 | new GameListItemPath( |
| 483 | FormatGameName(physical_name), icon, QString::fromStdString(name), | ||
| 484 | QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType())), | ||
| 485 | program_id), | ||
| 424 | new GameListItem( | 486 | new GameListItem( |
| 425 | QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), | 487 | QString::fromStdString(Loader::GetFileTypeString(loader->GetFileType()))), |
| 426 | new GameListItemSize(FileUtil::GetSize(physical_name)), | 488 | new GameListItemSize(FileUtil::GetSize(physical_name)), |
diff --git a/src/yuzu/game_list.h b/src/yuzu/game_list.h index 3bc14f07f..afe624b32 100644 --- a/src/yuzu/game_list.h +++ b/src/yuzu/game_list.h | |||
| @@ -59,7 +59,7 @@ public: | |||
| 59 | QToolButton* button_filter_close = nullptr; | 59 | QToolButton* button_filter_close = nullptr; |
| 60 | }; | 60 | }; |
| 61 | 61 | ||
| 62 | explicit GameList(GMainWindow* parent = nullptr); | 62 | explicit GameList(FileSys::VirtualFilesystem vfs, GMainWindow* parent = nullptr); |
| 63 | ~GameList() override; | 63 | ~GameList() override; |
| 64 | 64 | ||
| 65 | void clearFilter(); | 65 | void clearFilter(); |
| @@ -90,6 +90,7 @@ private: | |||
| 90 | void PopupContextMenu(const QPoint& menu_location); | 90 | void PopupContextMenu(const QPoint& menu_location); |
| 91 | void RefreshGameDirectory(); | 91 | void RefreshGameDirectory(); |
| 92 | 92 | ||
| 93 | FileSys::VirtualFilesystem vfs; | ||
| 93 | SearchField* search_field; | 94 | SearchField* search_field; |
| 94 | GMainWindow* main_window = nullptr; | 95 | GMainWindow* main_window = nullptr; |
| 95 | QVBoxLayout* layout = nullptr; | 96 | QVBoxLayout* layout = nullptr; |
diff --git a/src/yuzu/game_list_p.h b/src/yuzu/game_list_p.h index aa69a098f..114a0fc7f 100644 --- a/src/yuzu/game_list_p.h +++ b/src/yuzu/game_list_p.h | |||
| @@ -11,6 +11,7 @@ | |||
| 11 | #include <QStandardItem> | 11 | #include <QStandardItem> |
| 12 | #include <QString> | 12 | #include <QString> |
| 13 | #include "common/string_util.h" | 13 | #include "common/string_util.h" |
| 14 | #include "ui_settings.h" | ||
| 14 | #include "yuzu/util/util.h" | 15 | #include "yuzu/util/util.h" |
| 15 | 16 | ||
| 16 | /** | 17 | /** |
| @@ -18,8 +19,7 @@ | |||
| 18 | * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24) | 19 | * @param large If true, returns large icon (48x48), otherwise returns small icon (24x24) |
| 19 | * @return QPixmap default icon | 20 | * @return QPixmap default icon |
| 20 | */ | 21 | */ |
| 21 | static QPixmap GetDefaultIcon(bool large) { | 22 | static QPixmap GetDefaultIcon(u32 size) { |
| 22 | int size = large ? 48 : 24; | ||
| 23 | QPixmap icon(size, size); | 23 | QPixmap icon(size, size); |
| 24 | icon.fill(Qt::transparent); | 24 | icon.fill(Qt::transparent); |
| 25 | return icon; | 25 | return icon; |
| @@ -44,11 +44,25 @@ public: | |||
| 44 | static const int FullPathRole = Qt::UserRole + 1; | 44 | static const int FullPathRole = Qt::UserRole + 1; |
| 45 | static const int TitleRole = Qt::UserRole + 2; | 45 | static const int TitleRole = Qt::UserRole + 2; |
| 46 | static const int ProgramIdRole = Qt::UserRole + 3; | 46 | static const int ProgramIdRole = Qt::UserRole + 3; |
| 47 | static const int FileTypeRole = Qt::UserRole + 4; | ||
| 47 | 48 | ||
| 48 | GameListItemPath() = default; | 49 | GameListItemPath() = default; |
| 49 | GameListItemPath(const QString& game_path, const std::vector<u8>& smdh_data, u64 program_id) { | 50 | GameListItemPath(const QString& game_path, const std::vector<u8>& picture_data, |
| 51 | const QString& game_name, const QString& game_type, u64 program_id) | ||
| 52 | : GameListItem() { | ||
| 50 | setData(game_path, FullPathRole); | 53 | setData(game_path, FullPathRole); |
| 54 | setData(game_name, TitleRole); | ||
| 51 | setData(qulonglong(program_id), ProgramIdRole); | 55 | setData(qulonglong(program_id), ProgramIdRole); |
| 56 | setData(game_type, FileTypeRole); | ||
| 57 | |||
| 58 | QPixmap picture; | ||
| 59 | u32 size = UISettings::values.icon_size; | ||
| 60 | if (!picture.loadFromData(picture_data.data(), picture_data.size())) | ||
| 61 | picture = GetDefaultIcon(size); | ||
| 62 | |||
| 63 | picture = picture.scaled(size, size); | ||
| 64 | |||
| 65 | setData(picture, Qt::DecorationRole); | ||
| 52 | } | 66 | } |
| 53 | 67 | ||
| 54 | QVariant data(int role) const override { | 68 | QVariant data(int role) const override { |
| @@ -57,7 +71,23 @@ public: | |||
| 57 | Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename, | 71 | Common::SplitPath(data(FullPathRole).toString().toStdString(), nullptr, &filename, |
| 58 | nullptr); | 72 | nullptr); |
| 59 | QString title = data(TitleRole).toString(); | 73 | QString title = data(TitleRole).toString(); |
| 60 | return QString::fromStdString(filename) + (title.isEmpty() ? "" : "\n " + title); | 74 | |
| 75 | std::vector<QString> row_data{ | ||
| 76 | QString::fromStdString(filename), | ||
| 77 | data(FileTypeRole).toString(), | ||
| 78 | QString::fromStdString(fmt::format("0x{:016X}", data(ProgramIdRole).toULongLong())), | ||
| 79 | data(TitleRole).toString(), | ||
| 80 | }; | ||
| 81 | |||
| 82 | auto row1 = row_data.at(UISettings::values.row_1_text_id); | ||
| 83 | auto row2 = row_data.at(UISettings::values.row_2_text_id); | ||
| 84 | |||
| 85 | if (row1.isEmpty() || row1 == row2) | ||
| 86 | return row2; | ||
| 87 | if (row2.isEmpty()) | ||
| 88 | return row1; | ||
| 89 | |||
| 90 | return row1 + "\n " + row2; | ||
| 61 | } else { | 91 | } else { |
| 62 | return GameListItem::data(role); | 92 | return GameListItem::data(role); |
| 63 | } | 93 | } |
| @@ -109,8 +139,8 @@ class GameListWorker : public QObject, public QRunnable { | |||
| 109 | Q_OBJECT | 139 | Q_OBJECT |
| 110 | 140 | ||
| 111 | public: | 141 | public: |
| 112 | GameListWorker(QString dir_path, bool deep_scan) | 142 | GameListWorker(FileSys::VirtualFilesystem vfs, QString dir_path, bool deep_scan) |
| 113 | : dir_path(std::move(dir_path)), deep_scan(deep_scan) {} | 143 | : vfs(std::move(vfs)), dir_path(std::move(dir_path)), deep_scan(deep_scan) {} |
| 114 | 144 | ||
| 115 | public slots: | 145 | public slots: |
| 116 | /// Starts the processing of directory tree information. | 146 | /// Starts the processing of directory tree information. |
| @@ -133,6 +163,7 @@ signals: | |||
| 133 | void Finished(QStringList watch_list); | 163 | void Finished(QStringList watch_list); |
| 134 | 164 | ||
| 135 | private: | 165 | private: |
| 166 | FileSys::VirtualFilesystem vfs; | ||
| 136 | QStringList watch_list; | 167 | QStringList watch_list; |
| 137 | QString dir_path; | 168 | QString dir_path; |
| 138 | bool deep_scan; | 169 | bool deep_scan; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 17ed62c72..67e3c6549 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -24,6 +24,7 @@ | |||
| 24 | #include "common/string_util.h" | 24 | #include "common/string_util.h" |
| 25 | #include "core/core.h" | 25 | #include "core/core.h" |
| 26 | #include "core/crypto/key_manager.h" | 26 | #include "core/crypto/key_manager.h" |
| 27 | #include "core/file_sys/vfs_real.h" | ||
| 27 | #include "core/gdbstub/gdbstub.h" | 28 | #include "core/gdbstub/gdbstub.h" |
| 28 | #include "core/loader/loader.h" | 29 | #include "core/loader/loader.h" |
| 29 | #include "core/settings.h" | 30 | #include "core/settings.h" |
| @@ -83,7 +84,9 @@ void GMainWindow::ShowCallouts() {} | |||
| 83 | 84 | ||
| 84 | const int GMainWindow::max_recent_files_item; | 85 | const int GMainWindow::max_recent_files_item; |
| 85 | 86 | ||
| 86 | GMainWindow::GMainWindow() : config(new Config()), emu_thread(nullptr) { | 87 | GMainWindow::GMainWindow() |
| 88 | : config(new Config()), emu_thread(nullptr), | ||
| 89 | vfs(std::make_shared<FileSys::RealVfsFilesystem>()) { | ||
| 87 | 90 | ||
| 88 | debug_context = Tegra::DebugContext::Construct(); | 91 | debug_context = Tegra::DebugContext::Construct(); |
| 89 | 92 | ||
| @@ -132,7 +135,7 @@ void GMainWindow::InitializeWidgets() { | |||
| 132 | render_window = new GRenderWindow(this, emu_thread.get()); | 135 | render_window = new GRenderWindow(this, emu_thread.get()); |
| 133 | render_window->hide(); | 136 | render_window->hide(); |
| 134 | 137 | ||
| 135 | game_list = new GameList(this); | 138 | game_list = new GameList(vfs, this); |
| 136 | ui.horizontalLayout->addWidget(game_list); | 139 | ui.horizontalLayout->addWidget(game_list); |
| 137 | 140 | ||
| 138 | // Create status bar | 141 | // Create status bar |
| @@ -406,6 +409,7 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 406 | } | 409 | } |
| 407 | 410 | ||
| 408 | Core::System& system{Core::System::GetInstance()}; | 411 | Core::System& system{Core::System::GetInstance()}; |
| 412 | system.SetFilesystem(vfs); | ||
| 409 | 413 | ||
| 410 | system.SetGPUDebugContext(debug_context); | 414 | system.SetGPUDebugContext(debug_context); |
| 411 | 415 | ||
| @@ -768,6 +772,7 @@ void GMainWindow::OnConfigure() { | |||
| 768 | configureDialog.applyConfiguration(); | 772 | configureDialog.applyConfiguration(); |
| 769 | if (UISettings::values.theme != old_theme) | 773 | if (UISettings::values.theme != old_theme) |
| 770 | UpdateUITheme(); | 774 | UpdateUITheme(); |
| 775 | game_list->PopulateAsync(UISettings::values.gamedir, UISettings::values.gamedir_deepscan); | ||
| 771 | config->Save(); | 776 | config->Save(); |
| 772 | } | 777 | } |
| 773 | } | 778 | } |
diff --git a/src/yuzu/main.h b/src/yuzu/main.h index 6e335b8f8..74487c58c 100644 --- a/src/yuzu/main.h +++ b/src/yuzu/main.h | |||
| @@ -161,6 +161,9 @@ private: | |||
| 161 | bool emulation_running = false; | 161 | bool emulation_running = false; |
| 162 | std::unique_ptr<EmuThread> emu_thread; | 162 | std::unique_ptr<EmuThread> emu_thread; |
| 163 | 163 | ||
| 164 | // FS | ||
| 165 | FileSys::VirtualFilesystem vfs; | ||
| 166 | |||
| 164 | // Debugger panes | 167 | // Debugger panes |
| 165 | ProfilerWidget* profilerWidget; | 168 | ProfilerWidget* profilerWidget; |
| 166 | MicroProfileDialog* microProfileDialog; | 169 | MicroProfileDialog* microProfileDialog; |
diff --git a/src/yuzu/ui_settings.h b/src/yuzu/ui_settings.h index 2286c2559..051494bc5 100644 --- a/src/yuzu/ui_settings.h +++ b/src/yuzu/ui_settings.h | |||
| @@ -54,6 +54,12 @@ struct Values { | |||
| 54 | 54 | ||
| 55 | // logging | 55 | // logging |
| 56 | bool show_console; | 56 | bool show_console; |
| 57 | |||
| 58 | // Game List | ||
| 59 | bool show_unknown; | ||
| 60 | uint32_t icon_size; | ||
| 61 | uint8_t row_1_text_id; | ||
| 62 | uint8_t row_2_text_id; | ||
| 57 | }; | 63 | }; |
| 58 | 64 | ||
| 59 | extern Values values; | 65 | extern Values values; |
diff --git a/src/yuzu_cmd/yuzu.cpp b/src/yuzu_cmd/yuzu.cpp index d637dbd0c..0605c92e3 100644 --- a/src/yuzu_cmd/yuzu.cpp +++ b/src/yuzu_cmd/yuzu.cpp | |||
| @@ -161,6 +161,7 @@ int main(int argc, char** argv) { | |||
| 161 | } | 161 | } |
| 162 | 162 | ||
| 163 | Core::System& system{Core::System::GetInstance()}; | 163 | Core::System& system{Core::System::GetInstance()}; |
| 164 | system.SetFilesystem(std::make_shared<FileSys::RealVfsFilesystem>()); | ||
| 164 | 165 | ||
| 165 | SCOPE_EXIT({ system.Shutdown(); }); | 166 | SCOPE_EXIT({ system.Shutdown(); }); |
| 166 | 167 | ||