diff options
Diffstat (limited to 'src')
144 files changed, 3591 insertions, 1895 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt index 895ee53f1..a5e71d879 100644 --- a/src/common/CMakeLists.txt +++ b/src/common/CMakeLists.txt | |||
| @@ -44,7 +44,6 @@ add_library(common STATIC | |||
| 44 | detached_tasks.cpp | 44 | detached_tasks.cpp |
| 45 | detached_tasks.h | 45 | detached_tasks.h |
| 46 | bit_field.h | 46 | bit_field.h |
| 47 | bit_set.h | ||
| 48 | cityhash.cpp | 47 | cityhash.cpp |
| 49 | cityhash.h | 48 | cityhash.h |
| 50 | color.h | 49 | color.h |
diff --git a/src/common/bit_set.h b/src/common/bit_set.h deleted file mode 100644 index 5cd1352b2..000000000 --- a/src/common/bit_set.h +++ /dev/null | |||
| @@ -1,244 +0,0 @@ | |||
| 1 | // This file is under the public domain. | ||
| 2 | |||
| 3 | #pragma once | ||
| 4 | |||
| 5 | #include <cstddef> | ||
| 6 | #ifdef _WIN32 | ||
| 7 | #include <intrin.h> | ||
| 8 | #endif | ||
| 9 | #include <initializer_list> | ||
| 10 | #include <new> | ||
| 11 | #include <type_traits> | ||
| 12 | #include "common/common_types.h" | ||
| 13 | |||
| 14 | // namespace avoids conflict with OS X Carbon; don't use BitSet<T> directly | ||
| 15 | namespace Common { | ||
| 16 | |||
| 17 | // Helper functions: | ||
| 18 | |||
| 19 | #ifdef _MSC_VER | ||
| 20 | template <typename T> | ||
| 21 | static inline int CountSetBits(T v) { | ||
| 22 | // from https://graphics.stanford.edu/~seander/bithacks.html | ||
| 23 | // GCC has this built in, but MSVC's intrinsic will only emit the actual | ||
| 24 | // POPCNT instruction, which we're not depending on | ||
| 25 | v = v - ((v >> 1) & (T) ~(T)0 / 3); | ||
| 26 | v = (v & (T) ~(T)0 / 15 * 3) + ((v >> 2) & (T) ~(T)0 / 15 * 3); | ||
| 27 | v = (v + (v >> 4)) & (T) ~(T)0 / 255 * 15; | ||
| 28 | return (T)(v * ((T) ~(T)0 / 255)) >> (sizeof(T) - 1) * 8; | ||
| 29 | } | ||
| 30 | static inline int LeastSignificantSetBit(u8 val) { | ||
| 31 | unsigned long index; | ||
| 32 | _BitScanForward(&index, val); | ||
| 33 | return (int)index; | ||
| 34 | } | ||
| 35 | static inline int LeastSignificantSetBit(u16 val) { | ||
| 36 | unsigned long index; | ||
| 37 | _BitScanForward(&index, val); | ||
| 38 | return (int)index; | ||
| 39 | } | ||
| 40 | static inline int LeastSignificantSetBit(u32 val) { | ||
| 41 | unsigned long index; | ||
| 42 | _BitScanForward(&index, val); | ||
| 43 | return (int)index; | ||
| 44 | } | ||
| 45 | static inline int LeastSignificantSetBit(u64 val) { | ||
| 46 | unsigned long index; | ||
| 47 | _BitScanForward64(&index, val); | ||
| 48 | return (int)index; | ||
| 49 | } | ||
| 50 | #else | ||
| 51 | static inline int CountSetBits(u8 val) { | ||
| 52 | return __builtin_popcount(val); | ||
| 53 | } | ||
| 54 | static inline int CountSetBits(u16 val) { | ||
| 55 | return __builtin_popcount(val); | ||
| 56 | } | ||
| 57 | static inline int CountSetBits(u32 val) { | ||
| 58 | return __builtin_popcount(val); | ||
| 59 | } | ||
| 60 | static inline int CountSetBits(u64 val) { | ||
| 61 | return __builtin_popcountll(val); | ||
| 62 | } | ||
| 63 | static inline int LeastSignificantSetBit(u8 val) { | ||
| 64 | return __builtin_ctz(val); | ||
| 65 | } | ||
| 66 | static inline int LeastSignificantSetBit(u16 val) { | ||
| 67 | return __builtin_ctz(val); | ||
| 68 | } | ||
| 69 | static inline int LeastSignificantSetBit(u32 val) { | ||
| 70 | return __builtin_ctz(val); | ||
| 71 | } | ||
| 72 | static inline int LeastSignificantSetBit(u64 val) { | ||
| 73 | return __builtin_ctzll(val); | ||
| 74 | } | ||
| 75 | #endif | ||
| 76 | |||
| 77 | // Similar to std::bitset, this is a class which encapsulates a bitset, i.e. | ||
| 78 | // using the set bits of an integer to represent a set of integers. Like that | ||
| 79 | // class, it acts like an array of bools: | ||
| 80 | // BitSet32 bs; | ||
| 81 | // bs[1] = true; | ||
| 82 | // but also like the underlying integer ([0] = least significant bit): | ||
| 83 | // BitSet32 bs2 = ...; | ||
| 84 | // bs = (bs ^ bs2) & BitSet32(0xffff); | ||
| 85 | // The following additional functionality is provided: | ||
| 86 | // - Construction using an initializer list. | ||
| 87 | // BitSet bs { 1, 2, 4, 8 }; | ||
| 88 | // - Efficiently iterating through the set bits: | ||
| 89 | // for (int i : bs) | ||
| 90 | // [i is the *index* of a set bit] | ||
| 91 | // (This uses the appropriate CPU instruction to find the next set bit in one | ||
| 92 | // operation.) | ||
| 93 | // - Counting set bits using .Count() - see comment on that method. | ||
| 94 | |||
| 95 | // TODO: use constexpr when MSVC gets out of the Dark Ages | ||
| 96 | |||
| 97 | template <typename IntTy> | ||
| 98 | class BitSet { | ||
| 99 | static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types"); | ||
| 100 | |||
| 101 | public: | ||
| 102 | // A reference to a particular bit, returned from operator[]. | ||
| 103 | class Ref { | ||
| 104 | public: | ||
| 105 | Ref(Ref&& other) : m_bs(other.m_bs), m_mask(other.m_mask) {} | ||
| 106 | Ref(BitSet* bs, IntTy mask) : m_bs(bs), m_mask(mask) {} | ||
| 107 | operator bool() const { | ||
| 108 | return (m_bs->m_val & m_mask) != 0; | ||
| 109 | } | ||
| 110 | bool operator=(bool set) { | ||
| 111 | m_bs->m_val = (m_bs->m_val & ~m_mask) | (set ? m_mask : 0); | ||
| 112 | return set; | ||
| 113 | } | ||
| 114 | |||
| 115 | private: | ||
| 116 | BitSet* m_bs; | ||
| 117 | IntTy m_mask; | ||
| 118 | }; | ||
| 119 | |||
| 120 | // A STL-like iterator is required to be able to use range-based for loops. | ||
| 121 | class Iterator { | ||
| 122 | public: | ||
| 123 | Iterator(const Iterator& other) : m_val(other.m_val), m_bit(other.m_bit) {} | ||
| 124 | Iterator(IntTy val) : m_val(val), m_bit(0) {} | ||
| 125 | Iterator& operator=(Iterator other) { | ||
| 126 | new (this) Iterator(other); | ||
| 127 | return *this; | ||
| 128 | } | ||
| 129 | int operator*() { | ||
| 130 | return m_bit + ComputeLsb(); | ||
| 131 | } | ||
| 132 | Iterator& operator++() { | ||
| 133 | int lsb = ComputeLsb(); | ||
| 134 | m_val >>= lsb + 1; | ||
| 135 | m_bit += lsb + 1; | ||
| 136 | m_has_lsb = false; | ||
| 137 | return *this; | ||
| 138 | } | ||
| 139 | Iterator operator++(int _) { | ||
| 140 | Iterator other(*this); | ||
| 141 | ++*this; | ||
| 142 | return other; | ||
| 143 | } | ||
| 144 | bool operator==(Iterator other) const { | ||
| 145 | return m_val == other.m_val; | ||
| 146 | } | ||
| 147 | bool operator!=(Iterator other) const { | ||
| 148 | return m_val != other.m_val; | ||
| 149 | } | ||
| 150 | |||
| 151 | private: | ||
| 152 | int ComputeLsb() { | ||
| 153 | if (!m_has_lsb) { | ||
| 154 | m_lsb = LeastSignificantSetBit(m_val); | ||
| 155 | m_has_lsb = true; | ||
| 156 | } | ||
| 157 | return m_lsb; | ||
| 158 | } | ||
| 159 | IntTy m_val; | ||
| 160 | int m_bit; | ||
| 161 | int m_lsb = -1; | ||
| 162 | bool m_has_lsb = false; | ||
| 163 | }; | ||
| 164 | |||
| 165 | BitSet() : m_val(0) {} | ||
| 166 | explicit BitSet(IntTy val) : m_val(val) {} | ||
| 167 | BitSet(std::initializer_list<int> init) { | ||
| 168 | m_val = 0; | ||
| 169 | for (int bit : init) | ||
| 170 | m_val |= (IntTy)1 << bit; | ||
| 171 | } | ||
| 172 | |||
| 173 | static BitSet AllTrue(std::size_t count) { | ||
| 174 | return BitSet(count == sizeof(IntTy) * 8 ? ~(IntTy)0 : (((IntTy)1 << count) - 1)); | ||
| 175 | } | ||
| 176 | |||
| 177 | Ref operator[](std::size_t bit) { | ||
| 178 | return Ref(this, (IntTy)1 << bit); | ||
| 179 | } | ||
| 180 | const Ref operator[](std::size_t bit) const { | ||
| 181 | return (*const_cast<BitSet*>(this))[bit]; | ||
| 182 | } | ||
| 183 | bool operator==(BitSet other) const { | ||
| 184 | return m_val == other.m_val; | ||
| 185 | } | ||
| 186 | bool operator!=(BitSet other) const { | ||
| 187 | return m_val != other.m_val; | ||
| 188 | } | ||
| 189 | bool operator<(BitSet other) const { | ||
| 190 | return m_val < other.m_val; | ||
| 191 | } | ||
| 192 | bool operator>(BitSet other) const { | ||
| 193 | return m_val > other.m_val; | ||
| 194 | } | ||
| 195 | BitSet operator|(BitSet other) const { | ||
| 196 | return BitSet(m_val | other.m_val); | ||
| 197 | } | ||
| 198 | BitSet operator&(BitSet other) const { | ||
| 199 | return BitSet(m_val & other.m_val); | ||
| 200 | } | ||
| 201 | BitSet operator^(BitSet other) const { | ||
| 202 | return BitSet(m_val ^ other.m_val); | ||
| 203 | } | ||
| 204 | BitSet operator~() const { | ||
| 205 | return BitSet(~m_val); | ||
| 206 | } | ||
| 207 | BitSet& operator|=(BitSet other) { | ||
| 208 | return *this = *this | other; | ||
| 209 | } | ||
| 210 | BitSet& operator&=(BitSet other) { | ||
| 211 | return *this = *this & other; | ||
| 212 | } | ||
| 213 | BitSet& operator^=(BitSet other) { | ||
| 214 | return *this = *this ^ other; | ||
| 215 | } | ||
| 216 | operator u32() = delete; | ||
| 217 | operator bool() { | ||
| 218 | return m_val != 0; | ||
| 219 | } | ||
| 220 | |||
| 221 | // Warning: Even though on modern CPUs this is a single fast instruction, | ||
| 222 | // Dolphin's official builds do not currently assume POPCNT support on x86, | ||
| 223 | // so slower explicit bit twiddling is generated. Still should generally | ||
| 224 | // be faster than a loop. | ||
| 225 | unsigned int Count() const { | ||
| 226 | return CountSetBits(m_val); | ||
| 227 | } | ||
| 228 | |||
| 229 | Iterator begin() const { | ||
| 230 | return Iterator(m_val); | ||
| 231 | } | ||
| 232 | Iterator end() const { | ||
| 233 | return Iterator(0); | ||
| 234 | } | ||
| 235 | |||
| 236 | IntTy m_val; | ||
| 237 | }; | ||
| 238 | |||
| 239 | } // namespace Common | ||
| 240 | |||
| 241 | typedef Common::BitSet<u8> BitSet8; | ||
| 242 | typedef Common::BitSet<u16> BitSet16; | ||
| 243 | typedef Common::BitSet<u32> BitSet32; | ||
| 244 | typedef Common::BitSet<u64> BitSet64; | ||
diff --git a/src/common/thread.cpp b/src/common/thread.cpp index 9e207118f..5144c0d9f 100644 --- a/src/common/thread.cpp +++ b/src/common/thread.cpp | |||
| @@ -25,23 +25,6 @@ | |||
| 25 | 25 | ||
| 26 | namespace Common { | 26 | namespace Common { |
| 27 | 27 | ||
| 28 | int CurrentThreadId() { | ||
| 29 | #ifdef _MSC_VER | ||
| 30 | return GetCurrentThreadId(); | ||
| 31 | #elif defined __APPLE__ | ||
| 32 | return mach_thread_self(); | ||
| 33 | #else | ||
| 34 | return 0; | ||
| 35 | #endif | ||
| 36 | } | ||
| 37 | |||
| 38 | #ifdef _WIN32 | ||
| 39 | // Supporting functions | ||
| 40 | void SleepCurrentThread(int ms) { | ||
| 41 | Sleep(ms); | ||
| 42 | } | ||
| 43 | #endif | ||
| 44 | |||
| 45 | #ifdef _MSC_VER | 28 | #ifdef _MSC_VER |
| 46 | 29 | ||
| 47 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { | 30 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { |
| @@ -62,7 +45,7 @@ void SwitchCurrentThread() { | |||
| 62 | 45 | ||
| 63 | // This is implemented much nicer in upcoming msvc++, see: | 46 | // This is implemented much nicer in upcoming msvc++, see: |
| 64 | // http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx | 47 | // http://msdn.microsoft.com/en-us/library/xcb2z8hs(VS.100).aspx |
| 65 | void SetCurrentThreadName(const char* szThreadName) { | 48 | void SetCurrentThreadName(const char* name) { |
| 66 | static const DWORD MS_VC_EXCEPTION = 0x406D1388; | 49 | static const DWORD MS_VC_EXCEPTION = 0x406D1388; |
| 67 | 50 | ||
| 68 | #pragma pack(push, 8) | 51 | #pragma pack(push, 8) |
| @@ -75,7 +58,7 @@ void SetCurrentThreadName(const char* szThreadName) { | |||
| 75 | #pragma pack(pop) | 58 | #pragma pack(pop) |
| 76 | 59 | ||
| 77 | info.dwType = 0x1000; | 60 | info.dwType = 0x1000; |
| 78 | info.szName = szThreadName; | 61 | info.szName = name; |
| 79 | info.dwThreadID = -1; // dwThreadID; | 62 | info.dwThreadID = -1; // dwThreadID; |
| 80 | info.dwFlags = 0; | 63 | info.dwFlags = 0; |
| 81 | 64 | ||
| @@ -107,10 +90,6 @@ void SetCurrentThreadAffinity(u32 mask) { | |||
| 107 | } | 90 | } |
| 108 | 91 | ||
| 109 | #ifndef _WIN32 | 92 | #ifndef _WIN32 |
| 110 | void SleepCurrentThread(int ms) { | ||
| 111 | usleep(1000 * ms); | ||
| 112 | } | ||
| 113 | |||
| 114 | void SwitchCurrentThread() { | 93 | void SwitchCurrentThread() { |
| 115 | usleep(1000 * 1); | 94 | usleep(1000 * 1); |
| 116 | } | 95 | } |
| @@ -118,15 +97,15 @@ void SwitchCurrentThread() { | |||
| 118 | 97 | ||
| 119 | // MinGW with the POSIX threading model does not support pthread_setname_np | 98 | // MinGW with the POSIX threading model does not support pthread_setname_np |
| 120 | #if !defined(_WIN32) || defined(_MSC_VER) | 99 | #if !defined(_WIN32) || defined(_MSC_VER) |
| 121 | void SetCurrentThreadName(const char* szThreadName) { | 100 | void SetCurrentThreadName(const char* name) { |
| 122 | #ifdef __APPLE__ | 101 | #ifdef __APPLE__ |
| 123 | pthread_setname_np(szThreadName); | 102 | pthread_setname_np(name); |
| 124 | #elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) | 103 | #elif defined(__Bitrig__) || defined(__DragonFly__) || defined(__FreeBSD__) || defined(__OpenBSD__) |
| 125 | pthread_set_name_np(pthread_self(), szThreadName); | 104 | pthread_set_name_np(pthread_self(), name); |
| 126 | #elif defined(__NetBSD__) | 105 | #elif defined(__NetBSD__) |
| 127 | pthread_setname_np(pthread_self(), "%s", (void*)szThreadName); | 106 | pthread_setname_np(pthread_self(), "%s", (void*)name); |
| 128 | #else | 107 | #else |
| 129 | pthread_setname_np(pthread_self(), szThreadName); | 108 | pthread_setname_np(pthread_self(), name); |
| 130 | #endif | 109 | #endif |
| 131 | } | 110 | } |
| 132 | #endif | 111 | #endif |
diff --git a/src/common/thread.h b/src/common/thread.h index 6cbdb96a3..2cf74452d 100644 --- a/src/common/thread.h +++ b/src/common/thread.h | |||
| @@ -13,15 +13,8 @@ | |||
| 13 | 13 | ||
| 14 | namespace Common { | 14 | namespace Common { |
| 15 | 15 | ||
| 16 | int CurrentThreadId(); | ||
| 17 | |||
| 18 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); | ||
| 19 | void SetCurrentThreadAffinity(u32 mask); | ||
| 20 | |||
| 21 | class Event { | 16 | class Event { |
| 22 | public: | 17 | public: |
| 23 | Event() : is_set(false) {} | ||
| 24 | |||
| 25 | void Set() { | 18 | void Set() { |
| 26 | std::lock_guard<std::mutex> lk(mutex); | 19 | std::lock_guard<std::mutex> lk(mutex); |
| 27 | if (!is_set) { | 20 | if (!is_set) { |
| @@ -53,14 +46,14 @@ public: | |||
| 53 | } | 46 | } |
| 54 | 47 | ||
| 55 | private: | 48 | private: |
| 56 | bool is_set; | 49 | bool is_set = false; |
| 57 | std::condition_variable condvar; | 50 | std::condition_variable condvar; |
| 58 | std::mutex mutex; | 51 | std::mutex mutex; |
| 59 | }; | 52 | }; |
| 60 | 53 | ||
| 61 | class Barrier { | 54 | class Barrier { |
| 62 | public: | 55 | public: |
| 63 | explicit Barrier(std::size_t count_) : count(count_), waiting(0), generation(0) {} | 56 | explicit Barrier(std::size_t count_) : count(count_) {} |
| 64 | 57 | ||
| 65 | /// Blocks until all "count" threads have called Sync() | 58 | /// Blocks until all "count" threads have called Sync() |
| 66 | void Sync() { | 59 | void Sync() { |
| @@ -80,12 +73,13 @@ public: | |||
| 80 | private: | 73 | private: |
| 81 | std::condition_variable condvar; | 74 | std::condition_variable condvar; |
| 82 | std::mutex mutex; | 75 | std::mutex mutex; |
| 83 | const std::size_t count; | 76 | std::size_t count; |
| 84 | std::size_t waiting; | 77 | std::size_t waiting = 0; |
| 85 | std::size_t generation; // Incremented once each time the barrier is used | 78 | std::size_t generation = 0; // Incremented once each time the barrier is used |
| 86 | }; | 79 | }; |
| 87 | 80 | ||
| 88 | void SleepCurrentThread(int ms); | 81 | void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask); |
| 82 | void SetCurrentThreadAffinity(u32 mask); | ||
| 89 | void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms | 83 | void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms |
| 90 | void SetCurrentThreadName(const char* name); | 84 | void SetCurrentThreadName(const char* name); |
| 91 | 85 | ||
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt index a355eaca6..e1f21a764 100644 --- a/src/core/CMakeLists.txt +++ b/src/core/CMakeLists.txt | |||
| @@ -12,6 +12,8 @@ add_library(core STATIC | |||
| 12 | core_timing.h | 12 | core_timing.h |
| 13 | core_timing_util.cpp | 13 | core_timing_util.cpp |
| 14 | core_timing_util.h | 14 | core_timing_util.h |
| 15 | cpu_core_manager.cpp | ||
| 16 | cpu_core_manager.h | ||
| 15 | crypto/aes_util.cpp | 17 | crypto/aes_util.cpp |
| 16 | crypto/aes_util.h | 18 | crypto/aes_util.h |
| 17 | crypto/encryption_layer.cpp | 19 | crypto/encryption_layer.cpp |
| @@ -156,6 +158,8 @@ add_library(core STATIC | |||
| 156 | hle/service/am/applets/applets.h | 158 | hle/service/am/applets/applets.h |
| 157 | hle/service/am/applets/software_keyboard.cpp | 159 | hle/service/am/applets/software_keyboard.cpp |
| 158 | hle/service/am/applets/software_keyboard.h | 160 | hle/service/am/applets/software_keyboard.h |
| 161 | hle/service/am/applets/stub_applet.cpp | ||
| 162 | hle/service/am/applets/stub_applet.h | ||
| 159 | hle/service/am/idle.cpp | 163 | hle/service/am/idle.cpp |
| 160 | hle/service/am/idle.h | 164 | hle/service/am/idle.h |
| 161 | hle/service/am/omm.cpp | 165 | hle/service/am/omm.cpp |
diff --git a/src/core/core.cpp b/src/core/core.cpp index 6c72fdf4a..795fabc65 100644 --- a/src/core/core.cpp +++ b/src/core/core.cpp | |||
| @@ -14,6 +14,7 @@ | |||
| 14 | #include "core/core.h" | 14 | #include "core/core.h" |
| 15 | #include "core/core_cpu.h" | 15 | #include "core/core_cpu.h" |
| 16 | #include "core/core_timing.h" | 16 | #include "core/core_timing.h" |
| 17 | #include "core/cpu_core_manager.h" | ||
| 17 | #include "core/file_sys/mode.h" | 18 | #include "core/file_sys/mode.h" |
| 18 | #include "core/file_sys/vfs_concat.h" | 19 | #include "core/file_sys/vfs_concat.h" |
| 19 | #include "core/file_sys/vfs_real.h" | 20 | #include "core/file_sys/vfs_real.h" |
| @@ -28,7 +29,6 @@ | |||
| 28 | #include "core/hle/service/sm/sm.h" | 29 | #include "core/hle/service/sm/sm.h" |
| 29 | #include "core/loader/loader.h" | 30 | #include "core/loader/loader.h" |
| 30 | #include "core/perf_stats.h" | 31 | #include "core/perf_stats.h" |
| 31 | #include "core/settings.h" | ||
| 32 | #include "core/telemetry_session.h" | 32 | #include "core/telemetry_session.h" |
| 33 | #include "frontend/applets/software_keyboard.h" | 33 | #include "frontend/applets/software_keyboard.h" |
| 34 | #include "video_core/debug_utils/debug_utils.h" | 34 | #include "video_core/debug_utils/debug_utils.h" |
| @@ -71,64 +71,22 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs, | |||
| 71 | 71 | ||
| 72 | return vfs->OpenFile(path, FileSys::Mode::Read); | 72 | return vfs->OpenFile(path, FileSys::Mode::Read); |
| 73 | } | 73 | } |
| 74 | |||
| 75 | /// Runs a CPU core while the system is powered on | ||
| 76 | void RunCpuCore(Cpu& cpu_state) { | ||
| 77 | while (Core::System::GetInstance().IsPoweredOn()) { | ||
| 78 | cpu_state.RunLoop(true); | ||
| 79 | } | ||
| 80 | } | ||
| 81 | } // Anonymous namespace | 74 | } // Anonymous namespace |
| 82 | 75 | ||
| 83 | struct System::Impl { | 76 | struct System::Impl { |
| 84 | Cpu& CurrentCpuCore() { | 77 | Cpu& CurrentCpuCore() { |
| 85 | if (Settings::values.use_multi_core) { | 78 | return cpu_core_manager.GetCurrentCore(); |
| 86 | const auto& search = thread_to_cpu.find(std::this_thread::get_id()); | ||
| 87 | ASSERT(search != thread_to_cpu.end()); | ||
| 88 | ASSERT(search->second); | ||
| 89 | return *search->second; | ||
| 90 | } | ||
| 91 | |||
| 92 | // Otherwise, use single-threaded mode active_core variable | ||
| 93 | return *cpu_cores[active_core]; | ||
| 94 | } | 79 | } |
| 95 | 80 | ||
| 96 | ResultStatus RunLoop(bool tight_loop) { | 81 | ResultStatus RunLoop(bool tight_loop) { |
| 97 | status = ResultStatus::Success; | 82 | status = ResultStatus::Success; |
| 98 | 83 | ||
| 99 | // Update thread_to_cpu in case Core 0 is run from a different host thread | 84 | cpu_core_manager.RunLoop(tight_loop); |
| 100 | thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get(); | ||
| 101 | |||
| 102 | if (GDBStub::IsServerEnabled()) { | ||
| 103 | GDBStub::HandlePacket(); | ||
| 104 | |||
| 105 | // If the loop is halted and we want to step, use a tiny (1) number of instructions to | ||
| 106 | // execute. Otherwise, get out of the loop function. | ||
| 107 | if (GDBStub::GetCpuHaltFlag()) { | ||
| 108 | if (GDBStub::GetCpuStepFlag()) { | ||
| 109 | tight_loop = false; | ||
| 110 | } else { | ||
| 111 | return ResultStatus::Success; | ||
| 112 | } | ||
| 113 | } | ||
| 114 | } | ||
| 115 | |||
| 116 | for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { | ||
| 117 | cpu_cores[active_core]->RunLoop(tight_loop); | ||
| 118 | if (Settings::values.use_multi_core) { | ||
| 119 | // Cores 1-3 are run on other threads in this mode | ||
| 120 | break; | ||
| 121 | } | ||
| 122 | } | ||
| 123 | |||
| 124 | if (GDBStub::IsServerEnabled()) { | ||
| 125 | GDBStub::SetCpuStepFlag(false); | ||
| 126 | } | ||
| 127 | 85 | ||
| 128 | return status; | 86 | return status; |
| 129 | } | 87 | } |
| 130 | 88 | ||
| 131 | ResultStatus Init(Frontend::EmuWindow& emu_window) { | 89 | ResultStatus Init(System& system, Frontend::EmuWindow& emu_window) { |
| 132 | LOG_DEBUG(HW_Memory, "initialized OK"); | 90 | LOG_DEBUG(HW_Memory, "initialized OK"); |
| 133 | 91 | ||
| 134 | CoreTiming::Init(); | 92 | CoreTiming::Init(); |
| @@ -145,12 +103,6 @@ struct System::Impl { | |||
| 145 | auto main_process = Kernel::Process::Create(kernel, "main"); | 103 | auto main_process = Kernel::Process::Create(kernel, "main"); |
| 146 | kernel.MakeCurrentProcess(main_process.get()); | 104 | kernel.MakeCurrentProcess(main_process.get()); |
| 147 | 105 | ||
| 148 | cpu_barrier = std::make_unique<CpuBarrier>(); | ||
| 149 | cpu_exclusive_monitor = Cpu::MakeExclusiveMonitor(cpu_cores.size()); | ||
| 150 | for (std::size_t index = 0; index < cpu_cores.size(); ++index) { | ||
| 151 | cpu_cores[index] = std::make_unique<Cpu>(*cpu_exclusive_monitor, *cpu_barrier, index); | ||
| 152 | } | ||
| 153 | |||
| 154 | telemetry_session = std::make_unique<Core::TelemetrySession>(); | 106 | telemetry_session = std::make_unique<Core::TelemetrySession>(); |
| 155 | service_manager = std::make_shared<Service::SM::ServiceManager>(); | 107 | service_manager = std::make_shared<Service::SM::ServiceManager>(); |
| 156 | 108 | ||
| @@ -164,17 +116,8 @@ struct System::Impl { | |||
| 164 | 116 | ||
| 165 | gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer()); | 117 | gpu_core = std::make_unique<Tegra::GPU>(renderer->Rasterizer()); |
| 166 | 118 | ||
| 167 | // Create threads for CPU cores 1-3, and build thread_to_cpu map | 119 | cpu_core_manager.Initialize(system); |
| 168 | // CPU core 0 is run on the main thread | 120 | is_powered_on = true; |
| 169 | thread_to_cpu[std::this_thread::get_id()] = cpu_cores[0].get(); | ||
| 170 | if (Settings::values.use_multi_core) { | ||
| 171 | for (std::size_t index = 0; index < cpu_core_threads.size(); ++index) { | ||
| 172 | cpu_core_threads[index] = | ||
| 173 | std::make_unique<std::thread>(RunCpuCore, std::ref(*cpu_cores[index + 1])); | ||
| 174 | thread_to_cpu[cpu_core_threads[index]->get_id()] = cpu_cores[index + 1].get(); | ||
| 175 | } | ||
| 176 | } | ||
| 177 | |||
| 178 | LOG_DEBUG(Core, "Initialized OK"); | 121 | LOG_DEBUG(Core, "Initialized OK"); |
| 179 | 122 | ||
| 180 | // Reset counters and set time origin to current frame | 123 | // Reset counters and set time origin to current frame |
| @@ -184,7 +127,8 @@ struct System::Impl { | |||
| 184 | return ResultStatus::Success; | 127 | return ResultStatus::Success; |
| 185 | } | 128 | } |
| 186 | 129 | ||
| 187 | ResultStatus Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | 130 | ResultStatus Load(System& system, Frontend::EmuWindow& emu_window, |
| 131 | const std::string& filepath) { | ||
| 188 | app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); | 132 | app_loader = Loader::GetLoader(GetGameFileFromPath(virtual_filesystem, filepath)); |
| 189 | 133 | ||
| 190 | if (!app_loader) { | 134 | if (!app_loader) { |
| @@ -201,7 +145,7 @@ struct System::Impl { | |||
| 201 | return ResultStatus::ErrorSystemMode; | 145 | return ResultStatus::ErrorSystemMode; |
| 202 | } | 146 | } |
| 203 | 147 | ||
| 204 | ResultStatus init_result{Init(emu_window)}; | 148 | ResultStatus init_result{Init(system, emu_window)}; |
| 205 | if (init_result != ResultStatus::Success) { | 149 | if (init_result != ResultStatus::Success) { |
| 206 | LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", | 150 | LOG_CRITICAL(Core, "Failed to initialize system (Error {})!", |
| 207 | static_cast<int>(init_result)); | 151 | static_cast<int>(init_result)); |
| @@ -231,6 +175,8 @@ struct System::Impl { | |||
| 231 | Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", | 175 | Telemetry().AddField(Telemetry::FieldType::Performance, "Shutdown_Frametime", |
| 232 | perf_results.frametime * 1000.0); | 176 | perf_results.frametime * 1000.0); |
| 233 | 177 | ||
| 178 | is_powered_on = false; | ||
| 179 | |||
| 234 | // Shutdown emulation session | 180 | // Shutdown emulation session |
| 235 | renderer.reset(); | 181 | renderer.reset(); |
| 236 | GDBStub::Shutdown(); | 182 | GDBStub::Shutdown(); |
| @@ -240,19 +186,7 @@ struct System::Impl { | |||
| 240 | gpu_core.reset(); | 186 | gpu_core.reset(); |
| 241 | 187 | ||
| 242 | // Close all CPU/threading state | 188 | // Close all CPU/threading state |
| 243 | cpu_barrier->NotifyEnd(); | 189 | cpu_core_manager.Shutdown(); |
| 244 | if (Settings::values.use_multi_core) { | ||
| 245 | for (auto& thread : cpu_core_threads) { | ||
| 246 | thread->join(); | ||
| 247 | thread.reset(); | ||
| 248 | } | ||
| 249 | } | ||
| 250 | thread_to_cpu.clear(); | ||
| 251 | for (auto& cpu_core : cpu_cores) { | ||
| 252 | cpu_core.reset(); | ||
| 253 | } | ||
| 254 | cpu_exclusive_monitor.reset(); | ||
| 255 | cpu_barrier.reset(); | ||
| 256 | 190 | ||
| 257 | // Shutdown kernel and core timing | 191 | // Shutdown kernel and core timing |
| 258 | kernel.Shutdown(); | 192 | kernel.Shutdown(); |
| @@ -289,11 +223,8 @@ struct System::Impl { | |||
| 289 | std::unique_ptr<VideoCore::RendererBase> renderer; | 223 | std::unique_ptr<VideoCore::RendererBase> renderer; |
| 290 | std::unique_ptr<Tegra::GPU> gpu_core; | 224 | std::unique_ptr<Tegra::GPU> gpu_core; |
| 291 | std::shared_ptr<Tegra::DebugContext> debug_context; | 225 | std::shared_ptr<Tegra::DebugContext> debug_context; |
| 292 | std::unique_ptr<ExclusiveMonitor> cpu_exclusive_monitor; | 226 | CpuCoreManager cpu_core_manager; |
| 293 | std::unique_ptr<CpuBarrier> cpu_barrier; | 227 | bool is_powered_on = false; |
| 294 | std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cpu_cores; | ||
| 295 | std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> cpu_core_threads; | ||
| 296 | std::size_t active_core{}; ///< Active core, only used in single thread mode | ||
| 297 | 228 | ||
| 298 | /// Frontend applets | 229 | /// Frontend applets |
| 299 | std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; | 230 | std::unique_ptr<Core::Frontend::SoftwareKeyboardApplet> software_keyboard; |
| @@ -307,9 +238,6 @@ struct System::Impl { | |||
| 307 | ResultStatus status = ResultStatus::Success; | 238 | ResultStatus status = ResultStatus::Success; |
| 308 | std::string status_details = ""; | 239 | std::string status_details = ""; |
| 309 | 240 | ||
| 310 | /// Map of guest threads to CPU cores | ||
| 311 | std::map<std::thread::id, Cpu*> thread_to_cpu; | ||
| 312 | |||
| 313 | Core::PerfStats perf_stats; | 241 | Core::PerfStats perf_stats; |
| 314 | Core::FrameLimiter frame_limiter; | 242 | Core::FrameLimiter frame_limiter; |
| 315 | }; | 243 | }; |
| @@ -334,17 +262,15 @@ System::ResultStatus System::SingleStep() { | |||
| 334 | } | 262 | } |
| 335 | 263 | ||
| 336 | void System::InvalidateCpuInstructionCaches() { | 264 | void System::InvalidateCpuInstructionCaches() { |
| 337 | for (auto& cpu : impl->cpu_cores) { | 265 | impl->cpu_core_manager.InvalidateAllInstructionCaches(); |
| 338 | cpu->ArmInterface().ClearInstructionCache(); | ||
| 339 | } | ||
| 340 | } | 266 | } |
| 341 | 267 | ||
| 342 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { | 268 | System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { |
| 343 | return impl->Load(emu_window, filepath); | 269 | return impl->Load(*this, emu_window, filepath); |
| 344 | } | 270 | } |
| 345 | 271 | ||
| 346 | bool System::IsPoweredOn() const { | 272 | bool System::IsPoweredOn() const { |
| 347 | return impl->cpu_barrier && impl->cpu_barrier->IsAlive(); | 273 | return impl->is_powered_on; |
| 348 | } | 274 | } |
| 349 | 275 | ||
| 350 | void System::PrepareReschedule() { | 276 | void System::PrepareReschedule() { |
| @@ -408,21 +334,20 @@ const ARM_Interface& System::ArmInterface(std::size_t core_index) const { | |||
| 408 | } | 334 | } |
| 409 | 335 | ||
| 410 | Cpu& System::CpuCore(std::size_t core_index) { | 336 | Cpu& System::CpuCore(std::size_t core_index) { |
| 411 | ASSERT(core_index < NUM_CPU_CORES); | 337 | return impl->cpu_core_manager.GetCore(core_index); |
| 412 | return *impl->cpu_cores[core_index]; | ||
| 413 | } | 338 | } |
| 414 | 339 | ||
| 415 | const Cpu& System::CpuCore(std::size_t core_index) const { | 340 | const Cpu& System::CpuCore(std::size_t core_index) const { |
| 416 | ASSERT(core_index < NUM_CPU_CORES); | 341 | ASSERT(core_index < NUM_CPU_CORES); |
| 417 | return *impl->cpu_cores[core_index]; | 342 | return impl->cpu_core_manager.GetCore(core_index); |
| 418 | } | 343 | } |
| 419 | 344 | ||
| 420 | ExclusiveMonitor& System::Monitor() { | 345 | ExclusiveMonitor& System::Monitor() { |
| 421 | return *impl->cpu_exclusive_monitor; | 346 | return impl->cpu_core_manager.GetExclusiveMonitor(); |
| 422 | } | 347 | } |
| 423 | 348 | ||
| 424 | const ExclusiveMonitor& System::Monitor() const { | 349 | const ExclusiveMonitor& System::Monitor() const { |
| 425 | return *impl->cpu_exclusive_monitor; | 350 | return impl->cpu_core_manager.GetExclusiveMonitor(); |
| 426 | } | 351 | } |
| 427 | 352 | ||
| 428 | Tegra::GPU& System::GPU() { | 353 | Tegra::GPU& System::GPU() { |
| @@ -506,7 +431,7 @@ const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() cons | |||
| 506 | } | 431 | } |
| 507 | 432 | ||
| 508 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { | 433 | System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { |
| 509 | return impl->Init(emu_window); | 434 | return impl->Init(*this, emu_window); |
| 510 | } | 435 | } |
| 511 | 436 | ||
| 512 | void System::Shutdown() { | 437 | void System::Shutdown() { |
diff --git a/src/core/cpu_core_manager.cpp b/src/core/cpu_core_manager.cpp new file mode 100644 index 000000000..769a6fefa --- /dev/null +++ b/src/core/cpu_core_manager.cpp | |||
| @@ -0,0 +1,142 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/assert.h" | ||
| 6 | #include "core/arm/exclusive_monitor.h" | ||
| 7 | #include "core/core.h" | ||
| 8 | #include "core/core_cpu.h" | ||
| 9 | #include "core/cpu_core_manager.h" | ||
| 10 | #include "core/gdbstub/gdbstub.h" | ||
| 11 | #include "core/settings.h" | ||
| 12 | |||
| 13 | namespace Core { | ||
| 14 | namespace { | ||
| 15 | void RunCpuCore(const System& system, Cpu& cpu_state) { | ||
| 16 | while (system.IsPoweredOn()) { | ||
| 17 | cpu_state.RunLoop(true); | ||
| 18 | } | ||
| 19 | } | ||
| 20 | } // Anonymous namespace | ||
| 21 | |||
| 22 | CpuCoreManager::CpuCoreManager() = default; | ||
| 23 | CpuCoreManager::~CpuCoreManager() = default; | ||
| 24 | |||
| 25 | void CpuCoreManager::Initialize(System& system) { | ||
| 26 | barrier = std::make_unique<CpuBarrier>(); | ||
| 27 | exclusive_monitor = Cpu::MakeExclusiveMonitor(cores.size()); | ||
| 28 | |||
| 29 | for (std::size_t index = 0; index < cores.size(); ++index) { | ||
| 30 | cores[index] = std::make_unique<Cpu>(*exclusive_monitor, *barrier, index); | ||
| 31 | } | ||
| 32 | |||
| 33 | // Create threads for CPU cores 1-3, and build thread_to_cpu map | ||
| 34 | // CPU core 0 is run on the main thread | ||
| 35 | thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); | ||
| 36 | if (!Settings::values.use_multi_core) { | ||
| 37 | return; | ||
| 38 | } | ||
| 39 | |||
| 40 | for (std::size_t index = 0; index < core_threads.size(); ++index) { | ||
| 41 | core_threads[index] = std::make_unique<std::thread>(RunCpuCore, std::cref(system), | ||
| 42 | std::ref(*cores[index + 1])); | ||
| 43 | thread_to_cpu[core_threads[index]->get_id()] = cores[index + 1].get(); | ||
| 44 | } | ||
| 45 | } | ||
| 46 | |||
| 47 | void CpuCoreManager::Shutdown() { | ||
| 48 | barrier->NotifyEnd(); | ||
| 49 | if (Settings::values.use_multi_core) { | ||
| 50 | for (auto& thread : core_threads) { | ||
| 51 | thread->join(); | ||
| 52 | thread.reset(); | ||
| 53 | } | ||
| 54 | } | ||
| 55 | |||
| 56 | thread_to_cpu.clear(); | ||
| 57 | for (auto& cpu_core : cores) { | ||
| 58 | cpu_core.reset(); | ||
| 59 | } | ||
| 60 | |||
| 61 | exclusive_monitor.reset(); | ||
| 62 | barrier.reset(); | ||
| 63 | } | ||
| 64 | |||
| 65 | Cpu& CpuCoreManager::GetCore(std::size_t index) { | ||
| 66 | return *cores.at(index); | ||
| 67 | } | ||
| 68 | |||
| 69 | const Cpu& CpuCoreManager::GetCore(std::size_t index) const { | ||
| 70 | return *cores.at(index); | ||
| 71 | } | ||
| 72 | |||
| 73 | ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() { | ||
| 74 | return *exclusive_monitor; | ||
| 75 | } | ||
| 76 | |||
| 77 | const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const { | ||
| 78 | return *exclusive_monitor; | ||
| 79 | } | ||
| 80 | |||
| 81 | Cpu& CpuCoreManager::GetCurrentCore() { | ||
| 82 | if (Settings::values.use_multi_core) { | ||
| 83 | const auto& search = thread_to_cpu.find(std::this_thread::get_id()); | ||
| 84 | ASSERT(search != thread_to_cpu.end()); | ||
| 85 | ASSERT(search->second); | ||
| 86 | return *search->second; | ||
| 87 | } | ||
| 88 | |||
| 89 | // Otherwise, use single-threaded mode active_core variable | ||
| 90 | return *cores[active_core]; | ||
| 91 | } | ||
| 92 | |||
| 93 | const Cpu& CpuCoreManager::GetCurrentCore() const { | ||
| 94 | if (Settings::values.use_multi_core) { | ||
| 95 | const auto& search = thread_to_cpu.find(std::this_thread::get_id()); | ||
| 96 | ASSERT(search != thread_to_cpu.end()); | ||
| 97 | ASSERT(search->second); | ||
| 98 | return *search->second; | ||
| 99 | } | ||
| 100 | |||
| 101 | // Otherwise, use single-threaded mode active_core variable | ||
| 102 | return *cores[active_core]; | ||
| 103 | } | ||
| 104 | |||
| 105 | void CpuCoreManager::RunLoop(bool tight_loop) { | ||
| 106 | // Update thread_to_cpu in case Core 0 is run from a different host thread | ||
| 107 | thread_to_cpu[std::this_thread::get_id()] = cores[0].get(); | ||
| 108 | |||
| 109 | if (GDBStub::IsServerEnabled()) { | ||
| 110 | GDBStub::HandlePacket(); | ||
| 111 | |||
| 112 | // If the loop is halted and we want to step, use a tiny (1) number of instructions to | ||
| 113 | // execute. Otherwise, get out of the loop function. | ||
| 114 | if (GDBStub::GetCpuHaltFlag()) { | ||
| 115 | if (GDBStub::GetCpuStepFlag()) { | ||
| 116 | tight_loop = false; | ||
| 117 | } else { | ||
| 118 | return; | ||
| 119 | } | ||
| 120 | } | ||
| 121 | } | ||
| 122 | |||
| 123 | for (active_core = 0; active_core < NUM_CPU_CORES; ++active_core) { | ||
| 124 | cores[active_core]->RunLoop(tight_loop); | ||
| 125 | if (Settings::values.use_multi_core) { | ||
| 126 | // Cores 1-3 are run on other threads in this mode | ||
| 127 | break; | ||
| 128 | } | ||
| 129 | } | ||
| 130 | |||
| 131 | if (GDBStub::IsServerEnabled()) { | ||
| 132 | GDBStub::SetCpuStepFlag(false); | ||
| 133 | } | ||
| 134 | } | ||
| 135 | |||
| 136 | void CpuCoreManager::InvalidateAllInstructionCaches() { | ||
| 137 | for (auto& cpu : cores) { | ||
| 138 | cpu->ArmInterface().ClearInstructionCache(); | ||
| 139 | } | ||
| 140 | } | ||
| 141 | |||
| 142 | } // namespace Core | ||
diff --git a/src/core/cpu_core_manager.h b/src/core/cpu_core_manager.h new file mode 100644 index 000000000..a4d70ec56 --- /dev/null +++ b/src/core/cpu_core_manager.h | |||
| @@ -0,0 +1,59 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include <array> | ||
| 8 | #include <map> | ||
| 9 | #include <memory> | ||
| 10 | #include <thread> | ||
| 11 | |||
| 12 | namespace Core { | ||
| 13 | |||
| 14 | class Cpu; | ||
| 15 | class CpuBarrier; | ||
| 16 | class ExclusiveMonitor; | ||
| 17 | class System; | ||
| 18 | |||
| 19 | class CpuCoreManager { | ||
| 20 | public: | ||
| 21 | CpuCoreManager(); | ||
| 22 | CpuCoreManager(const CpuCoreManager&) = delete; | ||
| 23 | CpuCoreManager(CpuCoreManager&&) = delete; | ||
| 24 | |||
| 25 | ~CpuCoreManager(); | ||
| 26 | |||
| 27 | CpuCoreManager& operator=(const CpuCoreManager&) = delete; | ||
| 28 | CpuCoreManager& operator=(CpuCoreManager&&) = delete; | ||
| 29 | |||
| 30 | void Initialize(System& system); | ||
| 31 | void Shutdown(); | ||
| 32 | |||
| 33 | Cpu& GetCore(std::size_t index); | ||
| 34 | const Cpu& GetCore(std::size_t index) const; | ||
| 35 | |||
| 36 | Cpu& GetCurrentCore(); | ||
| 37 | const Cpu& GetCurrentCore() const; | ||
| 38 | |||
| 39 | ExclusiveMonitor& GetExclusiveMonitor(); | ||
| 40 | const ExclusiveMonitor& GetExclusiveMonitor() const; | ||
| 41 | |||
| 42 | void RunLoop(bool tight_loop); | ||
| 43 | |||
| 44 | void InvalidateAllInstructionCaches(); | ||
| 45 | |||
| 46 | private: | ||
| 47 | static constexpr std::size_t NUM_CPU_CORES = 4; | ||
| 48 | |||
| 49 | std::unique_ptr<ExclusiveMonitor> exclusive_monitor; | ||
| 50 | std::unique_ptr<CpuBarrier> barrier; | ||
| 51 | std::array<std::unique_ptr<Cpu>, NUM_CPU_CORES> cores; | ||
| 52 | std::array<std::unique_ptr<std::thread>, NUM_CPU_CORES - 1> core_threads; | ||
| 53 | std::size_t active_core{}; ///< Active core, only used in single thread mode | ||
| 54 | |||
| 55 | /// Map of guest threads to CPU cores | ||
| 56 | std::map<std::thread::id, Cpu*> thread_to_cpu; | ||
| 57 | }; | ||
| 58 | |||
| 59 | } // namespace Core | ||
diff --git a/src/core/file_sys/control_metadata.cpp b/src/core/file_sys/control_metadata.cpp index c8fa912bf..e065e592f 100644 --- a/src/core/file_sys/control_metadata.cpp +++ b/src/core/file_sys/control_metadata.cpp | |||
| @@ -8,13 +8,23 @@ | |||
| 8 | 8 | ||
| 9 | namespace FileSys { | 9 | namespace FileSys { |
| 10 | 10 | ||
| 11 | const std::array<const char*, 15> LANGUAGE_NAMES = { | 11 | const std::array<const char*, 15> LANGUAGE_NAMES{{ |
| 12 | "AmericanEnglish", "BritishEnglish", "Japanese", | 12 | "AmericanEnglish", |
| 13 | "French", "German", "LatinAmericanSpanish", | 13 | "BritishEnglish", |
| 14 | "Spanish", "Italian", "Dutch", | 14 | "Japanese", |
| 15 | "CanadianFrench", "Portugese", "Russian", | 15 | "French", |
| 16 | "Korean", "Taiwanese", "Chinese", | 16 | "German", |
| 17 | }; | 17 | "LatinAmericanSpanish", |
| 18 | "Spanish", | ||
| 19 | "Italian", | ||
| 20 | "Dutch", | ||
| 21 | "CanadianFrench", | ||
| 22 | "Portuguese", | ||
| 23 | "Russian", | ||
| 24 | "Korean", | ||
| 25 | "Taiwanese", | ||
| 26 | "Chinese", | ||
| 27 | }}; | ||
| 18 | 28 | ||
| 19 | std::string LanguageEntry::GetApplicationName() const { | 29 | std::string LanguageEntry::GetApplicationName() const { |
| 20 | return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), | 30 | return Common::StringFromFixedZeroTerminatedBuffer(application_name.data(), |
diff --git a/src/core/file_sys/patch_manager.cpp b/src/core/file_sys/patch_manager.cpp index 8d062eb3e..e8df08724 100644 --- a/src/core/file_sys/patch_manager.cpp +++ b/src/core/file_sys/patch_manager.cpp | |||
| @@ -26,6 +26,11 @@ namespace FileSys { | |||
| 26 | constexpr u64 SINGLE_BYTE_MODULUS = 0x100; | 26 | constexpr u64 SINGLE_BYTE_MODULUS = 0x100; |
| 27 | constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; | 27 | constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; |
| 28 | 28 | ||
| 29 | constexpr std::array<const char*, 14> EXEFS_FILE_NAMES{ | ||
| 30 | "main", "main.npdm", "rtld", "sdk", "subsdk0", "subsdk1", "subsdk2", | ||
| 31 | "subsdk3", "subsdk4", "subsdk5", "subsdk6", "subsdk7", "subsdk8", "subsdk9", | ||
| 32 | }; | ||
| 33 | |||
| 29 | struct NSOBuildHeader { | 34 | struct NSOBuildHeader { |
| 30 | u32_le magic; | 35 | u32_le magic; |
| 31 | INSERT_PADDING_BYTES(0x3C); | 36 | INSERT_PADDING_BYTES(0x3C); |
| @@ -57,6 +62,15 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { | |||
| 57 | if (exefs == nullptr) | 62 | if (exefs == nullptr) |
| 58 | return exefs; | 63 | return exefs; |
| 59 | 64 | ||
| 65 | if (Settings::values.dump_exefs) { | ||
| 66 | LOG_INFO(Loader, "Dumping ExeFS for title_id={:016X}", title_id); | ||
| 67 | const auto dump_dir = Service::FileSystem::GetModificationDumpRoot(title_id); | ||
| 68 | if (dump_dir != nullptr) { | ||
| 69 | const auto exefs_dir = GetOrCreateDirectoryRelative(dump_dir, "/exefs"); | ||
| 70 | VfsRawCopyD(exefs, exefs_dir); | ||
| 71 | } | ||
| 72 | } | ||
| 73 | |||
| 60 | const auto installed = Service::FileSystem::GetUnionContents(); | 74 | const auto installed = Service::FileSystem::GetUnionContents(); |
| 61 | 75 | ||
| 62 | // Game Updates | 76 | // Game Updates |
| @@ -70,6 +84,30 @@ VirtualDir PatchManager::PatchExeFS(VirtualDir exefs) const { | |||
| 70 | exefs = update->GetExeFS(); | 84 | exefs = update->GetExeFS(); |
| 71 | } | 85 | } |
| 72 | 86 | ||
| 87 | // LayeredExeFS | ||
| 88 | const auto load_dir = Service::FileSystem::GetModificationLoadRoot(title_id); | ||
| 89 | if (load_dir != nullptr && load_dir->GetSize() > 0) { | ||
| 90 | auto patch_dirs = load_dir->GetSubdirectories(); | ||
| 91 | std::sort( | ||
| 92 | patch_dirs.begin(), patch_dirs.end(), | ||
| 93 | [](const VirtualDir& l, const VirtualDir& r) { return l->GetName() < r->GetName(); }); | ||
| 94 | |||
| 95 | std::vector<VirtualDir> layers; | ||
| 96 | layers.reserve(patch_dirs.size() + 1); | ||
| 97 | for (const auto& subdir : patch_dirs) { | ||
| 98 | auto exefs_dir = subdir->GetSubdirectory("exefs"); | ||
| 99 | if (exefs_dir != nullptr) | ||
| 100 | layers.push_back(std::move(exefs_dir)); | ||
| 101 | } | ||
| 102 | layers.push_back(exefs); | ||
| 103 | |||
| 104 | auto layered = LayeredVfsDirectory::MakeLayeredDirectory(std::move(layers)); | ||
| 105 | if (layered != nullptr) { | ||
| 106 | LOG_INFO(Loader, " ExeFS: LayeredExeFS patches applied successfully"); | ||
| 107 | exefs = std::move(layered); | ||
| 108 | } | ||
| 109 | } | ||
| 110 | |||
| 73 | return exefs; | 111 | return exefs; |
| 74 | } | 112 | } |
| 75 | 113 | ||
| @@ -314,18 +352,25 @@ std::map<std::string, std::string, std::less<>> PatchManager::GetPatchVersionNam | |||
| 314 | if (IsDirValidAndNonEmpty(exefs_dir)) { | 352 | if (IsDirValidAndNonEmpty(exefs_dir)) { |
| 315 | bool ips = false; | 353 | bool ips = false; |
| 316 | bool ipswitch = false; | 354 | bool ipswitch = false; |
| 355 | bool layeredfs = false; | ||
| 317 | 356 | ||
| 318 | for (const auto& file : exefs_dir->GetFiles()) { | 357 | for (const auto& file : exefs_dir->GetFiles()) { |
| 319 | if (file->GetExtension() == "ips") | 358 | if (file->GetExtension() == "ips") { |
| 320 | ips = true; | 359 | ips = true; |
| 321 | else if (file->GetExtension() == "pchtxt") | 360 | } else if (file->GetExtension() == "pchtxt") { |
| 322 | ipswitch = true; | 361 | ipswitch = true; |
| 362 | } else if (std::find(EXEFS_FILE_NAMES.begin(), EXEFS_FILE_NAMES.end(), | ||
| 363 | file->GetName()) != EXEFS_FILE_NAMES.end()) { | ||
| 364 | layeredfs = true; | ||
| 365 | } | ||
| 323 | } | 366 | } |
| 324 | 367 | ||
| 325 | if (ips) | 368 | if (ips) |
| 326 | AppendCommaIfNotEmpty(types, "IPS"); | 369 | AppendCommaIfNotEmpty(types, "IPS"); |
| 327 | if (ipswitch) | 370 | if (ipswitch) |
| 328 | AppendCommaIfNotEmpty(types, "IPSwitch"); | 371 | AppendCommaIfNotEmpty(types, "IPSwitch"); |
| 372 | if (layeredfs) | ||
| 373 | AppendCommaIfNotEmpty(types, "LayeredExeFS"); | ||
| 329 | } | 374 | } |
| 330 | if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs"))) | 375 | if (IsDirValidAndNonEmpty(mod->GetSubdirectory("romfs"))) |
| 331 | AppendCommaIfNotEmpty(types, "LayeredFS"); | 376 | AppendCommaIfNotEmpty(types, "LayeredFS"); |
diff --git a/src/core/file_sys/registered_cache.cpp b/src/core/file_sys/registered_cache.cpp index a3f8f2f73..07c3af64a 100644 --- a/src/core/file_sys/registered_cache.cpp +++ b/src/core/file_sys/registered_cache.cpp | |||
| @@ -381,22 +381,22 @@ std::vector<RegisteredCacheEntry> RegisteredCache::ListEntriesFilter( | |||
| 381 | return out; | 381 | return out; |
| 382 | } | 382 | } |
| 383 | 383 | ||
| 384 | static std::shared_ptr<NCA> GetNCAFromNSPForID(std::shared_ptr<NSP> nsp, const NcaID& id) { | 384 | static std::shared_ptr<NCA> GetNCAFromNSPForID(const NSP& nsp, const NcaID& id) { |
| 385 | const auto file = nsp->GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); | 385 | const auto file = nsp.GetFile(fmt::format("{}.nca", Common::HexArrayToString(id, false))); |
| 386 | if (file == nullptr) | 386 | if (file == nullptr) |
| 387 | return nullptr; | 387 | return nullptr; |
| 388 | return std::make_shared<NCA>(file); | 388 | return std::make_shared<NCA>(file); |
| 389 | } | 389 | } |
| 390 | 390 | ||
| 391 | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists, | 391 | InstallResult RegisteredCache::InstallEntry(const XCI& xci, bool overwrite_if_exists, |
| 392 | const VfsCopyFunction& copy) { | 392 | const VfsCopyFunction& copy) { |
| 393 | return InstallEntry(xci->GetSecurePartitionNSP(), overwrite_if_exists, copy); | 393 | return InstallEntry(*xci.GetSecurePartitionNSP(), overwrite_if_exists, copy); |
| 394 | } | 394 | } |
| 395 | 395 | ||
| 396 | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists, | 396 | InstallResult RegisteredCache::InstallEntry(const NSP& nsp, bool overwrite_if_exists, |
| 397 | const VfsCopyFunction& copy) { | 397 | const VfsCopyFunction& copy) { |
| 398 | const auto& ncas = nsp->GetNCAsCollapsed(); | 398 | const auto ncas = nsp.GetNCAsCollapsed(); |
| 399 | const auto& meta_iter = std::find_if(ncas.begin(), ncas.end(), [](std::shared_ptr<NCA> nca) { | 399 | const auto meta_iter = std::find_if(ncas.begin(), ncas.end(), [](const auto& nca) { |
| 400 | return nca->GetType() == NCAContentType::Meta; | 400 | return nca->GetType() == NCAContentType::Meta; |
| 401 | }); | 401 | }); |
| 402 | 402 | ||
| @@ -410,7 +410,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw | |||
| 410 | const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); | 410 | const auto meta_id_raw = (*meta_iter)->GetName().substr(0, 32); |
| 411 | const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); | 411 | const auto meta_id = Common::HexStringToArray<16>(meta_id_raw); |
| 412 | 412 | ||
| 413 | const auto res = RawInstallNCA(*meta_iter, copy, overwrite_if_exists, meta_id); | 413 | const auto res = RawInstallNCA(**meta_iter, copy, overwrite_if_exists, meta_id); |
| 414 | if (res != InstallResult::Success) | 414 | if (res != InstallResult::Success) |
| 415 | return res; | 415 | return res; |
| 416 | 416 | ||
| @@ -422,7 +422,7 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw | |||
| 422 | const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); | 422 | const auto nca = GetNCAFromNSPForID(nsp, record.nca_id); |
| 423 | if (nca == nullptr) | 423 | if (nca == nullptr) |
| 424 | return InstallResult::ErrorCopyFailed; | 424 | return InstallResult::ErrorCopyFailed; |
| 425 | const auto res2 = RawInstallNCA(nca, copy, overwrite_if_exists, record.nca_id); | 425 | const auto res2 = RawInstallNCA(*nca, copy, overwrite_if_exists, record.nca_id); |
| 426 | if (res2 != InstallResult::Success) | 426 | if (res2 != InstallResult::Success) |
| 427 | return res2; | 427 | return res2; |
| 428 | } | 428 | } |
| @@ -431,21 +431,21 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overw | |||
| 431 | return InstallResult::Success; | 431 | return InstallResult::Success; |
| 432 | } | 432 | } |
| 433 | 433 | ||
| 434 | InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | 434 | InstallResult RegisteredCache::InstallEntry(const NCA& nca, TitleType type, |
| 435 | bool overwrite_if_exists, const VfsCopyFunction& copy) { | 435 | bool overwrite_if_exists, const VfsCopyFunction& copy) { |
| 436 | CNMTHeader header{ | 436 | CNMTHeader header{ |
| 437 | nca->GetTitleId(), ///< Title ID | 437 | nca.GetTitleId(), ///< Title ID |
| 438 | 0, ///< Ignore/Default title version | 438 | 0, ///< Ignore/Default title version |
| 439 | type, ///< Type | 439 | type, ///< Type |
| 440 | {}, ///< Padding | 440 | {}, ///< Padding |
| 441 | 0x10, ///< Default table offset | 441 | 0x10, ///< Default table offset |
| 442 | 1, ///< 1 Content Entry | 442 | 1, ///< 1 Content Entry |
| 443 | 0, ///< No Meta Entries | 443 | 0, ///< No Meta Entries |
| 444 | {}, ///< Padding | 444 | {}, ///< Padding |
| 445 | }; | 445 | }; |
| 446 | OptionalHeader opt_header{0, 0}; | 446 | OptionalHeader opt_header{0, 0}; |
| 447 | ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca->GetType()), {}}; | 447 | ContentRecord c_rec{{}, {}, {}, GetCRTypeFromNCAType(nca.GetType()), {}}; |
| 448 | const auto& data = nca->GetBaseFile()->ReadBytes(0x100000); | 448 | const auto& data = nca.GetBaseFile()->ReadBytes(0x100000); |
| 449 | mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); | 449 | mbedtls_sha256(data.data(), data.size(), c_rec.hash.data(), 0); |
| 450 | memcpy(&c_rec.nca_id, &c_rec.hash, 16); | 450 | memcpy(&c_rec.nca_id, &c_rec.hash, 16); |
| 451 | const CNMT new_cnmt(header, opt_header, {c_rec}, {}); | 451 | const CNMT new_cnmt(header, opt_header, {c_rec}, {}); |
| @@ -454,10 +454,10 @@ InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType | |||
| 454 | return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); | 454 | return RawInstallNCA(nca, copy, overwrite_if_exists, c_rec.nca_id); |
| 455 | } | 455 | } |
| 456 | 456 | ||
| 457 | InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, | 457 | InstallResult RegisteredCache::RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy, |
| 458 | bool overwrite_if_exists, | 458 | bool overwrite_if_exists, |
| 459 | std::optional<NcaID> override_id) { | 459 | std::optional<NcaID> override_id) { |
| 460 | const auto in = nca->GetBaseFile(); | 460 | const auto in = nca.GetBaseFile(); |
| 461 | Core::Crypto::SHA256Hash hash{}; | 461 | Core::Crypto::SHA256Hash hash{}; |
| 462 | 462 | ||
| 463 | // Calculate NcaID | 463 | // Calculate NcaID |
diff --git a/src/core/file_sys/registered_cache.h b/src/core/file_sys/registered_cache.h index 6b89db8de..3b77af4e0 100644 --- a/src/core/file_sys/registered_cache.h +++ b/src/core/file_sys/registered_cache.h | |||
| @@ -6,7 +6,6 @@ | |||
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <functional> | 8 | #include <functional> |
| 9 | #include <map> | ||
| 10 | #include <memory> | 9 | #include <memory> |
| 11 | #include <string> | 10 | #include <string> |
| 12 | #include <vector> | 11 | #include <vector> |
| @@ -104,17 +103,16 @@ public: | |||
| 104 | 103 | ||
| 105 | // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure | 104 | // Raw copies all the ncas from the xci/nsp to the csache. Does some quick checks to make sure |
| 106 | // there is a meta NCA and all of them are accessible. | 105 | // there is a meta NCA and all of them are accessible. |
| 107 | InstallResult InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists = false, | 106 | InstallResult InstallEntry(const XCI& xci, bool overwrite_if_exists = false, |
| 108 | const VfsCopyFunction& copy = &VfsRawCopy); | 107 | const VfsCopyFunction& copy = &VfsRawCopy); |
| 109 | InstallResult InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists = false, | 108 | InstallResult InstallEntry(const NSP& nsp, bool overwrite_if_exists = false, |
| 110 | const VfsCopyFunction& copy = &VfsRawCopy); | 109 | const VfsCopyFunction& copy = &VfsRawCopy); |
| 111 | 110 | ||
| 112 | // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this | 111 | // Due to the fact that we must use Meta-type NCAs to determine the existance of files, this |
| 113 | // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a | 112 | // poses quite a challenge. Instead of creating a new meta NCA for this file, yuzu will create a |
| 114 | // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there. | 113 | // dir inside the NAND called 'yuzu_meta' and store the raw CNMT there. |
| 115 | // TODO(DarkLordZach): Author real meta-type NCAs and install those. | 114 | // TODO(DarkLordZach): Author real meta-type NCAs and install those. |
| 116 | InstallResult InstallEntry(std::shared_ptr<NCA> nca, TitleType type, | 115 | InstallResult InstallEntry(const NCA& nca, TitleType type, bool overwrite_if_exists = false, |
| 117 | bool overwrite_if_exists = false, | ||
| 118 | const VfsCopyFunction& copy = &VfsRawCopy); | 116 | const VfsCopyFunction& copy = &VfsRawCopy); |
| 119 | 117 | ||
| 120 | private: | 118 | private: |
| @@ -128,7 +126,7 @@ private: | |||
| 128 | std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; | 126 | std::optional<NcaID> GetNcaIDFromMetadata(u64 title_id, ContentRecordType type) const; |
| 129 | VirtualFile GetFileAtID(NcaID id) const; | 127 | VirtualFile GetFileAtID(NcaID id) const; |
| 130 | VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; | 128 | VirtualFile OpenFileOrDirectoryConcat(const VirtualDir& dir, std::string_view path) const; |
| 131 | InstallResult RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, | 129 | InstallResult RawInstallNCA(const NCA& nca, const VfsCopyFunction& copy, |
| 132 | bool overwrite_if_exists, std::optional<NcaID> override_id = {}); | 130 | bool overwrite_if_exists, std::optional<NcaID> override_id = {}); |
| 133 | bool RawInstallYuzuMeta(const CNMT& cnmt); | 131 | bool RawInstallYuzuMeta(const CNMT& cnmt); |
| 134 | 132 | ||
diff --git a/src/core/gdbstub/gdbstub.cpp b/src/core/gdbstub/gdbstub.cpp index bdcc889e0..e6b5171ee 100644 --- a/src/core/gdbstub/gdbstub.cpp +++ b/src/core/gdbstub/gdbstub.cpp | |||
| @@ -71,10 +71,6 @@ constexpr u32 PSTATE_REGISTER = 33; | |||
| 71 | constexpr u32 UC_ARM64_REG_Q0 = 34; | 71 | constexpr u32 UC_ARM64_REG_Q0 = 34; |
| 72 | constexpr u32 FPCR_REGISTER = 66; | 72 | constexpr u32 FPCR_REGISTER = 66; |
| 73 | 73 | ||
| 74 | // TODO/WiP - Used while working on support for FPU | ||
| 75 | constexpr u32 TODO_DUMMY_REG_997 = 997; | ||
| 76 | constexpr u32 TODO_DUMMY_REG_998 = 998; | ||
| 77 | |||
| 78 | // For sample XML files see the GDB source /gdb/features | 74 | // For sample XML files see the GDB source /gdb/features |
| 79 | // GDB also wants the l character at the start | 75 | // GDB also wants the l character at the start |
| 80 | // This XML defines what the registers are for this specific ARM device | 76 | // This XML defines what the registers are for this specific ARM device |
| @@ -260,6 +256,36 @@ static void RegWrite(std::size_t id, u64 val, Kernel::Thread* thread = nullptr) | |||
| 260 | } | 256 | } |
| 261 | } | 257 | } |
| 262 | 258 | ||
| 259 | static u128 FpuRead(std::size_t id, Kernel::Thread* thread = nullptr) { | ||
| 260 | if (!thread) { | ||
| 261 | return u128{0}; | ||
| 262 | } | ||
| 263 | |||
| 264 | auto& thread_context = thread->GetContext(); | ||
| 265 | |||
| 266 | if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | ||
| 267 | return thread_context.vector_registers[id - UC_ARM64_REG_Q0]; | ||
| 268 | } else if (id == FPCR_REGISTER) { | ||
| 269 | return u128{thread_context.fpcr, 0}; | ||
| 270 | } else { | ||
| 271 | return u128{0}; | ||
| 272 | } | ||
| 273 | } | ||
| 274 | |||
| 275 | static void FpuWrite(std::size_t id, u128 val, Kernel::Thread* thread = nullptr) { | ||
| 276 | if (!thread) { | ||
| 277 | return; | ||
| 278 | } | ||
| 279 | |||
| 280 | auto& thread_context = thread->GetContext(); | ||
| 281 | |||
| 282 | if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | ||
| 283 | thread_context.vector_registers[id - UC_ARM64_REG_Q0] = val; | ||
| 284 | } else if (id == FPCR_REGISTER) { | ||
| 285 | thread_context.fpcr = static_cast<u32>(val[0]); | ||
| 286 | } | ||
| 287 | } | ||
| 288 | |||
| 263 | /** | 289 | /** |
| 264 | * Turns hex string character into the equivalent byte. | 290 | * Turns hex string character into the equivalent byte. |
| 265 | * | 291 | * |
| @@ -409,6 +435,27 @@ static u64 GdbHexToLong(const u8* src) { | |||
| 409 | return output; | 435 | return output; |
| 410 | } | 436 | } |
| 411 | 437 | ||
| 438 | /** | ||
| 439 | * Convert a gdb-formatted hex string into a u128. | ||
| 440 | * | ||
| 441 | * @param src Pointer to hex string. | ||
| 442 | */ | ||
| 443 | static u128 GdbHexToU128(const u8* src) { | ||
| 444 | u128 output; | ||
| 445 | |||
| 446 | for (int i = 0; i < 16; i += 2) { | ||
| 447 | output[0] = (output[0] << 4) | HexCharToValue(src[15 - i - 1]); | ||
| 448 | output[0] = (output[0] << 4) | HexCharToValue(src[15 - i]); | ||
| 449 | } | ||
| 450 | |||
| 451 | for (int i = 0; i < 16; i += 2) { | ||
| 452 | output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i - 1]); | ||
| 453 | output[1] = (output[1] << 4) | HexCharToValue(src[16 + 15 - i]); | ||
| 454 | } | ||
| 455 | |||
| 456 | return output; | ||
| 457 | } | ||
| 458 | |||
| 412 | /// Read a byte from the gdb client. | 459 | /// Read a byte from the gdb client. |
| 413 | static u8 ReadByte() { | 460 | static u8 ReadByte() { |
| 414 | u8 c; | 461 | u8 c; |
| @@ -599,8 +646,7 @@ static void HandleQuery() { | |||
| 599 | for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { | 646 | for (u32 core = 0; core < Core::NUM_CPU_CORES; core++) { |
| 600 | const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList(); | 647 | const auto& threads = Core::System::GetInstance().Scheduler(core).GetThreadList(); |
| 601 | for (const auto& thread : threads) { | 648 | for (const auto& thread : threads) { |
| 602 | val += fmt::format("{:x}", thread->GetThreadID()); | 649 | val += fmt::format("{:x},", thread->GetThreadID()); |
| 603 | val += ","; | ||
| 604 | } | 650 | } |
| 605 | } | 651 | } |
| 606 | val.pop_back(); | 652 | val.pop_back(); |
| @@ -791,11 +837,15 @@ static void ReadRegister() { | |||
| 791 | } else if (id == PSTATE_REGISTER) { | 837 | } else if (id == PSTATE_REGISTER) { |
| 792 | IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); | 838 | IntToGdbHex(reply, static_cast<u32>(RegRead(id, current_thread))); |
| 793 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | 839 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { |
| 794 | LongToGdbHex(reply, RegRead(id, current_thread)); | 840 | u128 r = FpuRead(id, current_thread); |
| 841 | LongToGdbHex(reply, r[0]); | ||
| 842 | LongToGdbHex(reply + 16, r[1]); | ||
| 795 | } else if (id == FPCR_REGISTER) { | 843 | } else if (id == FPCR_REGISTER) { |
| 796 | LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_998, current_thread)); | 844 | u128 r = FpuRead(id, current_thread); |
| 797 | } else { | 845 | IntToGdbHex(reply, static_cast<u32>(r[0])); |
| 798 | LongToGdbHex(reply, RegRead(TODO_DUMMY_REG_997, current_thread)); | 846 | } else if (id == FPCR_REGISTER + 1) { |
| 847 | u128 r = FpuRead(id, current_thread); | ||
| 848 | IntToGdbHex(reply, static_cast<u32>(r[0] >> 32)); | ||
| 799 | } | 849 | } |
| 800 | 850 | ||
| 801 | SendReply(reinterpret_cast<char*>(reply)); | 851 | SendReply(reinterpret_cast<char*>(reply)); |
| @@ -822,13 +872,18 @@ static void ReadRegisters() { | |||
| 822 | 872 | ||
| 823 | bufptr += 8; | 873 | bufptr += 8; |
| 824 | 874 | ||
| 825 | for (u32 reg = UC_ARM64_REG_Q0; reg <= UC_ARM64_REG_Q0 + 31; reg++) { | 875 | u128 r; |
| 826 | LongToGdbHex(bufptr + reg * 16, RegRead(reg, current_thread)); | 876 | |
| 877 | for (u32 reg = UC_ARM64_REG_Q0; reg < FPCR_REGISTER; reg++) { | ||
| 878 | r = FpuRead(reg, current_thread); | ||
| 879 | LongToGdbHex(bufptr + reg * 32, r[0]); | ||
| 880 | LongToGdbHex(bufptr + reg * 32 + 16, r[1]); | ||
| 827 | } | 881 | } |
| 828 | 882 | ||
| 829 | bufptr += 32 * 32; | 883 | bufptr += 32 * 32; |
| 830 | 884 | ||
| 831 | LongToGdbHex(bufptr, RegRead(TODO_DUMMY_REG_998, current_thread)); | 885 | r = FpuRead(FPCR_REGISTER, current_thread); |
| 886 | IntToGdbHex(bufptr, static_cast<u32>(r[0])); | ||
| 832 | 887 | ||
| 833 | bufptr += 8; | 888 | bufptr += 8; |
| 834 | 889 | ||
| @@ -853,14 +908,12 @@ static void WriteRegister() { | |||
| 853 | } else if (id == PSTATE_REGISTER) { | 908 | } else if (id == PSTATE_REGISTER) { |
| 854 | RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); | 909 | RegWrite(id, GdbHexToInt(buffer_ptr), current_thread); |
| 855 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { | 910 | } else if (id >= UC_ARM64_REG_Q0 && id < FPCR_REGISTER) { |
| 856 | RegWrite(id, GdbHexToLong(buffer_ptr), current_thread); | 911 | FpuWrite(id, GdbHexToU128(buffer_ptr), current_thread); |
| 857 | } else if (id == FPCR_REGISTER) { | 912 | } else if (id == FPCR_REGISTER) { |
| 858 | RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr), current_thread); | 913 | } else if (id == FPCR_REGISTER + 1) { |
| 859 | } else { | ||
| 860 | RegWrite(TODO_DUMMY_REG_997, GdbHexToLong(buffer_ptr), current_thread); | ||
| 861 | } | 914 | } |
| 862 | 915 | ||
| 863 | // Update Unicorn context skipping scheduler, no running threads at this point | 916 | // Update ARM context, skipping scheduler - no running threads at this point |
| 864 | Core::System::GetInstance() | 917 | Core::System::GetInstance() |
| 865 | .ArmInterface(current_core) | 918 | .ArmInterface(current_core) |
| 866 | .LoadContext(current_thread->GetContext()); | 919 | .LoadContext(current_thread->GetContext()); |
| @@ -885,13 +938,13 @@ static void WriteRegisters() { | |||
| 885 | } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { | 938 | } else if (reg >= UC_ARM64_REG_Q0 && reg < FPCR_REGISTER) { |
| 886 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); | 939 | RegWrite(reg, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 887 | } else if (reg == FPCR_REGISTER) { | 940 | } else if (reg == FPCR_REGISTER) { |
| 888 | RegWrite(TODO_DUMMY_REG_998, GdbHexToLong(buffer_ptr + i * 16), current_thread); | 941 | RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 889 | } else { | 942 | } else if (reg == FPCR_REGISTER + 1) { |
| 890 | UNIMPLEMENTED(); | 943 | RegWrite(FPCR_REGISTER, GdbHexToLong(buffer_ptr + i * 16), current_thread); |
| 891 | } | 944 | } |
| 892 | } | 945 | } |
| 893 | 946 | ||
| 894 | // Update Unicorn context skipping scheduler, no running threads at this point | 947 | // Update ARM context, skipping scheduler - no running threads at this point |
| 895 | Core::System::GetInstance() | 948 | Core::System::GetInstance() |
| 896 | .ArmInterface(current_core) | 949 | .ArmInterface(current_core) |
| 897 | .LoadContext(current_thread->GetContext()); | 950 | .LoadContext(current_thread->GetContext()); |
| @@ -917,12 +970,6 @@ static void ReadMemory() { | |||
| 917 | SendReply("E01"); | 970 | SendReply("E01"); |
| 918 | } | 971 | } |
| 919 | 972 | ||
| 920 | const auto& vm_manager = Core::CurrentProcess()->VMManager(); | ||
| 921 | if (addr < vm_manager.GetCodeRegionBaseAddress() || | ||
| 922 | addr >= vm_manager.GetMapRegionEndAddress()) { | ||
| 923 | return SendReply("E00"); | ||
| 924 | } | ||
| 925 | |||
| 926 | if (!Memory::IsValidVirtualAddress(addr)) { | 973 | if (!Memory::IsValidVirtualAddress(addr)) { |
| 927 | return SendReply("E00"); | 974 | return SendReply("E00"); |
| 928 | } | 975 | } |
| @@ -967,7 +1014,7 @@ void Break(bool is_memory_break) { | |||
| 967 | static void Step() { | 1014 | static void Step() { |
| 968 | if (command_length > 1) { | 1015 | if (command_length > 1) { |
| 969 | RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); | 1016 | RegWrite(PC_REGISTER, GdbHexToLong(command_buffer + 1), current_thread); |
| 970 | // Update Unicorn context skipping scheduler, no running threads at this point | 1017 | // Update ARM context, skipping scheduler - no running threads at this point |
| 971 | Core::System::GetInstance() | 1018 | Core::System::GetInstance() |
| 972 | .ArmInterface(current_core) | 1019 | .ArmInterface(current_core) |
| 973 | .LoadContext(current_thread->GetContext()); | 1020 | .LoadContext(current_thread->GetContext()); |
| @@ -1010,7 +1057,7 @@ static bool CommitBreakpoint(BreakpointType type, VAddr addr, u64 len) { | |||
| 1010 | breakpoint.addr = addr; | 1057 | breakpoint.addr = addr; |
| 1011 | breakpoint.len = len; | 1058 | breakpoint.len = len; |
| 1012 | Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); | 1059 | Memory::ReadBlock(addr, breakpoint.inst.data(), breakpoint.inst.size()); |
| 1013 | static constexpr std::array<u8, 4> btrap{{0x00, 0x7d, 0x20, 0xd4}}; | 1060 | static constexpr std::array<u8, 4> btrap{0x00, 0x7d, 0x20, 0xd4}; |
| 1014 | Memory::WriteBlock(addr, btrap.data(), btrap.size()); | 1061 | Memory::WriteBlock(addr, btrap.data(), btrap.size()); |
| 1015 | Core::System::GetInstance().InvalidateCpuInstructionCaches(); | 1062 | Core::System::GetInstance().InvalidateCpuInstructionCaches(); |
| 1016 | p.insert({addr, breakpoint}); | 1063 | p.insert({addr, breakpoint}); |
| @@ -1321,13 +1368,15 @@ void SetCpuStepFlag(bool is_step) { | |||
| 1321 | } | 1368 | } |
| 1322 | 1369 | ||
| 1323 | void SendTrap(Kernel::Thread* thread, int trap) { | 1370 | void SendTrap(Kernel::Thread* thread, int trap) { |
| 1324 | if (send_trap) { | 1371 | if (!send_trap) { |
| 1325 | if (!halt_loop || current_thread == thread) { | 1372 | return; |
| 1326 | current_thread = thread; | ||
| 1327 | SendSignal(thread, trap); | ||
| 1328 | } | ||
| 1329 | halt_loop = true; | ||
| 1330 | send_trap = false; | ||
| 1331 | } | 1373 | } |
| 1374 | |||
| 1375 | if (!halt_loop || current_thread == thread) { | ||
| 1376 | current_thread = thread; | ||
| 1377 | SendSignal(thread, trap); | ||
| 1378 | } | ||
| 1379 | halt_loop = true; | ||
| 1380 | send_trap = false; | ||
| 1332 | } | 1381 | } |
| 1333 | }; // namespace GDBStub | 1382 | }; // namespace GDBStub |
diff --git a/src/core/hle/kernel/handle_table.cpp b/src/core/hle/kernel/handle_table.cpp index 5ee5c05e3..1bf79b692 100644 --- a/src/core/hle/kernel/handle_table.cpp +++ b/src/core/hle/kernel/handle_table.cpp | |||
| @@ -12,12 +12,23 @@ | |||
| 12 | #include "core/hle/kernel/thread.h" | 12 | #include "core/hle/kernel/thread.h" |
| 13 | 13 | ||
| 14 | namespace Kernel { | 14 | namespace Kernel { |
| 15 | namespace { | ||
| 16 | constexpr u16 GetSlot(Handle handle) { | ||
| 17 | return handle >> 15; | ||
| 18 | } | ||
| 19 | |||
| 20 | constexpr u16 GetGeneration(Handle handle) { | ||
| 21 | return handle & 0x7FFF; | ||
| 22 | } | ||
| 23 | } // Anonymous namespace | ||
| 15 | 24 | ||
| 16 | HandleTable::HandleTable() { | 25 | HandleTable::HandleTable() { |
| 17 | next_generation = 1; | 26 | next_generation = 1; |
| 18 | Clear(); | 27 | Clear(); |
| 19 | } | 28 | } |
| 20 | 29 | ||
| 30 | HandleTable::~HandleTable() = default; | ||
| 31 | |||
| 21 | ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { | 32 | ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { |
| 22 | DEBUG_ASSERT(obj != nullptr); | 33 | DEBUG_ASSERT(obj != nullptr); |
| 23 | 34 | ||
diff --git a/src/core/hle/kernel/handle_table.h b/src/core/hle/kernel/handle_table.h index 9e2f33e8a..e3f3e3fb8 100644 --- a/src/core/hle/kernel/handle_table.h +++ b/src/core/hle/kernel/handle_table.h | |||
| @@ -43,6 +43,7 @@ enum KernelHandle : Handle { | |||
| 43 | class HandleTable final : NonCopyable { | 43 | class HandleTable final : NonCopyable { |
| 44 | public: | 44 | public: |
| 45 | HandleTable(); | 45 | HandleTable(); |
| 46 | ~HandleTable(); | ||
| 46 | 47 | ||
| 47 | /** | 48 | /** |
| 48 | * Allocates a handle for the given object. | 49 | * Allocates a handle for the given object. |
| @@ -89,18 +90,8 @@ public: | |||
| 89 | void Clear(); | 90 | void Clear(); |
| 90 | 91 | ||
| 91 | private: | 92 | private: |
| 92 | /** | 93 | /// This is the maximum limit of handles allowed per process in Horizon |
| 93 | * This is the maximum limit of handles allowed per process in CTR-OS. It can be further | 94 | static constexpr std::size_t MAX_COUNT = 1024; |
| 94 | * reduced by ExHeader values, but this is not emulated here. | ||
| 95 | */ | ||
| 96 | static const std::size_t MAX_COUNT = 4096; | ||
| 97 | |||
| 98 | static u16 GetSlot(Handle handle) { | ||
| 99 | return handle >> 15; | ||
| 100 | } | ||
| 101 | static u16 GetGeneration(Handle handle) { | ||
| 102 | return handle & 0x7FFF; | ||
| 103 | } | ||
| 104 | 95 | ||
| 105 | /// Stores the Object referenced by the handle or null if the slot is empty. | 96 | /// Stores the Object referenced by the handle or null if the slot is empty. |
| 106 | std::array<SharedPtr<Object>, MAX_COUNT> objects; | 97 | std::array<SharedPtr<Object>, MAX_COUNT> objects; |
diff --git a/src/core/hle/kernel/resource_limit.h b/src/core/hle/kernel/resource_limit.h index bec065543..59dc11c22 100644 --- a/src/core/hle/kernel/resource_limit.h +++ b/src/core/hle/kernel/resource_limit.h | |||
| @@ -14,7 +14,7 @@ namespace Kernel { | |||
| 14 | 14 | ||
| 15 | class KernelCore; | 15 | class KernelCore; |
| 16 | 16 | ||
| 17 | enum class ResourceType { | 17 | enum class ResourceType : u32 { |
| 18 | PhysicalMemory, | 18 | PhysicalMemory, |
| 19 | Threads, | 19 | Threads, |
| 20 | Events, | 20 | Events, |
| @@ -25,6 +25,10 @@ enum class ResourceType { | |||
| 25 | ResourceTypeCount | 25 | ResourceTypeCount |
| 26 | }; | 26 | }; |
| 27 | 27 | ||
| 28 | constexpr bool IsValidResourceType(ResourceType type) { | ||
| 29 | return type < ResourceType::ResourceTypeCount; | ||
| 30 | } | ||
| 31 | |||
| 28 | class ResourceLimit final : public Object { | 32 | class ResourceLimit final : public Object { |
| 29 | public: | 33 | public: |
| 30 | /** | 34 | /** |
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp index b8b6b4d49..5e9660a48 100644 --- a/src/core/hle/kernel/svc.cpp +++ b/src/core/hle/kernel/svc.cpp | |||
| @@ -63,56 +63,129 @@ bool IsInsideNewMapRegion(const VMManager& vm, VAddr address, u64 size) { | |||
| 63 | vm.GetNewMapRegionEndAddress()); | 63 | vm.GetNewMapRegionEndAddress()); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | // 8 GiB | ||
| 67 | constexpr u64 MAIN_MEMORY_SIZE = 0x200000000; | ||
| 68 | |||
| 66 | // Helper function that performs the common sanity checks for svcMapMemory | 69 | // Helper function that performs the common sanity checks for svcMapMemory |
| 67 | // and svcUnmapMemory. This is doable, as both functions perform their sanitizing | 70 | // and svcUnmapMemory. This is doable, as both functions perform their sanitizing |
| 68 | // in the same order. | 71 | // in the same order. |
| 69 | ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr, | 72 | ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr, |
| 70 | u64 size) { | 73 | u64 size) { |
| 71 | if (!Common::Is4KBAligned(dst_addr) || !Common::Is4KBAligned(src_addr)) { | 74 | if (!Common::Is4KBAligned(dst_addr)) { |
| 75 | LOG_ERROR(Kernel_SVC, "Destination address is not aligned to 4KB, 0x{:016X}", dst_addr); | ||
| 72 | return ERR_INVALID_ADDRESS; | 76 | return ERR_INVALID_ADDRESS; |
| 73 | } | 77 | } |
| 74 | 78 | ||
| 75 | if (size == 0 || !Common::Is4KBAligned(size)) { | 79 | if (!Common::Is4KBAligned(src_addr)) { |
| 80 | LOG_ERROR(Kernel_SVC, "Source address is not aligned to 4KB, 0x{:016X}", src_addr); | ||
| 81 | return ERR_INVALID_SIZE; | ||
| 82 | } | ||
| 83 | |||
| 84 | if (size == 0) { | ||
| 85 | LOG_ERROR(Kernel_SVC, "Size is 0"); | ||
| 86 | return ERR_INVALID_SIZE; | ||
| 87 | } | ||
| 88 | |||
| 89 | if (!Common::Is4KBAligned(size)) { | ||
| 90 | LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size); | ||
| 76 | return ERR_INVALID_SIZE; | 91 | return ERR_INVALID_SIZE; |
| 77 | } | 92 | } |
| 78 | 93 | ||
| 79 | if (!IsValidAddressRange(dst_addr, size)) { | 94 | if (!IsValidAddressRange(dst_addr, size)) { |
| 95 | LOG_ERROR(Kernel_SVC, | ||
| 96 | "Destination is not a valid address range, addr=0x{:016X}, size=0x{:016X}", | ||
| 97 | dst_addr, size); | ||
| 80 | return ERR_INVALID_ADDRESS_STATE; | 98 | return ERR_INVALID_ADDRESS_STATE; |
| 81 | } | 99 | } |
| 82 | 100 | ||
| 83 | if (!IsValidAddressRange(src_addr, size)) { | 101 | if (!IsValidAddressRange(src_addr, size)) { |
| 102 | LOG_ERROR(Kernel_SVC, "Source is not a valid address range, addr=0x{:016X}, size=0x{:016X}", | ||
| 103 | src_addr, size); | ||
| 84 | return ERR_INVALID_ADDRESS_STATE; | 104 | return ERR_INVALID_ADDRESS_STATE; |
| 85 | } | 105 | } |
| 86 | 106 | ||
| 87 | if (!IsInsideAddressSpace(vm_manager, src_addr, size)) { | 107 | if (!IsInsideAddressSpace(vm_manager, src_addr, size)) { |
| 108 | LOG_ERROR(Kernel_SVC, | ||
| 109 | "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", | ||
| 110 | src_addr, size); | ||
| 88 | return ERR_INVALID_ADDRESS_STATE; | 111 | return ERR_INVALID_ADDRESS_STATE; |
| 89 | } | 112 | } |
| 90 | 113 | ||
| 91 | if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) { | 114 | if (!IsInsideNewMapRegion(vm_manager, dst_addr, size)) { |
| 115 | LOG_ERROR(Kernel_SVC, | ||
| 116 | "Destination is not within the new map region, addr=0x{:016X}, size=0x{:016X}", | ||
| 117 | dst_addr, size); | ||
| 92 | return ERR_INVALID_MEMORY_RANGE; | 118 | return ERR_INVALID_MEMORY_RANGE; |
| 93 | } | 119 | } |
| 94 | 120 | ||
| 95 | const VAddr dst_end_address = dst_addr + size; | 121 | const VAddr dst_end_address = dst_addr + size; |
| 96 | if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() && | 122 | if (dst_end_address > vm_manager.GetHeapRegionBaseAddress() && |
| 97 | vm_manager.GetHeapRegionEndAddress() > dst_addr) { | 123 | vm_manager.GetHeapRegionEndAddress() > dst_addr) { |
| 124 | LOG_ERROR(Kernel_SVC, | ||
| 125 | "Destination does not fit within the heap region, addr=0x{:016X}, " | ||
| 126 | "size=0x{:016X}, end_addr=0x{:016X}", | ||
| 127 | dst_addr, size, dst_end_address); | ||
| 98 | return ERR_INVALID_MEMORY_RANGE; | 128 | return ERR_INVALID_MEMORY_RANGE; |
| 99 | } | 129 | } |
| 100 | 130 | ||
| 101 | if (dst_end_address > vm_manager.GetMapRegionBaseAddress() && | 131 | if (dst_end_address > vm_manager.GetMapRegionBaseAddress() && |
| 102 | vm_manager.GetMapRegionEndAddress() > dst_addr) { | 132 | vm_manager.GetMapRegionEndAddress() > dst_addr) { |
| 133 | LOG_ERROR(Kernel_SVC, | ||
| 134 | "Destination does not fit within the map region, addr=0x{:016X}, " | ||
| 135 | "size=0x{:016X}, end_addr=0x{:016X}", | ||
| 136 | dst_addr, size, dst_end_address); | ||
| 103 | return ERR_INVALID_MEMORY_RANGE; | 137 | return ERR_INVALID_MEMORY_RANGE; |
| 104 | } | 138 | } |
| 105 | 139 | ||
| 106 | return RESULT_SUCCESS; | 140 | return RESULT_SUCCESS; |
| 107 | } | 141 | } |
| 142 | |||
| 143 | enum class ResourceLimitValueType { | ||
| 144 | CurrentValue, | ||
| 145 | LimitValue, | ||
| 146 | }; | ||
| 147 | |||
| 148 | ResultVal<s64> RetrieveResourceLimitValue(Handle resource_limit, u32 resource_type, | ||
| 149 | ResourceLimitValueType value_type) { | ||
| 150 | const auto type = static_cast<ResourceType>(resource_type); | ||
| 151 | if (!IsValidResourceType(type)) { | ||
| 152 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); | ||
| 153 | return ERR_INVALID_ENUM_VALUE; | ||
| 154 | } | ||
| 155 | |||
| 156 | const auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 157 | const auto* const current_process = kernel.CurrentProcess(); | ||
| 158 | ASSERT(current_process != nullptr); | ||
| 159 | |||
| 160 | const auto resource_limit_object = | ||
| 161 | current_process->GetHandleTable().Get<ResourceLimit>(resource_limit); | ||
| 162 | if (!resource_limit_object) { | ||
| 163 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", | ||
| 164 | resource_limit); | ||
| 165 | return ERR_INVALID_HANDLE; | ||
| 166 | } | ||
| 167 | |||
| 168 | if (value_type == ResourceLimitValueType::CurrentValue) { | ||
| 169 | return MakeResult(resource_limit_object->GetCurrentResourceValue(type)); | ||
| 170 | } | ||
| 171 | |||
| 172 | return MakeResult(resource_limit_object->GetMaxResourceValue(type)); | ||
| 173 | } | ||
| 108 | } // Anonymous namespace | 174 | } // Anonymous namespace |
| 109 | 175 | ||
| 110 | /// Set the process heap to a given Size. It can both extend and shrink the heap. | 176 | /// Set the process heap to a given Size. It can both extend and shrink the heap. |
| 111 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { | 177 | static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { |
| 112 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); | 178 | LOG_TRACE(Kernel_SVC, "called, heap_size=0x{:X}", heap_size); |
| 113 | 179 | ||
| 114 | // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 4GB. | 180 | // Size must be a multiple of 0x200000 (2MB) and be equal to or less than 8GB. |
| 115 | if ((heap_size & 0xFFFFFFFE001FFFFF) != 0) { | 181 | if ((heap_size % 0x200000) != 0) { |
| 182 | LOG_ERROR(Kernel_SVC, "The heap size is not a multiple of 2MB, heap_size=0x{:016X}", | ||
| 183 | heap_size); | ||
| 184 | return ERR_INVALID_SIZE; | ||
| 185 | } | ||
| 186 | |||
| 187 | if (heap_size >= 0x200000000) { | ||
| 188 | LOG_ERROR(Kernel_SVC, "The heap size is not less than 8GB, heap_size=0x{:016X}", heap_size); | ||
| 116 | return ERR_INVALID_SIZE; | 189 | return ERR_INVALID_SIZE; |
| 117 | } | 190 | } |
| 118 | 191 | ||
| @@ -127,20 +200,31 @@ static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) { | |||
| 127 | LOG_TRACE(Kernel_SVC, "called, addr=0x{:X}, size=0x{:X}, prot=0x{:X}", addr, size, prot); | 200 | LOG_TRACE(Kernel_SVC, "called, addr=0x{:X}, size=0x{:X}, prot=0x{:X}", addr, size, prot); |
| 128 | 201 | ||
| 129 | if (!Common::Is4KBAligned(addr)) { | 202 | if (!Common::Is4KBAligned(addr)) { |
| 203 | LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); | ||
| 130 | return ERR_INVALID_ADDRESS; | 204 | return ERR_INVALID_ADDRESS; |
| 131 | } | 205 | } |
| 132 | 206 | ||
| 133 | if (size == 0 || !Common::Is4KBAligned(size)) { | 207 | if (size == 0) { |
| 208 | LOG_ERROR(Kernel_SVC, "Size is 0"); | ||
| 209 | return ERR_INVALID_SIZE; | ||
| 210 | } | ||
| 211 | |||
| 212 | if (!Common::Is4KBAligned(size)) { | ||
| 213 | LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); | ||
| 134 | return ERR_INVALID_SIZE; | 214 | return ERR_INVALID_SIZE; |
| 135 | } | 215 | } |
| 136 | 216 | ||
| 137 | if (!IsValidAddressRange(addr, size)) { | 217 | if (!IsValidAddressRange(addr, size)) { |
| 218 | LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", | ||
| 219 | addr, size); | ||
| 138 | return ERR_INVALID_ADDRESS_STATE; | 220 | return ERR_INVALID_ADDRESS_STATE; |
| 139 | } | 221 | } |
| 140 | 222 | ||
| 141 | const auto permission = static_cast<MemoryPermission>(prot); | 223 | const auto permission = static_cast<MemoryPermission>(prot); |
| 142 | if (permission != MemoryPermission::None && permission != MemoryPermission::Read && | 224 | if (permission != MemoryPermission::None && permission != MemoryPermission::Read && |
| 143 | permission != MemoryPermission::ReadWrite) { | 225 | permission != MemoryPermission::ReadWrite) { |
| 226 | LOG_ERROR(Kernel_SVC, "Invalid memory permission specified, Got memory permission=0x{:08X}", | ||
| 227 | static_cast<u32>(permission)); | ||
| 144 | return ERR_INVALID_MEMORY_PERMISSIONS; | 228 | return ERR_INVALID_MEMORY_PERMISSIONS; |
| 145 | } | 229 | } |
| 146 | 230 | ||
| @@ -148,11 +232,15 @@ static ResultCode SetMemoryPermission(VAddr addr, u64 size, u32 prot) { | |||
| 148 | auto& vm_manager = current_process->VMManager(); | 232 | auto& vm_manager = current_process->VMManager(); |
| 149 | 233 | ||
| 150 | if (!IsInsideAddressSpace(vm_manager, addr, size)) { | 234 | if (!IsInsideAddressSpace(vm_manager, addr, size)) { |
| 235 | LOG_ERROR(Kernel_SVC, | ||
| 236 | "Source is not within the address space, addr=0x{:016X}, size=0x{:016X}", addr, | ||
| 237 | size); | ||
| 151 | return ERR_INVALID_ADDRESS_STATE; | 238 | return ERR_INVALID_ADDRESS_STATE; |
| 152 | } | 239 | } |
| 153 | 240 | ||
| 154 | const VMManager::VMAHandle iter = vm_manager.FindVMA(addr); | 241 | const VMManager::VMAHandle iter = vm_manager.FindVMA(addr); |
| 155 | if (iter == vm_manager.vma_map.end()) { | 242 | if (iter == vm_manager.vma_map.end()) { |
| 243 | LOG_ERROR(Kernel_SVC, "Unable to find VMA for address=0x{:016X}", addr); | ||
| 156 | return ERR_INVALID_ADDRESS_STATE; | 244 | return ERR_INVALID_ADDRESS_STATE; |
| 157 | } | 245 | } |
| 158 | 246 | ||
| @@ -207,6 +295,9 @@ static ResultCode UnmapMemory(VAddr dst_addr, VAddr src_addr, u64 size) { | |||
| 207 | /// Connect to an OS service given the port name, returns the handle to the port to out | 295 | /// Connect to an OS service given the port name, returns the handle to the port to out |
| 208 | static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) { | 296 | static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) { |
| 209 | if (!Memory::IsValidVirtualAddress(port_name_address)) { | 297 | if (!Memory::IsValidVirtualAddress(port_name_address)) { |
| 298 | LOG_ERROR(Kernel_SVC, | ||
| 299 | "Port Name Address is not a valid virtual address, port_name_address=0x{:016X}", | ||
| 300 | port_name_address); | ||
| 210 | return ERR_NOT_FOUND; | 301 | return ERR_NOT_FOUND; |
| 211 | } | 302 | } |
| 212 | 303 | ||
| @@ -214,6 +305,8 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address | |||
| 214 | // Read 1 char beyond the max allowed port name to detect names that are too long. | 305 | // Read 1 char beyond the max allowed port name to detect names that are too long. |
| 215 | std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1); | 306 | std::string port_name = Memory::ReadCString(port_name_address, PortNameMaxLength + 1); |
| 216 | if (port_name.size() > PortNameMaxLength) { | 307 | if (port_name.size() > PortNameMaxLength) { |
| 308 | LOG_ERROR(Kernel_SVC, "Port name is too long, expected {} but got {}", PortNameMaxLength, | ||
| 309 | port_name.size()); | ||
| 217 | return ERR_OUT_OF_RANGE; | 310 | return ERR_OUT_OF_RANGE; |
| 218 | } | 311 | } |
| 219 | 312 | ||
| @@ -262,6 +355,7 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { | |||
| 262 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 355 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 263 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 356 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| 264 | if (!thread) { | 357 | if (!thread) { |
| 358 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", thread_handle); | ||
| 265 | return ERR_INVALID_HANDLE; | 359 | return ERR_INVALID_HANDLE; |
| 266 | } | 360 | } |
| 267 | 361 | ||
| @@ -276,6 +370,8 @@ static ResultCode GetProcessId(u32* process_id, Handle process_handle) { | |||
| 276 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 370 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 277 | const SharedPtr<Process> process = handle_table.Get<Process>(process_handle); | 371 | const SharedPtr<Process> process = handle_table.Get<Process>(process_handle); |
| 278 | if (!process) { | 372 | if (!process) { |
| 373 | LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", | ||
| 374 | process_handle); | ||
| 279 | return ERR_INVALID_HANDLE; | 375 | return ERR_INVALID_HANDLE; |
| 280 | } | 376 | } |
| 281 | 377 | ||
| @@ -305,12 +401,18 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 | |||
| 305 | LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", | 401 | LOG_TRACE(Kernel_SVC, "called handles_address=0x{:X}, handle_count={}, nano_seconds={}", |
| 306 | handles_address, handle_count, nano_seconds); | 402 | handles_address, handle_count, nano_seconds); |
| 307 | 403 | ||
| 308 | if (!Memory::IsValidVirtualAddress(handles_address)) | 404 | if (!Memory::IsValidVirtualAddress(handles_address)) { |
| 405 | LOG_ERROR(Kernel_SVC, | ||
| 406 | "Handle address is not a valid virtual address, handle_address=0x{:016X}", | ||
| 407 | handles_address); | ||
| 309 | return ERR_INVALID_POINTER; | 408 | return ERR_INVALID_POINTER; |
| 409 | } | ||
| 310 | 410 | ||
| 311 | static constexpr u64 MaxHandles = 0x40; | 411 | static constexpr u64 MaxHandles = 0x40; |
| 312 | 412 | ||
| 313 | if (handle_count > MaxHandles) { | 413 | if (handle_count > MaxHandles) { |
| 414 | LOG_ERROR(Kernel_SVC, "Handle count specified is too large, expected {} but got {}", | ||
| 415 | MaxHandles, handle_count); | ||
| 314 | return ERR_OUT_OF_RANGE; | 416 | return ERR_OUT_OF_RANGE; |
| 315 | } | 417 | } |
| 316 | 418 | ||
| @@ -325,6 +427,7 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 | |||
| 325 | const auto object = handle_table.Get<WaitObject>(handle); | 427 | const auto object = handle_table.Get<WaitObject>(handle); |
| 326 | 428 | ||
| 327 | if (object == nullptr) { | 429 | if (object == nullptr) { |
| 430 | LOG_ERROR(Kernel_SVC, "Object is a nullptr"); | ||
| 328 | return ERR_INVALID_HANDLE; | 431 | return ERR_INVALID_HANDLE; |
| 329 | } | 432 | } |
| 330 | 433 | ||
| @@ -348,11 +451,13 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64 | |||
| 348 | 451 | ||
| 349 | // If a timeout value of 0 was provided, just return the Timeout error code instead of | 452 | // If a timeout value of 0 was provided, just return the Timeout error code instead of |
| 350 | // suspending the thread. | 453 | // suspending the thread. |
| 351 | if (nano_seconds == 0) | 454 | if (nano_seconds == 0) { |
| 352 | return RESULT_TIMEOUT; | 455 | return RESULT_TIMEOUT; |
| 456 | } | ||
| 353 | 457 | ||
| 354 | for (auto& object : objects) | 458 | for (auto& object : objects) { |
| 355 | object->AddWaitingThread(thread); | 459 | object->AddWaitingThread(thread); |
| 460 | } | ||
| 356 | 461 | ||
| 357 | thread->SetWaitObjects(std::move(objects)); | 462 | thread->SetWaitObjects(std::move(objects)); |
| 358 | thread->SetStatus(ThreadStatus::WaitSynchAny); | 463 | thread->SetStatus(ThreadStatus::WaitSynchAny); |
| @@ -373,6 +478,8 @@ static ResultCode CancelSynchronization(Handle thread_handle) { | |||
| 373 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 478 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 374 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 479 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| 375 | if (!thread) { | 480 | if (!thread) { |
| 481 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 482 | thread_handle); | ||
| 376 | return ERR_INVALID_HANDLE; | 483 | return ERR_INVALID_HANDLE; |
| 377 | } | 484 | } |
| 378 | 485 | ||
| @@ -391,10 +498,13 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr, | |||
| 391 | holding_thread_handle, mutex_addr, requesting_thread_handle); | 498 | holding_thread_handle, mutex_addr, requesting_thread_handle); |
| 392 | 499 | ||
| 393 | if (Memory::IsKernelVirtualAddress(mutex_addr)) { | 500 | if (Memory::IsKernelVirtualAddress(mutex_addr)) { |
| 501 | LOG_ERROR(Kernel_SVC, "Mutex Address is a kernel virtual address, mutex_addr={:016X}", | ||
| 502 | mutex_addr); | ||
| 394 | return ERR_INVALID_ADDRESS_STATE; | 503 | return ERR_INVALID_ADDRESS_STATE; |
| 395 | } | 504 | } |
| 396 | 505 | ||
| 397 | if (!Common::IsWordAligned(mutex_addr)) { | 506 | if (!Common::IsWordAligned(mutex_addr)) { |
| 507 | LOG_ERROR(Kernel_SVC, "Mutex Address is not word aligned, mutex_addr={:016X}", mutex_addr); | ||
| 398 | return ERR_INVALID_ADDRESS; | 508 | return ERR_INVALID_ADDRESS; |
| 399 | } | 509 | } |
| 400 | 510 | ||
| @@ -408,10 +518,13 @@ static ResultCode ArbitrateUnlock(VAddr mutex_addr) { | |||
| 408 | LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); | 518 | LOG_TRACE(Kernel_SVC, "called mutex_addr=0x{:X}", mutex_addr); |
| 409 | 519 | ||
| 410 | if (Memory::IsKernelVirtualAddress(mutex_addr)) { | 520 | if (Memory::IsKernelVirtualAddress(mutex_addr)) { |
| 521 | LOG_ERROR(Kernel_SVC, "Mutex Address is a kernel virtual address, mutex_addr={:016X}", | ||
| 522 | mutex_addr); | ||
| 411 | return ERR_INVALID_ADDRESS_STATE; | 523 | return ERR_INVALID_ADDRESS_STATE; |
| 412 | } | 524 | } |
| 413 | 525 | ||
| 414 | if (!Common::IsWordAligned(mutex_addr)) { | 526 | if (!Common::IsWordAligned(mutex_addr)) { |
| 527 | LOG_ERROR(Kernel_SVC, "Mutex Address is not word aligned, mutex_addr={:016X}", mutex_addr); | ||
| 415 | return ERR_INVALID_ADDRESS; | 528 | return ERR_INVALID_ADDRESS; |
| 416 | } | 529 | } |
| 417 | 530 | ||
| @@ -602,10 +715,14 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 602 | break; | 715 | break; |
| 603 | case GetInfoType::RandomEntropy: | 716 | case GetInfoType::RandomEntropy: |
| 604 | if (handle != 0) { | 717 | if (handle != 0) { |
| 718 | LOG_ERROR(Kernel_SVC, "Process Handle is non zero, expected 0 result but got {:016X}", | ||
| 719 | handle); | ||
| 605 | return ERR_INVALID_HANDLE; | 720 | return ERR_INVALID_HANDLE; |
| 606 | } | 721 | } |
| 607 | 722 | ||
| 608 | if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) { | 723 | if (info_sub_id >= Process::RANDOM_ENTROPY_SIZE) { |
| 724 | LOG_ERROR(Kernel_SVC, "Entropy size is out of range, expected {} but got {}", | ||
| 725 | Process::RANDOM_ENTROPY_SIZE, info_sub_id); | ||
| 609 | return ERR_INVALID_COMBINATION; | 726 | return ERR_INVALID_COMBINATION; |
| 610 | } | 727 | } |
| 611 | 728 | ||
| @@ -643,12 +760,16 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 643 | case GetInfoType::ThreadTickCount: { | 760 | case GetInfoType::ThreadTickCount: { |
| 644 | constexpr u64 num_cpus = 4; | 761 | constexpr u64 num_cpus = 4; |
| 645 | if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { | 762 | if (info_sub_id != 0xFFFFFFFFFFFFFFFF && info_sub_id >= num_cpus) { |
| 763 | LOG_ERROR(Kernel_SVC, "Core count is out of range, expected {} but got {}", num_cpus, | ||
| 764 | info_sub_id); | ||
| 646 | return ERR_INVALID_COMBINATION; | 765 | return ERR_INVALID_COMBINATION; |
| 647 | } | 766 | } |
| 648 | 767 | ||
| 649 | const auto thread = | 768 | const auto thread = |
| 650 | current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle)); | 769 | current_process->GetHandleTable().Get<Thread>(static_cast<Handle>(handle)); |
| 651 | if (!thread) { | 770 | if (!thread) { |
| 771 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", | ||
| 772 | static_cast<Handle>(handle)); | ||
| 652 | return ERR_INVALID_HANDLE; | 773 | return ERR_INVALID_HANDLE; |
| 653 | } | 774 | } |
| 654 | 775 | ||
| @@ -671,7 +792,8 @@ static ResultCode GetInfo(u64* result, u64 info_id, u64 handle, u64 info_sub_id) | |||
| 671 | break; | 792 | break; |
| 672 | } | 793 | } |
| 673 | default: | 794 | default: |
| 674 | UNIMPLEMENTED(); | 795 | LOG_WARNING(Kernel_SVC, "(STUBBED) Unimplemented svcGetInfo id=0x{:016X}", info_id); |
| 796 | return ERR_INVALID_ENUM_VALUE; | ||
| 675 | } | 797 | } |
| 676 | 798 | ||
| 677 | return RESULT_SUCCESS; | 799 | return RESULT_SUCCESS; |
| @@ -690,14 +812,22 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { | |||
| 690 | const auto* current_process = Core::CurrentProcess(); | 812 | const auto* current_process = Core::CurrentProcess(); |
| 691 | const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); | 813 | const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); |
| 692 | if (!thread) { | 814 | if (!thread) { |
| 815 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | ||
| 693 | return ERR_INVALID_HANDLE; | 816 | return ERR_INVALID_HANDLE; |
| 694 | } | 817 | } |
| 695 | 818 | ||
| 696 | if (thread->GetOwnerProcess() != current_process) { | 819 | if (thread->GetOwnerProcess() != current_process) { |
| 820 | LOG_ERROR(Kernel_SVC, | ||
| 821 | "The current process does not own the current thread, thread_handle={:08X} " | ||
| 822 | "thread_pid={}, " | ||
| 823 | "current_process_pid={}", | ||
| 824 | handle, thread->GetOwnerProcess()->GetProcessID(), | ||
| 825 | current_process->GetProcessID()); | ||
| 697 | return ERR_INVALID_HANDLE; | 826 | return ERR_INVALID_HANDLE; |
| 698 | } | 827 | } |
| 699 | 828 | ||
| 700 | if (thread == GetCurrentThread()) { | 829 | if (thread == GetCurrentThread()) { |
| 830 | LOG_ERROR(Kernel_SVC, "The thread handle specified is the current running thread"); | ||
| 701 | return ERR_ALREADY_REGISTERED; | 831 | return ERR_ALREADY_REGISTERED; |
| 702 | } | 832 | } |
| 703 | 833 | ||
| @@ -718,9 +848,12 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { | |||
| 718 | 848 | ||
| 719 | /// Gets the priority for the specified thread | 849 | /// Gets the priority for the specified thread |
| 720 | static ResultCode GetThreadPriority(u32* priority, Handle handle) { | 850 | static ResultCode GetThreadPriority(u32* priority, Handle handle) { |
| 851 | LOG_TRACE(Kernel_SVC, "called"); | ||
| 852 | |||
| 721 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 853 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 722 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle); | 854 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle); |
| 723 | if (!thread) { | 855 | if (!thread) { |
| 856 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | ||
| 724 | return ERR_INVALID_HANDLE; | 857 | return ERR_INVALID_HANDLE; |
| 725 | } | 858 | } |
| 726 | 859 | ||
| @@ -730,7 +863,13 @@ static ResultCode GetThreadPriority(u32* priority, Handle handle) { | |||
| 730 | 863 | ||
| 731 | /// Sets the priority for the specified thread | 864 | /// Sets the priority for the specified thread |
| 732 | static ResultCode SetThreadPriority(Handle handle, u32 priority) { | 865 | static ResultCode SetThreadPriority(Handle handle, u32 priority) { |
| 866 | LOG_TRACE(Kernel_SVC, "called"); | ||
| 867 | |||
| 733 | if (priority > THREADPRIO_LOWEST) { | 868 | if (priority > THREADPRIO_LOWEST) { |
| 869 | LOG_ERROR( | ||
| 870 | Kernel_SVC, | ||
| 871 | "An invalid priority was specified, expected {} but got {} for thread_handle={:08X}", | ||
| 872 | THREADPRIO_LOWEST, priority, handle); | ||
| 734 | return ERR_INVALID_THREAD_PRIORITY; | 873 | return ERR_INVALID_THREAD_PRIORITY; |
| 735 | } | 874 | } |
| 736 | 875 | ||
| @@ -738,6 +877,7 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) { | |||
| 738 | 877 | ||
| 739 | SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); | 878 | SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle); |
| 740 | if (!thread) { | 879 | if (!thread) { |
| 880 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, handle=0x{:08X}", handle); | ||
| 741 | return ERR_INVALID_HANDLE; | 881 | return ERR_INVALID_HANDLE; |
| 742 | } | 882 | } |
| 743 | 883 | ||
| @@ -760,32 +900,46 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s | |||
| 760 | shared_memory_handle, addr, size, permissions); | 900 | shared_memory_handle, addr, size, permissions); |
| 761 | 901 | ||
| 762 | if (!Common::Is4KBAligned(addr)) { | 902 | if (!Common::Is4KBAligned(addr)) { |
| 903 | LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); | ||
| 763 | return ERR_INVALID_ADDRESS; | 904 | return ERR_INVALID_ADDRESS; |
| 764 | } | 905 | } |
| 765 | 906 | ||
| 766 | if (size == 0 || !Common::Is4KBAligned(size)) { | 907 | if (size == 0) { |
| 908 | LOG_ERROR(Kernel_SVC, "Size is 0"); | ||
| 909 | return ERR_INVALID_SIZE; | ||
| 910 | } | ||
| 911 | |||
| 912 | if (!Common::Is4KBAligned(size)) { | ||
| 913 | LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); | ||
| 767 | return ERR_INVALID_SIZE; | 914 | return ERR_INVALID_SIZE; |
| 768 | } | 915 | } |
| 769 | 916 | ||
| 770 | if (!IsValidAddressRange(addr, size)) { | 917 | if (!IsValidAddressRange(addr, size)) { |
| 918 | LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", | ||
| 919 | addr, size); | ||
| 771 | return ERR_INVALID_ADDRESS_STATE; | 920 | return ERR_INVALID_ADDRESS_STATE; |
| 772 | } | 921 | } |
| 773 | 922 | ||
| 774 | const auto permissions_type = static_cast<MemoryPermission>(permissions); | 923 | const auto permissions_type = static_cast<MemoryPermission>(permissions); |
| 775 | if (permissions_type != MemoryPermission::Read && | 924 | if (permissions_type != MemoryPermission::Read && |
| 776 | permissions_type != MemoryPermission::ReadWrite) { | 925 | permissions_type != MemoryPermission::ReadWrite) { |
| 777 | LOG_ERROR(Kernel_SVC, "Invalid permissions=0x{:08X}", permissions); | 926 | LOG_ERROR(Kernel_SVC, "Expected Read or ReadWrite permission but got permissions=0x{:08X}", |
| 927 | permissions); | ||
| 778 | return ERR_INVALID_MEMORY_PERMISSIONS; | 928 | return ERR_INVALID_MEMORY_PERMISSIONS; |
| 779 | } | 929 | } |
| 780 | 930 | ||
| 781 | auto* const current_process = Core::CurrentProcess(); | 931 | auto* const current_process = Core::CurrentProcess(); |
| 782 | auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); | 932 | auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); |
| 783 | if (!shared_memory) { | 933 | if (!shared_memory) { |
| 934 | LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", | ||
| 935 | shared_memory_handle); | ||
| 784 | return ERR_INVALID_HANDLE; | 936 | return ERR_INVALID_HANDLE; |
| 785 | } | 937 | } |
| 786 | 938 | ||
| 787 | const auto& vm_manager = current_process->VMManager(); | 939 | const auto& vm_manager = current_process->VMManager(); |
| 788 | if (!vm_manager.IsWithinASLRRegion(addr, size)) { | 940 | if (!vm_manager.IsWithinASLRRegion(addr, size)) { |
| 941 | LOG_ERROR(Kernel_SVC, "Region is not within the ASLR region. addr=0x{:016X}, size={:016X}", | ||
| 942 | addr, size); | ||
| 789 | return ERR_INVALID_MEMORY_RANGE; | 943 | return ERR_INVALID_MEMORY_RANGE; |
| 790 | } | 944 | } |
| 791 | 945 | ||
| @@ -797,25 +951,38 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 | |||
| 797 | shared_memory_handle, addr, size); | 951 | shared_memory_handle, addr, size); |
| 798 | 952 | ||
| 799 | if (!Common::Is4KBAligned(addr)) { | 953 | if (!Common::Is4KBAligned(addr)) { |
| 954 | LOG_ERROR(Kernel_SVC, "Address is not aligned to 4KB, addr=0x{:016X}", addr); | ||
| 800 | return ERR_INVALID_ADDRESS; | 955 | return ERR_INVALID_ADDRESS; |
| 801 | } | 956 | } |
| 802 | 957 | ||
| 803 | if (size == 0 || !Common::Is4KBAligned(size)) { | 958 | if (size == 0) { |
| 959 | LOG_ERROR(Kernel_SVC, "Size is 0"); | ||
| 960 | return ERR_INVALID_SIZE; | ||
| 961 | } | ||
| 962 | |||
| 963 | if (!Common::Is4KBAligned(size)) { | ||
| 964 | LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, size=0x{:016X}", size); | ||
| 804 | return ERR_INVALID_SIZE; | 965 | return ERR_INVALID_SIZE; |
| 805 | } | 966 | } |
| 806 | 967 | ||
| 807 | if (!IsValidAddressRange(addr, size)) { | 968 | if (!IsValidAddressRange(addr, size)) { |
| 969 | LOG_ERROR(Kernel_SVC, "Region is not a valid address range, addr=0x{:016X}, size=0x{:016X}", | ||
| 970 | addr, size); | ||
| 808 | return ERR_INVALID_ADDRESS_STATE; | 971 | return ERR_INVALID_ADDRESS_STATE; |
| 809 | } | 972 | } |
| 810 | 973 | ||
| 811 | auto* const current_process = Core::CurrentProcess(); | 974 | auto* const current_process = Core::CurrentProcess(); |
| 812 | auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); | 975 | auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle); |
| 813 | if (!shared_memory) { | 976 | if (!shared_memory) { |
| 977 | LOG_ERROR(Kernel_SVC, "Shared memory does not exist, shared_memory_handle=0x{:08X}", | ||
| 978 | shared_memory_handle); | ||
| 814 | return ERR_INVALID_HANDLE; | 979 | return ERR_INVALID_HANDLE; |
| 815 | } | 980 | } |
| 816 | 981 | ||
| 817 | const auto& vm_manager = current_process->VMManager(); | 982 | const auto& vm_manager = current_process->VMManager(); |
| 818 | if (!vm_manager.IsWithinASLRRegion(addr, size)) { | 983 | if (!vm_manager.IsWithinASLRRegion(addr, size)) { |
| 984 | LOG_ERROR(Kernel_SVC, "Region is not within the ASLR region. addr=0x{:016X}, size={:016X}", | ||
| 985 | addr, size); | ||
| 819 | return ERR_INVALID_MEMORY_RANGE; | 986 | return ERR_INVALID_MEMORY_RANGE; |
| 820 | } | 987 | } |
| 821 | 988 | ||
| @@ -825,9 +992,12 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 | |||
| 825 | /// Query process memory | 992 | /// Query process memory |
| 826 | static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, | 993 | static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, |
| 827 | Handle process_handle, u64 addr) { | 994 | Handle process_handle, u64 addr) { |
| 995 | LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr); | ||
| 828 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 996 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 829 | SharedPtr<Process> process = handle_table.Get<Process>(process_handle); | 997 | SharedPtr<Process> process = handle_table.Get<Process>(process_handle); |
| 830 | if (!process) { | 998 | if (!process) { |
| 999 | LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", | ||
| 1000 | process_handle); | ||
| 831 | return ERR_INVALID_HANDLE; | 1001 | return ERR_INVALID_HANDLE; |
| 832 | } | 1002 | } |
| 833 | auto vma = process->VMManager().FindVMA(addr); | 1003 | auto vma = process->VMManager().FindVMA(addr); |
| @@ -843,8 +1013,6 @@ static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_i | |||
| 843 | memory_info->size = vma->second.size; | 1013 | memory_info->size = vma->second.size; |
| 844 | memory_info->type = static_cast<u32>(vma->second.meminfo_state); | 1014 | memory_info->type = static_cast<u32>(vma->second.meminfo_state); |
| 845 | } | 1015 | } |
| 846 | |||
| 847 | LOG_TRACE(Kernel_SVC, "called process=0x{:08X} addr={:X}", process_handle, addr); | ||
| 848 | return RESULT_SUCCESS; | 1016 | return RESULT_SUCCESS; |
| 849 | } | 1017 | } |
| 850 | 1018 | ||
| @@ -873,7 +1041,14 @@ static void ExitProcess() { | |||
| 873 | /// Creates a new thread | 1041 | /// Creates a new thread |
| 874 | static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, | 1042 | static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, |
| 875 | u32 priority, s32 processor_id) { | 1043 | u32 priority, s32 processor_id) { |
| 1044 | LOG_TRACE(Kernel_SVC, | ||
| 1045 | "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, " | ||
| 1046 | "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", | ||
| 1047 | entry_point, name, arg, stack_top, priority, processor_id, *out_handle); | ||
| 1048 | |||
| 876 | if (priority > THREADPRIO_LOWEST) { | 1049 | if (priority > THREADPRIO_LOWEST) { |
| 1050 | LOG_ERROR(Kernel_SVC, "An invalid priority was specified, expected {} but got {}", | ||
| 1051 | THREADPRIO_LOWEST, priority); | ||
| 877 | return ERR_INVALID_THREAD_PRIORITY; | 1052 | return ERR_INVALID_THREAD_PRIORITY; |
| 878 | } | 1053 | } |
| 879 | 1054 | ||
| @@ -904,6 +1079,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | |||
| 904 | 1079 | ||
| 905 | const auto new_guest_handle = current_process->GetHandleTable().Create(thread); | 1080 | const auto new_guest_handle = current_process->GetHandleTable().Create(thread); |
| 906 | if (new_guest_handle.Failed()) { | 1081 | if (new_guest_handle.Failed()) { |
| 1082 | LOG_ERROR(Kernel_SVC, "Failed to create handle with error=0x{:X}", | ||
| 1083 | new_guest_handle.Code().raw); | ||
| 907 | return new_guest_handle.Code(); | 1084 | return new_guest_handle.Code(); |
| 908 | } | 1085 | } |
| 909 | thread->SetGuestHandle(*new_guest_handle); | 1086 | thread->SetGuestHandle(*new_guest_handle); |
| @@ -911,11 +1088,6 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V | |||
| 911 | 1088 | ||
| 912 | Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); | 1089 | Core::System::GetInstance().CpuCore(thread->GetProcessorID()).PrepareReschedule(); |
| 913 | 1090 | ||
| 914 | LOG_TRACE(Kernel_SVC, | ||
| 915 | "called entrypoint=0x{:08X} ({}), arg=0x{:08X}, stacktop=0x{:08X}, " | ||
| 916 | "threadpriority=0x{:08X}, processorid=0x{:08X} : created handle=0x{:08X}", | ||
| 917 | entry_point, name, arg, stack_top, priority, processor_id, *out_handle); | ||
| 918 | |||
| 919 | return RESULT_SUCCESS; | 1091 | return RESULT_SUCCESS; |
| 920 | } | 1092 | } |
| 921 | 1093 | ||
| @@ -926,6 +1098,8 @@ static ResultCode StartThread(Handle thread_handle) { | |||
| 926 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1098 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 927 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1099 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| 928 | if (!thread) { | 1100 | if (!thread) { |
| 1101 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 1102 | thread_handle); | ||
| 929 | return ERR_INVALID_HANDLE; | 1103 | return ERR_INVALID_HANDLE; |
| 930 | } | 1104 | } |
| 931 | 1105 | ||
| @@ -1105,10 +1279,12 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout | |||
| 1105 | address, type, value, timeout); | 1279 | address, type, value, timeout); |
| 1106 | // If the passed address is a kernel virtual address, return invalid memory state. | 1280 | // If the passed address is a kernel virtual address, return invalid memory state. |
| 1107 | if (Memory::IsKernelVirtualAddress(address)) { | 1281 | if (Memory::IsKernelVirtualAddress(address)) { |
| 1282 | LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); | ||
| 1108 | return ERR_INVALID_ADDRESS_STATE; | 1283 | return ERR_INVALID_ADDRESS_STATE; |
| 1109 | } | 1284 | } |
| 1110 | // If the address is not properly aligned to 4 bytes, return invalid address. | 1285 | // If the address is not properly aligned to 4 bytes, return invalid address. |
| 1111 | if (address % sizeof(u32) != 0) { | 1286 | if (!Common::IsWordAligned(address)) { |
| 1287 | LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address); | ||
| 1112 | return ERR_INVALID_ADDRESS; | 1288 | return ERR_INVALID_ADDRESS; |
| 1113 | } | 1289 | } |
| 1114 | 1290 | ||
| @@ -1120,6 +1296,10 @@ static ResultCode WaitForAddress(VAddr address, u32 type, s32 value, s64 timeout | |||
| 1120 | case AddressArbiter::ArbitrationType::WaitIfEqual: | 1296 | case AddressArbiter::ArbitrationType::WaitIfEqual: |
| 1121 | return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); | 1297 | return AddressArbiter::WaitForAddressIfEqual(address, value, timeout); |
| 1122 | default: | 1298 | default: |
| 1299 | LOG_ERROR(Kernel_SVC, | ||
| 1300 | "Invalid arbitration type, expected WaitIfLessThan, DecrementAndWaitIfLessThan " | ||
| 1301 | "or WaitIfEqual but got {}", | ||
| 1302 | type); | ||
| 1123 | return ERR_INVALID_ENUM_VALUE; | 1303 | return ERR_INVALID_ENUM_VALUE; |
| 1124 | } | 1304 | } |
| 1125 | } | 1305 | } |
| @@ -1130,10 +1310,12 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to | |||
| 1130 | address, type, value, num_to_wake); | 1310 | address, type, value, num_to_wake); |
| 1131 | // If the passed address is a kernel virtual address, return invalid memory state. | 1311 | // If the passed address is a kernel virtual address, return invalid memory state. |
| 1132 | if (Memory::IsKernelVirtualAddress(address)) { | 1312 | if (Memory::IsKernelVirtualAddress(address)) { |
| 1313 | LOG_ERROR(Kernel_SVC, "Address is a kernel virtual address, address={:016X}", address); | ||
| 1133 | return ERR_INVALID_ADDRESS_STATE; | 1314 | return ERR_INVALID_ADDRESS_STATE; |
| 1134 | } | 1315 | } |
| 1135 | // If the address is not properly aligned to 4 bytes, return invalid address. | 1316 | // If the address is not properly aligned to 4 bytes, return invalid address. |
| 1136 | if (address % sizeof(u32) != 0) { | 1317 | if (!Common::IsWordAligned(address)) { |
| 1318 | LOG_ERROR(Kernel_SVC, "Address is not word aligned, address={:016X}", address); | ||
| 1137 | return ERR_INVALID_ADDRESS; | 1319 | return ERR_INVALID_ADDRESS; |
| 1138 | } | 1320 | } |
| 1139 | 1321 | ||
| @@ -1146,12 +1328,18 @@ static ResultCode SignalToAddress(VAddr address, u32 type, s32 value, s32 num_to | |||
| 1146 | return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, | 1328 | return AddressArbiter::ModifyByWaitingCountAndSignalToAddressIfEqual(address, value, |
| 1147 | num_to_wake); | 1329 | num_to_wake); |
| 1148 | default: | 1330 | default: |
| 1331 | LOG_ERROR(Kernel_SVC, | ||
| 1332 | "Invalid signal type, expected Signal, IncrementAndSignalIfEqual " | ||
| 1333 | "or ModifyByWaitingCountAndSignalIfEqual but got {}", | ||
| 1334 | type); | ||
| 1149 | return ERR_INVALID_ENUM_VALUE; | 1335 | return ERR_INVALID_ENUM_VALUE; |
| 1150 | } | 1336 | } |
| 1151 | } | 1337 | } |
| 1152 | 1338 | ||
| 1153 | /// This returns the total CPU ticks elapsed since the CPU was powered-on | 1339 | /// This returns the total CPU ticks elapsed since the CPU was powered-on |
| 1154 | static u64 GetSystemTick() { | 1340 | static u64 GetSystemTick() { |
| 1341 | LOG_TRACE(Kernel_SVC, "called"); | ||
| 1342 | |||
| 1155 | const u64 result{CoreTiming::GetTicks()}; | 1343 | const u64 result{CoreTiming::GetTicks()}; |
| 1156 | 1344 | ||
| 1157 | // Advance time to defeat dumb games that busy-wait for the frame to end. | 1345 | // Advance time to defeat dumb games that busy-wait for the frame to end. |
| @@ -1225,6 +1413,8 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) | |||
| 1225 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1413 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 1226 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1414 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| 1227 | if (!thread) { | 1415 | if (!thread) { |
| 1416 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 1417 | thread_handle); | ||
| 1228 | return ERR_INVALID_HANDLE; | 1418 | return ERR_INVALID_HANDLE; |
| 1229 | } | 1419 | } |
| 1230 | 1420 | ||
| @@ -1235,12 +1425,14 @@ static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) | |||
| 1235 | } | 1425 | } |
| 1236 | 1426 | ||
| 1237 | static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { | 1427 | static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { |
| 1238 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle, | 1428 | LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:016X}, core=0x{:X}", thread_handle, |
| 1239 | mask, core); | 1429 | mask, core); |
| 1240 | 1430 | ||
| 1241 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1431 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 1242 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); | 1432 | const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle); |
| 1243 | if (!thread) { | 1433 | if (!thread) { |
| 1434 | LOG_ERROR(Kernel_SVC, "Thread handle does not exist, thread_handle=0x{:08X}", | ||
| 1435 | thread_handle); | ||
| 1244 | return ERR_INVALID_HANDLE; | 1436 | return ERR_INVALID_HANDLE; |
| 1245 | } | 1437 | } |
| 1246 | 1438 | ||
| @@ -1255,6 +1447,7 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { | |||
| 1255 | } | 1447 | } |
| 1256 | 1448 | ||
| 1257 | if (mask == 0) { | 1449 | if (mask == 0) { |
| 1450 | LOG_ERROR(Kernel_SVC, "Mask is 0"); | ||
| 1258 | return ERR_INVALID_COMBINATION; | 1451 | return ERR_INVALID_COMBINATION; |
| 1259 | } | 1452 | } |
| 1260 | 1453 | ||
| @@ -1264,11 +1457,14 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { | |||
| 1264 | if (core == OnlyChangeMask) { | 1457 | if (core == OnlyChangeMask) { |
| 1265 | core = thread->GetIdealCore(); | 1458 | core = thread->GetIdealCore(); |
| 1266 | } else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) { | 1459 | } else if (core >= Core::NUM_CPU_CORES && core != static_cast<u32>(-1)) { |
| 1460 | LOG_ERROR(Kernel_SVC, "Invalid core specified, got {}", core); | ||
| 1267 | return ERR_INVALID_PROCESSOR_ID; | 1461 | return ERR_INVALID_PROCESSOR_ID; |
| 1268 | } | 1462 | } |
| 1269 | 1463 | ||
| 1270 | // Error out if the input core isn't enabled in the input mask. | 1464 | // Error out if the input core isn't enabled in the input mask. |
| 1271 | if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) { | 1465 | if (core < Core::NUM_CPU_CORES && (mask & (1ull << core)) == 0) { |
| 1466 | LOG_ERROR(Kernel_SVC, "Core is not enabled for the current mask, core={}, mask={:016X}", | ||
| 1467 | core, mask); | ||
| 1272 | return ERR_INVALID_COMBINATION; | 1468 | return ERR_INVALID_COMBINATION; |
| 1273 | } | 1469 | } |
| 1274 | 1470 | ||
| @@ -1281,21 +1477,36 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss | |||
| 1281 | u32 remote_permissions) { | 1477 | u32 remote_permissions) { |
| 1282 | LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, | 1478 | LOG_TRACE(Kernel_SVC, "called, size=0x{:X}, localPerms=0x{:08X}, remotePerms=0x{:08X}", size, |
| 1283 | local_permissions, remote_permissions); | 1479 | local_permissions, remote_permissions); |
| 1480 | if (size == 0) { | ||
| 1481 | LOG_ERROR(Kernel_SVC, "Size is 0"); | ||
| 1482 | return ERR_INVALID_SIZE; | ||
| 1483 | } | ||
| 1484 | if (!Common::Is4KBAligned(size)) { | ||
| 1485 | LOG_ERROR(Kernel_SVC, "Size is not aligned to 4KB, 0x{:016X}", size); | ||
| 1486 | return ERR_INVALID_SIZE; | ||
| 1487 | } | ||
| 1284 | 1488 | ||
| 1285 | // Size must be a multiple of 4KB and be less than or equal to | 1489 | if (size >= MAIN_MEMORY_SIZE) { |
| 1286 | // approx. 8 GB (actually (1GB - 512B) * 8) | 1490 | LOG_ERROR(Kernel_SVC, "Size is not less than 8GB, 0x{:016X}", size); |
| 1287 | if (size == 0 || (size & 0xFFFFFFFE00000FFF) != 0) { | ||
| 1288 | return ERR_INVALID_SIZE; | 1491 | return ERR_INVALID_SIZE; |
| 1289 | } | 1492 | } |
| 1290 | 1493 | ||
| 1291 | const auto local_perms = static_cast<MemoryPermission>(local_permissions); | 1494 | const auto local_perms = static_cast<MemoryPermission>(local_permissions); |
| 1292 | if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) { | 1495 | if (local_perms != MemoryPermission::Read && local_perms != MemoryPermission::ReadWrite) { |
| 1496 | LOG_ERROR(Kernel_SVC, | ||
| 1497 | "Invalid local memory permissions, expected Read or ReadWrite but got " | ||
| 1498 | "local_permissions={}", | ||
| 1499 | static_cast<u32>(local_permissions)); | ||
| 1293 | return ERR_INVALID_MEMORY_PERMISSIONS; | 1500 | return ERR_INVALID_MEMORY_PERMISSIONS; |
| 1294 | } | 1501 | } |
| 1295 | 1502 | ||
| 1296 | const auto remote_perms = static_cast<MemoryPermission>(remote_permissions); | 1503 | const auto remote_perms = static_cast<MemoryPermission>(remote_permissions); |
| 1297 | if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite && | 1504 | if (remote_perms != MemoryPermission::Read && remote_perms != MemoryPermission::ReadWrite && |
| 1298 | remote_perms != MemoryPermission::DontCare) { | 1505 | remote_perms != MemoryPermission::DontCare) { |
| 1506 | LOG_ERROR(Kernel_SVC, | ||
| 1507 | "Invalid remote memory permissions, expected Read, ReadWrite or DontCare but got " | ||
| 1508 | "remote_permissions={}", | ||
| 1509 | static_cast<u32>(remote_permissions)); | ||
| 1299 | return ERR_INVALID_MEMORY_PERMISSIONS; | 1510 | return ERR_INVALID_MEMORY_PERMISSIONS; |
| 1300 | } | 1511 | } |
| 1301 | 1512 | ||
| @@ -1315,6 +1526,7 @@ static ResultCode ClearEvent(Handle handle) { | |||
| 1315 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1526 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 1316 | SharedPtr<Event> evt = handle_table.Get<Event>(handle); | 1527 | SharedPtr<Event> evt = handle_table.Get<Event>(handle); |
| 1317 | if (evt == nullptr) { | 1528 | if (evt == nullptr) { |
| 1529 | LOG_ERROR(Kernel_SVC, "Event handle does not exist, handle=0x{:08X}", handle); | ||
| 1318 | return ERR_INVALID_HANDLE; | 1530 | return ERR_INVALID_HANDLE; |
| 1319 | } | 1531 | } |
| 1320 | 1532 | ||
| @@ -1333,11 +1545,14 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) { | |||
| 1333 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); | 1545 | const auto& handle_table = Core::CurrentProcess()->GetHandleTable(); |
| 1334 | const auto process = handle_table.Get<Process>(process_handle); | 1546 | const auto process = handle_table.Get<Process>(process_handle); |
| 1335 | if (!process) { | 1547 | if (!process) { |
| 1548 | LOG_ERROR(Kernel_SVC, "Process handle does not exist, process_handle=0x{:08X}", | ||
| 1549 | process_handle); | ||
| 1336 | return ERR_INVALID_HANDLE; | 1550 | return ERR_INVALID_HANDLE; |
| 1337 | } | 1551 | } |
| 1338 | 1552 | ||
| 1339 | const auto info_type = static_cast<InfoType>(type); | 1553 | const auto info_type = static_cast<InfoType>(type); |
| 1340 | if (info_type != InfoType::Status) { | 1554 | if (info_type != InfoType::Status) { |
| 1555 | LOG_ERROR(Kernel_SVC, "Expected info_type to be Status but got {} instead", type); | ||
| 1341 | return ERR_INVALID_ENUM_VALUE; | 1556 | return ERR_INVALID_ENUM_VALUE; |
| 1342 | } | 1557 | } |
| 1343 | 1558 | ||
| @@ -1345,6 +1560,87 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) { | |||
| 1345 | return RESULT_SUCCESS; | 1560 | return RESULT_SUCCESS; |
| 1346 | } | 1561 | } |
| 1347 | 1562 | ||
| 1563 | static ResultCode CreateResourceLimit(Handle* out_handle) { | ||
| 1564 | LOG_DEBUG(Kernel_SVC, "called"); | ||
| 1565 | |||
| 1566 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 1567 | auto resource_limit = ResourceLimit::Create(kernel); | ||
| 1568 | |||
| 1569 | auto* const current_process = kernel.CurrentProcess(); | ||
| 1570 | ASSERT(current_process != nullptr); | ||
| 1571 | |||
| 1572 | const auto handle = current_process->GetHandleTable().Create(std::move(resource_limit)); | ||
| 1573 | if (handle.Failed()) { | ||
| 1574 | return handle.Code(); | ||
| 1575 | } | ||
| 1576 | |||
| 1577 | *out_handle = *handle; | ||
| 1578 | return RESULT_SUCCESS; | ||
| 1579 | } | ||
| 1580 | |||
| 1581 | static ResultCode GetResourceLimitLimitValue(u64* out_value, Handle resource_limit, | ||
| 1582 | u32 resource_type) { | ||
| 1583 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); | ||
| 1584 | |||
| 1585 | const auto limit_value = RetrieveResourceLimitValue(resource_limit, resource_type, | ||
| 1586 | ResourceLimitValueType::LimitValue); | ||
| 1587 | if (limit_value.Failed()) { | ||
| 1588 | return limit_value.Code(); | ||
| 1589 | } | ||
| 1590 | |||
| 1591 | *out_value = static_cast<u64>(*limit_value); | ||
| 1592 | return RESULT_SUCCESS; | ||
| 1593 | } | ||
| 1594 | |||
| 1595 | static ResultCode GetResourceLimitCurrentValue(u64* out_value, Handle resource_limit, | ||
| 1596 | u32 resource_type) { | ||
| 1597 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}", resource_limit, resource_type); | ||
| 1598 | |||
| 1599 | const auto current_value = RetrieveResourceLimitValue(resource_limit, resource_type, | ||
| 1600 | ResourceLimitValueType::CurrentValue); | ||
| 1601 | if (current_value.Failed()) { | ||
| 1602 | return current_value.Code(); | ||
| 1603 | } | ||
| 1604 | |||
| 1605 | *out_value = static_cast<u64>(*current_value); | ||
| 1606 | return RESULT_SUCCESS; | ||
| 1607 | } | ||
| 1608 | |||
| 1609 | static ResultCode SetResourceLimitLimitValue(Handle resource_limit, u32 resource_type, u64 value) { | ||
| 1610 | LOG_DEBUG(Kernel_SVC, "called. Handle={:08X}, Resource type={}, Value={}", resource_limit, | ||
| 1611 | resource_type, value); | ||
| 1612 | |||
| 1613 | const auto type = static_cast<ResourceType>(resource_type); | ||
| 1614 | if (!IsValidResourceType(type)) { | ||
| 1615 | LOG_ERROR(Kernel_SVC, "Invalid resource limit type: '{}'", resource_type); | ||
| 1616 | return ERR_INVALID_ENUM_VALUE; | ||
| 1617 | } | ||
| 1618 | |||
| 1619 | auto& kernel = Core::System::GetInstance().Kernel(); | ||
| 1620 | auto* const current_process = kernel.CurrentProcess(); | ||
| 1621 | ASSERT(current_process != nullptr); | ||
| 1622 | |||
| 1623 | auto resource_limit_object = | ||
| 1624 | current_process->GetHandleTable().Get<ResourceLimit>(resource_limit); | ||
| 1625 | if (!resource_limit_object) { | ||
| 1626 | LOG_ERROR(Kernel_SVC, "Handle to non-existent resource limit instance used. Handle={:08X}", | ||
| 1627 | resource_limit); | ||
| 1628 | return ERR_INVALID_HANDLE; | ||
| 1629 | } | ||
| 1630 | |||
| 1631 | const auto set_result = resource_limit_object->SetLimitValue(type, static_cast<s64>(value)); | ||
| 1632 | if (set_result.IsError()) { | ||
| 1633 | LOG_ERROR( | ||
| 1634 | Kernel_SVC, | ||
| 1635 | "Attempted to lower resource limit ({}) for category '{}' below its current value ({})", | ||
| 1636 | resource_limit_object->GetMaxResourceValue(type), resource_type, | ||
| 1637 | resource_limit_object->GetCurrentResourceValue(type)); | ||
| 1638 | return set_result; | ||
| 1639 | } | ||
| 1640 | |||
| 1641 | return RESULT_SUCCESS; | ||
| 1642 | } | ||
| 1643 | |||
| 1348 | namespace { | 1644 | namespace { |
| 1349 | struct FunctionDef { | 1645 | struct FunctionDef { |
| 1350 | using Func = void(); | 1646 | using Func = void(); |
| @@ -1404,8 +1700,8 @@ static const FunctionDef SVC_Table[] = { | |||
| 1404 | {0x2D, nullptr, "UnmapPhysicalMemory"}, | 1700 | {0x2D, nullptr, "UnmapPhysicalMemory"}, |
| 1405 | {0x2E, nullptr, "GetFutureThreadInfo"}, | 1701 | {0x2E, nullptr, "GetFutureThreadInfo"}, |
| 1406 | {0x2F, nullptr, "GetLastThreadInfo"}, | 1702 | {0x2F, nullptr, "GetLastThreadInfo"}, |
| 1407 | {0x30, nullptr, "GetResourceLimitLimitValue"}, | 1703 | {0x30, SvcWrap<GetResourceLimitLimitValue>, "GetResourceLimitLimitValue"}, |
| 1408 | {0x31, nullptr, "GetResourceLimitCurrentValue"}, | 1704 | {0x31, SvcWrap<GetResourceLimitCurrentValue>, "GetResourceLimitCurrentValue"}, |
| 1409 | {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, | 1705 | {0x32, SvcWrap<SetThreadActivity>, "SetThreadActivity"}, |
| 1410 | {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, | 1706 | {0x33, SvcWrap<GetThreadContext>, "GetThreadContext"}, |
| 1411 | {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, | 1707 | {0x34, SvcWrap<WaitForAddress>, "WaitForAddress"}, |
| @@ -1481,8 +1777,8 @@ static const FunctionDef SVC_Table[] = { | |||
| 1481 | {0x7A, nullptr, "StartProcess"}, | 1777 | {0x7A, nullptr, "StartProcess"}, |
| 1482 | {0x7B, nullptr, "TerminateProcess"}, | 1778 | {0x7B, nullptr, "TerminateProcess"}, |
| 1483 | {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"}, | 1779 | {0x7C, SvcWrap<GetProcessInfo>, "GetProcessInfo"}, |
| 1484 | {0x7D, nullptr, "CreateResourceLimit"}, | 1780 | {0x7D, SvcWrap<CreateResourceLimit>, "CreateResourceLimit"}, |
| 1485 | {0x7E, nullptr, "SetResourceLimitLimitValue"}, | 1781 | {0x7E, SvcWrap<SetResourceLimitLimitValue>, "SetResourceLimitLimitValue"}, |
| 1486 | {0x7F, nullptr, "CallSecureMonitor"}, | 1782 | {0x7F, nullptr, "CallSecureMonitor"}, |
| 1487 | }; | 1783 | }; |
| 1488 | 1784 | ||
diff --git a/src/core/hle/kernel/svc_wrap.h b/src/core/hle/kernel/svc_wrap.h index 233a99fb0..fa1116624 100644 --- a/src/core/hle/kernel/svc_wrap.h +++ b/src/core/hle/kernel/svc_wrap.h | |||
| @@ -43,6 +43,14 @@ void SvcWrap() { | |||
| 43 | FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw); | 43 | FuncReturn(func(static_cast<u32>(Param(0)), static_cast<u32>(Param(1))).raw); |
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | template <ResultCode func(u32*)> | ||
| 47 | void SvcWrap() { | ||
| 48 | u32 param = 0; | ||
| 49 | const u32 retval = func(¶m).raw; | ||
| 50 | Core::CurrentArmInterface().SetReg(1, param); | ||
| 51 | FuncReturn(retval); | ||
| 52 | } | ||
| 53 | |||
| 46 | template <ResultCode func(u32*, u32)> | 54 | template <ResultCode func(u32*, u32)> |
| 47 | void SvcWrap() { | 55 | void SvcWrap() { |
| 48 | u32 param_1 = 0; | 56 | u32 param_1 = 0; |
diff --git a/src/core/hle/service/acc/acc.cpp b/src/core/hle/service/acc/acc.cpp index c629f9357..1f8ed265e 100644 --- a/src/core/hle/service/acc/acc.cpp +++ b/src/core/hle/service/acc/acc.cpp | |||
| @@ -21,17 +21,6 @@ | |||
| 21 | 21 | ||
| 22 | namespace Service::Account { | 22 | namespace Service::Account { |
| 23 | 23 | ||
| 24 | // TODO: RE this structure | ||
| 25 | struct UserData { | ||
| 26 | INSERT_PADDING_WORDS(1); | ||
| 27 | u32 icon_id; | ||
| 28 | u8 bg_color_id; | ||
| 29 | INSERT_PADDING_BYTES(0x7); | ||
| 30 | INSERT_PADDING_BYTES(0x10); | ||
| 31 | INSERT_PADDING_BYTES(0x60); | ||
| 32 | }; | ||
| 33 | static_assert(sizeof(UserData) == 0x80, "UserData structure has incorrect size"); | ||
| 34 | |||
| 35 | // Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg | 24 | // Smallest JPEG https://github.com/mathiasbynens/small/blob/master/jpeg.jpg |
| 36 | // used as a backup should the one on disk not exist | 25 | // used as a backup should the one on disk not exist |
| 37 | constexpr u32 backup_jpeg_size = 107; | 26 | constexpr u32 backup_jpeg_size = 107; |
| @@ -72,9 +61,11 @@ private: | |||
| 72 | void Get(Kernel::HLERequestContext& ctx) { | 61 | void Get(Kernel::HLERequestContext& ctx) { |
| 73 | LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); | 62 | LOG_INFO(Service_ACC, "called user_id={}", user_id.Format()); |
| 74 | ProfileBase profile_base{}; | 63 | ProfileBase profile_base{}; |
| 75 | std::array<u8, MAX_DATA> data{}; | 64 | ProfileData data{}; |
| 76 | if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { | 65 | if (profile_manager.GetProfileBaseAndData(user_id, profile_base, data)) { |
| 77 | ctx.WriteBuffer(data); | 66 | std::array<u8, sizeof(ProfileData)> raw_data; |
| 67 | std::memcpy(raw_data.data(), &data, sizeof(ProfileData)); | ||
| 68 | ctx.WriteBuffer(raw_data); | ||
| 78 | IPC::ResponseBuilder rb{ctx, 16}; | 69 | IPC::ResponseBuilder rb{ctx, 16}; |
| 79 | rb.Push(RESULT_SUCCESS); | 70 | rb.Push(RESULT_SUCCESS); |
| 80 | rb.PushRaw(profile_base); | 71 | rb.PushRaw(profile_base); |
| @@ -216,10 +207,11 @@ void Module::Interface::GetLastOpenedUser(Kernel::HLERequestContext& ctx) { | |||
| 216 | void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { | 207 | void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { |
| 217 | IPC::RequestParser rp{ctx}; | 208 | IPC::RequestParser rp{ctx}; |
| 218 | UUID user_id = rp.PopRaw<UUID>(); | 209 | UUID user_id = rp.PopRaw<UUID>(); |
| 210 | LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); | ||
| 211 | |||
| 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 212 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 220 | rb.Push(RESULT_SUCCESS); | 213 | rb.Push(RESULT_SUCCESS); |
| 221 | rb.PushIpcInterface<IProfile>(user_id, *profile_manager); | 214 | rb.PushIpcInterface<IProfile>(user_id, *profile_manager); |
| 222 | LOG_DEBUG(Service_ACC, "called user_id={}", user_id.Format()); | ||
| 223 | } | 215 | } |
| 224 | 216 | ||
| 225 | void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) { | 217 | void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) { |
| @@ -236,10 +228,10 @@ void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx | |||
| 236 | } | 228 | } |
| 237 | 229 | ||
| 238 | void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) { | 230 | void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) { |
| 231 | LOG_DEBUG(Service_ACC, "called"); | ||
| 239 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 232 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 240 | rb.Push(RESULT_SUCCESS); | 233 | rb.Push(RESULT_SUCCESS); |
| 241 | rb.PushIpcInterface<IManagerForApplication>(); | 234 | rb.PushIpcInterface<IManagerForApplication>(); |
| 242 | LOG_DEBUG(Service_ACC, "called"); | ||
| 243 | } | 235 | } |
| 244 | 236 | ||
| 245 | void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { | 237 | void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { |
diff --git a/src/core/hle/service/acc/profile_manager.cpp b/src/core/hle/service/acc/profile_manager.cpp index 968263846..1316d0b07 100644 --- a/src/core/hle/service/acc/profile_manager.cpp +++ b/src/core/hle/service/acc/profile_manager.cpp | |||
| @@ -18,7 +18,7 @@ struct UserRaw { | |||
| 18 | UUID uuid2; | 18 | UUID uuid2; |
| 19 | u64 timestamp; | 19 | u64 timestamp; |
| 20 | ProfileUsername username; | 20 | ProfileUsername username; |
| 21 | INSERT_PADDING_BYTES(0x80); | 21 | ProfileData extra_data; |
| 22 | }; | 22 | }; |
| 23 | static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); | 23 | static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); |
| 24 | 24 | ||
| @@ -346,7 +346,7 @@ void ProfileManager::ParseUserSaveFile() { | |||
| 346 | continue; | 346 | continue; |
| 347 | } | 347 | } |
| 348 | 348 | ||
| 349 | AddUser({user.uuid, user.username, user.timestamp, {}, false}); | 349 | AddUser({user.uuid, user.username, user.timestamp, user.extra_data, false}); |
| 350 | } | 350 | } |
| 351 | 351 | ||
| 352 | std::stable_partition(profiles.begin(), profiles.end(), | 352 | std::stable_partition(profiles.begin(), profiles.end(), |
| @@ -361,6 +361,7 @@ void ProfileManager::WriteUserSaveFile() { | |||
| 361 | raw.users[i].uuid2 = profiles[i].user_uuid; | 361 | raw.users[i].uuid2 = profiles[i].user_uuid; |
| 362 | raw.users[i].uuid = profiles[i].user_uuid; | 362 | raw.users[i].uuid = profiles[i].user_uuid; |
| 363 | raw.users[i].timestamp = profiles[i].creation_time; | 363 | raw.users[i].timestamp = profiles[i].creation_time; |
| 364 | raw.users[i].extra_data = profiles[i].data; | ||
| 364 | } | 365 | } |
| 365 | 366 | ||
| 366 | const auto raw_path = | 367 | const auto raw_path = |
diff --git a/src/core/hle/service/acc/profile_manager.h b/src/core/hle/service/acc/profile_manager.h index d2d8e6c6b..c4ce2e0b3 100644 --- a/src/core/hle/service/acc/profile_manager.h +++ b/src/core/hle/service/acc/profile_manager.h | |||
| @@ -13,7 +13,6 @@ | |||
| 13 | 13 | ||
| 14 | namespace Service::Account { | 14 | namespace Service::Account { |
| 15 | constexpr std::size_t MAX_USERS = 8; | 15 | constexpr std::size_t MAX_USERS = 8; |
| 16 | constexpr std::size_t MAX_DATA = 128; | ||
| 17 | constexpr u128 INVALID_UUID{{0, 0}}; | 16 | constexpr u128 INVALID_UUID{{0, 0}}; |
| 18 | 17 | ||
| 19 | struct UUID { | 18 | struct UUID { |
| @@ -50,9 +49,20 @@ static_assert(sizeof(UUID) == 16, "UUID is an invalid size!"); | |||
| 50 | 49 | ||
| 51 | constexpr std::size_t profile_username_size = 32; | 50 | constexpr std::size_t profile_username_size = 32; |
| 52 | using ProfileUsername = std::array<u8, profile_username_size>; | 51 | using ProfileUsername = std::array<u8, profile_username_size>; |
| 53 | using ProfileData = std::array<u8, MAX_DATA>; | ||
| 54 | using UserIDArray = std::array<UUID, MAX_USERS>; | 52 | using UserIDArray = std::array<UUID, MAX_USERS>; |
| 55 | 53 | ||
| 54 | /// Contains extra data related to a user. | ||
| 55 | /// TODO: RE this structure | ||
| 56 | struct ProfileData { | ||
| 57 | INSERT_PADDING_WORDS(1); | ||
| 58 | u32 icon_id; | ||
| 59 | u8 bg_color_id; | ||
| 60 | INSERT_PADDING_BYTES(0x7); | ||
| 61 | INSERT_PADDING_BYTES(0x10); | ||
| 62 | INSERT_PADDING_BYTES(0x60); | ||
| 63 | }; | ||
| 64 | static_assert(sizeof(ProfileData) == 0x80, "ProfileData structure has incorrect size"); | ||
| 65 | |||
| 56 | /// This holds general information about a users profile. This is where we store all the information | 66 | /// This holds general information about a users profile. This is where we store all the information |
| 57 | /// based on a specific user | 67 | /// based on a specific user |
| 58 | struct ProfileInfo { | 68 | struct ProfileInfo { |
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp index 11181a0af..d595c37b0 100644 --- a/src/core/hle/service/am/am.cpp +++ b/src/core/hle/service/am/am.cpp | |||
| @@ -6,8 +6,6 @@ | |||
| 6 | #include <cinttypes> | 6 | #include <cinttypes> |
| 7 | #include <cstring> | 7 | #include <cstring> |
| 8 | #include <stack> | 8 | #include <stack> |
| 9 | #include "applets/applets.h" | ||
| 10 | #include "applets/software_keyboard.h" | ||
| 11 | #include "audio_core/audio_renderer.h" | 9 | #include "audio_core/audio_renderer.h" |
| 12 | #include "core/core.h" | 10 | #include "core/core.h" |
| 13 | #include "core/hle/ipc_helpers.h" | 11 | #include "core/hle/ipc_helpers.h" |
| @@ -18,6 +16,9 @@ | |||
| 18 | #include "core/hle/service/am/am.h" | 16 | #include "core/hle/service/am/am.h" |
| 19 | #include "core/hle/service/am/applet_ae.h" | 17 | #include "core/hle/service/am/applet_ae.h" |
| 20 | #include "core/hle/service/am/applet_oe.h" | 18 | #include "core/hle/service/am/applet_oe.h" |
| 19 | #include "core/hle/service/am/applets/applets.h" | ||
| 20 | #include "core/hle/service/am/applets/software_keyboard.h" | ||
| 21 | #include "core/hle/service/am/applets/stub_applet.h" | ||
| 21 | #include "core/hle/service/am/idle.h" | 22 | #include "core/hle/service/am/idle.h" |
| 22 | #include "core/hle/service/am/omm.h" | 23 | #include "core/hle/service/am/omm.h" |
| 23 | #include "core/hle/service/am/spsm.h" | 24 | #include "core/hle/service/am/spsm.h" |
| @@ -216,6 +217,7 @@ ISelfController::~ISelfController() = default; | |||
| 216 | void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { | 217 | void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { |
| 217 | // Takes 3 input u8s with each field located immediately after the previous | 218 | // Takes 3 input u8s with each field located immediately after the previous |
| 218 | // u8, these are bool flags. No output. | 219 | // u8, these are bool flags. No output. |
| 220 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 219 | 221 | ||
| 220 | IPC::RequestParser rp{ctx}; | 222 | IPC::RequestParser rp{ctx}; |
| 221 | 223 | ||
| @@ -228,44 +230,40 @@ void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { | |||
| 228 | 230 | ||
| 229 | IPC::ResponseBuilder rb{ctx, 2}; | 231 | IPC::ResponseBuilder rb{ctx, 2}; |
| 230 | rb.Push(RESULT_SUCCESS); | 232 | rb.Push(RESULT_SUCCESS); |
| 231 | |||
| 232 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 233 | } | 233 | } |
| 234 | 234 | ||
| 235 | void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { | 235 | void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { |
| 236 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 237 | |||
| 236 | IPC::ResponseBuilder rb{ctx, 2}; | 238 | IPC::ResponseBuilder rb{ctx, 2}; |
| 237 | rb.Push(RESULT_SUCCESS); | 239 | rb.Push(RESULT_SUCCESS); |
| 238 | |||
| 239 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 240 | } | 240 | } |
| 241 | 241 | ||
| 242 | void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { | 242 | void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { |
| 243 | IPC::RequestParser rp{ctx}; | 243 | IPC::RequestParser rp{ctx}; |
| 244 | 244 | ||
| 245 | bool flag = rp.Pop<bool>(); | 245 | bool flag = rp.Pop<bool>(); |
| 246 | LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); | ||
| 246 | 247 | ||
| 247 | IPC::ResponseBuilder rb{ctx, 2}; | 248 | IPC::ResponseBuilder rb{ctx, 2}; |
| 248 | rb.Push(RESULT_SUCCESS); | 249 | rb.Push(RESULT_SUCCESS); |
| 249 | |||
| 250 | LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); | ||
| 251 | } | 250 | } |
| 252 | 251 | ||
| 253 | void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { | 252 | void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { |
| 253 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 254 | |||
| 254 | IPC::ResponseBuilder rb{ctx, 2}; | 255 | IPC::ResponseBuilder rb{ctx, 2}; |
| 255 | rb.Push(RESULT_SUCCESS); | 256 | rb.Push(RESULT_SUCCESS); |
| 256 | |||
| 257 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 258 | } | 257 | } |
| 259 | 258 | ||
| 260 | void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { | 259 | void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { |
| 261 | IPC::RequestParser rp{ctx}; | 260 | IPC::RequestParser rp{ctx}; |
| 262 | 261 | ||
| 263 | bool flag = rp.Pop<bool>(); | 262 | bool flag = rp.Pop<bool>(); |
| 263 | LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); | ||
| 264 | 264 | ||
| 265 | IPC::ResponseBuilder rb{ctx, 2}; | 265 | IPC::ResponseBuilder rb{ctx, 2}; |
| 266 | rb.Push(RESULT_SUCCESS); | 266 | rb.Push(RESULT_SUCCESS); |
| 267 | |||
| 268 | LOG_WARNING(Service_AM, "(STUBBED) called flag={}", flag); | ||
| 269 | } | 267 | } |
| 270 | 268 | ||
| 271 | void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { | 269 | void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { |
| @@ -274,45 +272,45 @@ void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& | |||
| 274 | IPC::RequestParser rp{ctx}; | 272 | IPC::RequestParser rp{ctx}; |
| 275 | 273 | ||
| 276 | bool enabled = rp.Pop<bool>(); | 274 | bool enabled = rp.Pop<bool>(); |
| 275 | LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); | ||
| 277 | 276 | ||
| 278 | IPC::ResponseBuilder rb{ctx, 2}; | 277 | IPC::ResponseBuilder rb{ctx, 2}; |
| 279 | rb.Push(RESULT_SUCCESS); | 278 | rb.Push(RESULT_SUCCESS); |
| 280 | |||
| 281 | LOG_WARNING(Service_AM, "(STUBBED) called enabled={}", enabled); | ||
| 282 | } | 279 | } |
| 283 | 280 | ||
| 284 | void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { | 281 | void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { |
| 282 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 283 | |||
| 285 | IPC::ResponseBuilder rb{ctx, 2}; | 284 | IPC::ResponseBuilder rb{ctx, 2}; |
| 286 | rb.Push(RESULT_SUCCESS); | 285 | rb.Push(RESULT_SUCCESS); |
| 287 | |||
| 288 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 289 | } | 286 | } |
| 290 | 287 | ||
| 291 | void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { | 288 | void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { |
| 289 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 290 | |||
| 292 | IPC::ResponseBuilder rb{ctx, 2}; | 291 | IPC::ResponseBuilder rb{ctx, 2}; |
| 293 | rb.Push(RESULT_SUCCESS); | 292 | rb.Push(RESULT_SUCCESS); |
| 294 | |||
| 295 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 296 | } | 293 | } |
| 297 | 294 | ||
| 298 | void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { | 295 | void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { |
| 296 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 297 | |||
| 299 | launchable_event->Signal(); | 298 | launchable_event->Signal(); |
| 300 | 299 | ||
| 301 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 300 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 302 | rb.Push(RESULT_SUCCESS); | 301 | rb.Push(RESULT_SUCCESS); |
| 303 | rb.PushCopyObjects(launchable_event); | 302 | rb.PushCopyObjects(launchable_event); |
| 304 | |||
| 305 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 306 | } | 303 | } |
| 307 | 304 | ||
| 308 | void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { | 305 | void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { |
| 306 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 307 | |||
| 309 | IPC::ResponseBuilder rb{ctx, 2}; | 308 | IPC::ResponseBuilder rb{ctx, 2}; |
| 310 | rb.Push(RESULT_SUCCESS); | 309 | rb.Push(RESULT_SUCCESS); |
| 311 | |||
| 312 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 313 | } | 310 | } |
| 314 | 311 | ||
| 315 | void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { | 312 | void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { |
| 313 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 316 | // TODO(Subv): Find out how AM determines the display to use, for now just | 314 | // TODO(Subv): Find out how AM determines the display to use, for now just |
| 317 | // create the layer in the Default display. | 315 | // create the layer in the Default display. |
| 318 | u64 display_id = nvflinger->OpenDisplay("Default"); | 316 | u64 display_id = nvflinger->OpenDisplay("Default"); |
| @@ -321,32 +319,31 @@ void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) | |||
| 321 | IPC::ResponseBuilder rb{ctx, 4}; | 319 | IPC::ResponseBuilder rb{ctx, 4}; |
| 322 | rb.Push(RESULT_SUCCESS); | 320 | rb.Push(RESULT_SUCCESS); |
| 323 | rb.Push(layer_id); | 321 | rb.Push(layer_id); |
| 324 | |||
| 325 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 326 | } | 322 | } |
| 327 | 323 | ||
| 328 | void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) { | 324 | void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) { |
| 325 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 326 | |||
| 329 | IPC::ResponseBuilder rb{ctx, 2}; | 327 | IPC::ResponseBuilder rb{ctx, 2}; |
| 330 | rb.Push(RESULT_SUCCESS); | 328 | rb.Push(RESULT_SUCCESS); |
| 331 | |||
| 332 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 333 | } | 329 | } |
| 334 | 330 | ||
| 335 | void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { | 331 | void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { |
| 336 | IPC::RequestParser rp{ctx}; | 332 | IPC::RequestParser rp{ctx}; |
| 337 | idle_time_detection_extension = rp.Pop<u32>(); | 333 | idle_time_detection_extension = rp.Pop<u32>(); |
| 334 | LOG_WARNING(Service_AM, "(STUBBED) called idle_time_detection_extension={}", | ||
| 335 | idle_time_detection_extension); | ||
| 336 | |||
| 338 | IPC::ResponseBuilder rb{ctx, 2}; | 337 | IPC::ResponseBuilder rb{ctx, 2}; |
| 339 | rb.Push(RESULT_SUCCESS); | 338 | rb.Push(RESULT_SUCCESS); |
| 340 | |||
| 341 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 342 | } | 339 | } |
| 343 | 340 | ||
| 344 | void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { | 341 | void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { |
| 342 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 343 | |||
| 345 | IPC::ResponseBuilder rb{ctx, 3}; | 344 | IPC::ResponseBuilder rb{ctx, 3}; |
| 346 | rb.Push(RESULT_SUCCESS); | 345 | rb.Push(RESULT_SUCCESS); |
| 347 | rb.Push<u32>(idle_time_detection_extension); | 346 | rb.Push<u32>(idle_time_detection_extension); |
| 348 | |||
| 349 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 350 | } | 347 | } |
| 351 | 348 | ||
| 352 | AppletMessageQueue::AppletMessageQueue() { | 349 | AppletMessageQueue::AppletMessageQueue() { |
| @@ -437,59 +434,63 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q | |||
| 437 | ICommonStateGetter::~ICommonStateGetter() = default; | 434 | ICommonStateGetter::~ICommonStateGetter() = default; |
| 438 | 435 | ||
| 439 | void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { | 436 | void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { |
| 437 | LOG_DEBUG(Service_AM, "called"); | ||
| 438 | |||
| 440 | IPC::ResponseBuilder rb{ctx, 3}; | 439 | IPC::ResponseBuilder rb{ctx, 3}; |
| 441 | rb.Push(RESULT_SUCCESS); | 440 | rb.Push(RESULT_SUCCESS); |
| 442 | 441 | ||
| 443 | rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode | 442 | rb.Push<u8>(static_cast<u8>(Service::PM::SystemBootMode::Normal)); // Normal boot mode |
| 444 | |||
| 445 | LOG_DEBUG(Service_AM, "called"); | ||
| 446 | } | 443 | } |
| 447 | 444 | ||
| 448 | void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { | 445 | void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { |
| 446 | LOG_DEBUG(Service_AM, "called"); | ||
| 447 | |||
| 449 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 448 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 450 | rb.Push(RESULT_SUCCESS); | 449 | rb.Push(RESULT_SUCCESS); |
| 451 | rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent()); | 450 | rb.PushCopyObjects(msg_queue->GetMesssageRecieveEvent()); |
| 452 | |||
| 453 | LOG_DEBUG(Service_AM, "called"); | ||
| 454 | } | 451 | } |
| 455 | 452 | ||
| 456 | void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { | 453 | void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { |
| 454 | LOG_DEBUG(Service_AM, "called"); | ||
| 455 | |||
| 457 | IPC::ResponseBuilder rb{ctx, 3}; | 456 | IPC::ResponseBuilder rb{ctx, 3}; |
| 458 | rb.Push(RESULT_SUCCESS); | 457 | rb.Push(RESULT_SUCCESS); |
| 459 | rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage()); | 458 | rb.PushEnum<AppletMessageQueue::AppletMessage>(msg_queue->PopMessage()); |
| 460 | |||
| 461 | LOG_DEBUG(Service_AM, "called"); | ||
| 462 | } | 459 | } |
| 463 | 460 | ||
| 464 | void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { | 461 | void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { |
| 462 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 463 | |||
| 465 | IPC::ResponseBuilder rb{ctx, 3}; | 464 | IPC::ResponseBuilder rb{ctx, 3}; |
| 466 | rb.Push(RESULT_SUCCESS); | 465 | rb.Push(RESULT_SUCCESS); |
| 467 | rb.Push(static_cast<u8>(FocusState::InFocus)); | 466 | rb.Push(static_cast<u8>(FocusState::InFocus)); |
| 468 | |||
| 469 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 470 | } | 467 | } |
| 471 | 468 | ||
| 472 | void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { | 469 | void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { |
| 470 | LOG_DEBUG(Service_AM, "called"); | ||
| 471 | |||
| 473 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 472 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 474 | rb.Push(RESULT_SUCCESS); | 473 | rb.Push(RESULT_SUCCESS); |
| 475 | rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); | 474 | rb.PushCopyObjects(msg_queue->GetOperationModeChangedEvent()); |
| 476 | |||
| 477 | LOG_DEBUG(Service_AM, "called"); | ||
| 478 | } | 475 | } |
| 479 | 476 | ||
| 480 | void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) { | 477 | void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) { |
| 478 | LOG_DEBUG(Service_AM, "called"); | ||
| 479 | |||
| 481 | IPC::ResponseBuilder rb{ctx, 4}; | 480 | IPC::ResponseBuilder rb{ctx, 4}; |
| 482 | rb.Push(RESULT_SUCCESS); | 481 | rb.Push(RESULT_SUCCESS); |
| 483 | 482 | ||
| 484 | if (Settings::values.use_docked_mode) { | 483 | if (Settings::values.use_docked_mode) { |
| 485 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); | 484 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * |
| 486 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); | 485 | static_cast<u32>(Settings::values.resolution_factor)); |
| 486 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * | ||
| 487 | static_cast<u32>(Settings::values.resolution_factor)); | ||
| 487 | } else { | 488 | } else { |
| 488 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); | 489 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) * |
| 489 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); | 490 | static_cast<u32>(Settings::values.resolution_factor)); |
| 491 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) * | ||
| 492 | static_cast<u32>(Settings::values.resolution_factor)); | ||
| 490 | } | 493 | } |
| 491 | |||
| 492 | LOG_DEBUG(Service_AM, "called"); | ||
| 493 | } | 494 | } |
| 494 | 495 | ||
| 495 | IStorage::IStorage(std::vector<u8> buffer) | 496 | IStorage::IStorage(std::vector<u8> buffer) |
| @@ -512,21 +513,21 @@ const std::vector<u8>& IStorage::GetData() const { | |||
| 512 | 513 | ||
| 513 | void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { | 514 | void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { |
| 514 | const bool use_docked_mode{Settings::values.use_docked_mode}; | 515 | const bool use_docked_mode{Settings::values.use_docked_mode}; |
| 516 | LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); | ||
| 517 | |||
| 515 | IPC::ResponseBuilder rb{ctx, 3}; | 518 | IPC::ResponseBuilder rb{ctx, 3}; |
| 516 | rb.Push(RESULT_SUCCESS); | 519 | rb.Push(RESULT_SUCCESS); |
| 517 | rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); | 520 | rb.Push(static_cast<u8>(use_docked_mode ? OperationMode::Docked : OperationMode::Handheld)); |
| 518 | |||
| 519 | LOG_DEBUG(Service_AM, "called"); | ||
| 520 | } | 521 | } |
| 521 | 522 | ||
| 522 | void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { | 523 | void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { |
| 523 | const bool use_docked_mode{Settings::values.use_docked_mode}; | 524 | const bool use_docked_mode{Settings::values.use_docked_mode}; |
| 525 | LOG_DEBUG(Service_AM, "called, use_docked_mode={}", use_docked_mode); | ||
| 526 | |||
| 524 | IPC::ResponseBuilder rb{ctx, 3}; | 527 | IPC::ResponseBuilder rb{ctx, 3}; |
| 525 | rb.Push(RESULT_SUCCESS); | 528 | rb.Push(RESULT_SUCCESS); |
| 526 | rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked | 529 | rb.Push(static_cast<u32>(use_docked_mode ? APM::PerformanceMode::Docked |
| 527 | : APM::PerformanceMode::Handheld)); | 530 | : APM::PerformanceMode::Handheld)); |
| 528 | |||
| 529 | LOG_DEBUG(Service_AM, "called"); | ||
| 530 | } | 531 | } |
| 531 | 532 | ||
| 532 | class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { | 533 | class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { |
| @@ -561,32 +562,34 @@ public: | |||
| 561 | 562 | ||
| 562 | private: | 563 | private: |
| 563 | void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { | 564 | void GetAppletStateChangedEvent(Kernel::HLERequestContext& ctx) { |
| 565 | LOG_DEBUG(Service_AM, "called"); | ||
| 566 | |||
| 564 | const auto event = applet->GetBroker().GetStateChangedEvent(); | 567 | const auto event = applet->GetBroker().GetStateChangedEvent(); |
| 565 | event->Signal(); | 568 | event->Signal(); |
| 566 | 569 | ||
| 567 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 570 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 568 | rb.Push(RESULT_SUCCESS); | 571 | rb.Push(RESULT_SUCCESS); |
| 569 | rb.PushCopyObjects(event); | 572 | rb.PushCopyObjects(event); |
| 570 | |||
| 571 | LOG_DEBUG(Service_AM, "called"); | ||
| 572 | } | 573 | } |
| 573 | 574 | ||
| 574 | void IsCompleted(Kernel::HLERequestContext& ctx) { | 575 | void IsCompleted(Kernel::HLERequestContext& ctx) { |
| 576 | LOG_DEBUG(Service_AM, "called"); | ||
| 577 | |||
| 575 | IPC::ResponseBuilder rb{ctx, 3}; | 578 | IPC::ResponseBuilder rb{ctx, 3}; |
| 576 | rb.Push(RESULT_SUCCESS); | 579 | rb.Push(RESULT_SUCCESS); |
| 577 | rb.Push<u32>(applet->TransactionComplete()); | 580 | rb.Push<u32>(applet->TransactionComplete()); |
| 578 | |||
| 579 | LOG_DEBUG(Service_AM, "called"); | ||
| 580 | } | 581 | } |
| 581 | 582 | ||
| 582 | void GetResult(Kernel::HLERequestContext& ctx) { | 583 | void GetResult(Kernel::HLERequestContext& ctx) { |
| 584 | LOG_DEBUG(Service_AM, "called"); | ||
| 585 | |||
| 583 | IPC::ResponseBuilder rb{ctx, 2}; | 586 | IPC::ResponseBuilder rb{ctx, 2}; |
| 584 | rb.Push(applet->GetStatus()); | 587 | rb.Push(applet->GetStatus()); |
| 585 | |||
| 586 | LOG_DEBUG(Service_AM, "called"); | ||
| 587 | } | 588 | } |
| 588 | 589 | ||
| 589 | void Start(Kernel::HLERequestContext& ctx) { | 590 | void Start(Kernel::HLERequestContext& ctx) { |
| 591 | LOG_DEBUG(Service_AM, "called"); | ||
| 592 | |||
| 590 | ASSERT(applet != nullptr); | 593 | ASSERT(applet != nullptr); |
| 591 | 594 | ||
| 592 | applet->Initialize(); | 595 | applet->Initialize(); |
| @@ -594,36 +597,39 @@ private: | |||
| 594 | 597 | ||
| 595 | IPC::ResponseBuilder rb{ctx, 2}; | 598 | IPC::ResponseBuilder rb{ctx, 2}; |
| 596 | rb.Push(RESULT_SUCCESS); | 599 | rb.Push(RESULT_SUCCESS); |
| 597 | |||
| 598 | LOG_DEBUG(Service_AM, "called"); | ||
| 599 | } | 600 | } |
| 600 | 601 | ||
| 601 | void PushInData(Kernel::HLERequestContext& ctx) { | 602 | void PushInData(Kernel::HLERequestContext& ctx) { |
| 603 | LOG_DEBUG(Service_AM, "called"); | ||
| 604 | |||
| 602 | IPC::RequestParser rp{ctx}; | 605 | IPC::RequestParser rp{ctx}; |
| 603 | applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>()); | 606 | applet->GetBroker().PushNormalDataFromGame(*rp.PopIpcInterface<IStorage>()); |
| 604 | 607 | ||
| 605 | IPC::ResponseBuilder rb{ctx, 2}; | 608 | IPC::ResponseBuilder rb{ctx, 2}; |
| 606 | rb.Push(RESULT_SUCCESS); | 609 | rb.Push(RESULT_SUCCESS); |
| 607 | |||
| 608 | LOG_DEBUG(Service_AM, "called"); | ||
| 609 | } | 610 | } |
| 610 | 611 | ||
| 611 | void PopOutData(Kernel::HLERequestContext& ctx) { | 612 | void PopOutData(Kernel::HLERequestContext& ctx) { |
| 613 | LOG_DEBUG(Service_AM, "called"); | ||
| 614 | |||
| 612 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 615 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 613 | 616 | ||
| 614 | const auto storage = applet->GetBroker().PopNormalDataToGame(); | 617 | const auto storage = applet->GetBroker().PopNormalDataToGame(); |
| 615 | if (storage == nullptr) { | 618 | if (storage == nullptr) { |
| 619 | LOG_ERROR(Service_AM, | ||
| 620 | "storage is a nullptr. There is no data in the current normal channel"); | ||
| 621 | |||
| 616 | rb.Push(ERR_NO_DATA_IN_CHANNEL); | 622 | rb.Push(ERR_NO_DATA_IN_CHANNEL); |
| 617 | return; | 623 | return; |
| 618 | } | 624 | } |
| 619 | 625 | ||
| 620 | rb.Push(RESULT_SUCCESS); | 626 | rb.Push(RESULT_SUCCESS); |
| 621 | rb.PushIpcInterface<IStorage>(std::move(*storage)); | 627 | rb.PushIpcInterface<IStorage>(std::move(*storage)); |
| 622 | |||
| 623 | LOG_DEBUG(Service_AM, "called"); | ||
| 624 | } | 628 | } |
| 625 | 629 | ||
| 626 | void PushInteractiveInData(Kernel::HLERequestContext& ctx) { | 630 | void PushInteractiveInData(Kernel::HLERequestContext& ctx) { |
| 631 | LOG_DEBUG(Service_AM, "called"); | ||
| 632 | |||
| 627 | IPC::RequestParser rp{ctx}; | 633 | IPC::RequestParser rp{ctx}; |
| 628 | applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>()); | 634 | applet->GetBroker().PushInteractiveDataFromGame(*rp.PopIpcInterface<IStorage>()); |
| 629 | 635 | ||
| @@ -633,51 +639,52 @@ private: | |||
| 633 | 639 | ||
| 634 | IPC::ResponseBuilder rb{ctx, 2}; | 640 | IPC::ResponseBuilder rb{ctx, 2}; |
| 635 | rb.Push(RESULT_SUCCESS); | 641 | rb.Push(RESULT_SUCCESS); |
| 636 | |||
| 637 | LOG_DEBUG(Service_AM, "called"); | ||
| 638 | } | 642 | } |
| 639 | 643 | ||
| 640 | void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { | 644 | void PopInteractiveOutData(Kernel::HLERequestContext& ctx) { |
| 645 | LOG_DEBUG(Service_AM, "called"); | ||
| 646 | |||
| 641 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 647 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 642 | 648 | ||
| 643 | const auto storage = applet->GetBroker().PopInteractiveDataToGame(); | 649 | const auto storage = applet->GetBroker().PopInteractiveDataToGame(); |
| 644 | if (storage == nullptr) { | 650 | if (storage == nullptr) { |
| 651 | LOG_ERROR(Service_AM, | ||
| 652 | "storage is a nullptr. There is no data in the current interactive channel"); | ||
| 653 | |||
| 645 | rb.Push(ERR_NO_DATA_IN_CHANNEL); | 654 | rb.Push(ERR_NO_DATA_IN_CHANNEL); |
| 646 | return; | 655 | return; |
| 647 | } | 656 | } |
| 648 | 657 | ||
| 649 | rb.Push(RESULT_SUCCESS); | 658 | rb.Push(RESULT_SUCCESS); |
| 650 | rb.PushIpcInterface<IStorage>(std::move(*storage)); | 659 | rb.PushIpcInterface<IStorage>(std::move(*storage)); |
| 651 | |||
| 652 | LOG_DEBUG(Service_AM, "called"); | ||
| 653 | } | 660 | } |
| 654 | 661 | ||
| 655 | void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) { | 662 | void GetPopOutDataEvent(Kernel::HLERequestContext& ctx) { |
| 663 | LOG_DEBUG(Service_AM, "called"); | ||
| 664 | |||
| 656 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 665 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 657 | rb.Push(RESULT_SUCCESS); | 666 | rb.Push(RESULT_SUCCESS); |
| 658 | rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent()); | 667 | rb.PushCopyObjects(applet->GetBroker().GetNormalDataEvent()); |
| 659 | |||
| 660 | LOG_DEBUG(Service_AM, "called"); | ||
| 661 | } | 668 | } |
| 662 | 669 | ||
| 663 | void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) { | 670 | void GetPopInteractiveOutDataEvent(Kernel::HLERequestContext& ctx) { |
| 671 | LOG_DEBUG(Service_AM, "called"); | ||
| 672 | |||
| 664 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 673 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 665 | rb.Push(RESULT_SUCCESS); | 674 | rb.Push(RESULT_SUCCESS); |
| 666 | rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); | 675 | rb.PushCopyObjects(applet->GetBroker().GetInteractiveDataEvent()); |
| 667 | |||
| 668 | LOG_DEBUG(Service_AM, "called"); | ||
| 669 | } | 676 | } |
| 670 | 677 | ||
| 671 | std::shared_ptr<Applets::Applet> applet; | 678 | std::shared_ptr<Applets::Applet> applet; |
| 672 | }; | 679 | }; |
| 673 | 680 | ||
| 674 | void IStorage::Open(Kernel::HLERequestContext& ctx) { | 681 | void IStorage::Open(Kernel::HLERequestContext& ctx) { |
| 682 | LOG_DEBUG(Service_AM, "called"); | ||
| 683 | |||
| 675 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 684 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 676 | 685 | ||
| 677 | rb.Push(RESULT_SUCCESS); | 686 | rb.Push(RESULT_SUCCESS); |
| 678 | rb.PushIpcInterface<IStorageAccessor>(*this); | 687 | rb.PushIpcInterface<IStorageAccessor>(*this); |
| 679 | |||
| 680 | LOG_DEBUG(Service_AM, "called"); | ||
| 681 | } | 688 | } |
| 682 | 689 | ||
| 683 | IStorageAccessor::IStorageAccessor(IStorage& storage) | 690 | IStorageAccessor::IStorageAccessor(IStorage& storage) |
| @@ -696,21 +703,27 @@ IStorageAccessor::IStorageAccessor(IStorage& storage) | |||
| 696 | IStorageAccessor::~IStorageAccessor() = default; | 703 | IStorageAccessor::~IStorageAccessor() = default; |
| 697 | 704 | ||
| 698 | void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) { | 705 | void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) { |
| 706 | LOG_DEBUG(Service_AM, "called"); | ||
| 707 | |||
| 699 | IPC::ResponseBuilder rb{ctx, 4}; | 708 | IPC::ResponseBuilder rb{ctx, 4}; |
| 700 | 709 | ||
| 701 | rb.Push(RESULT_SUCCESS); | 710 | rb.Push(RESULT_SUCCESS); |
| 702 | rb.Push(static_cast<u64>(backing.buffer.size())); | 711 | rb.Push(static_cast<u64>(backing.buffer.size())); |
| 703 | |||
| 704 | LOG_DEBUG(Service_AM, "called"); | ||
| 705 | } | 712 | } |
| 706 | 713 | ||
| 707 | void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { | 714 | void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { |
| 708 | IPC::RequestParser rp{ctx}; | 715 | IPC::RequestParser rp{ctx}; |
| 709 | 716 | ||
| 710 | const u64 offset{rp.Pop<u64>()}; | 717 | const u64 offset{rp.Pop<u64>()}; |
| 718 | LOG_DEBUG(Service_AM, "called, offset={}", offset); | ||
| 719 | |||
| 711 | const std::vector<u8> data{ctx.ReadBuffer()}; | 720 | const std::vector<u8> data{ctx.ReadBuffer()}; |
| 712 | 721 | ||
| 713 | if (data.size() > backing.buffer.size() - offset) { | 722 | if (data.size() > backing.buffer.size() - offset) { |
| 723 | LOG_ERROR(Service_AM, | ||
| 724 | "offset is out of bounds, backing_buffer_sz={}, data_size={}, offset={}", | ||
| 725 | backing.buffer.size(), data.size(), offset); | ||
| 726 | |||
| 714 | IPC::ResponseBuilder rb{ctx, 2}; | 727 | IPC::ResponseBuilder rb{ctx, 2}; |
| 715 | rb.Push(ERR_SIZE_OUT_OF_BOUNDS); | 728 | rb.Push(ERR_SIZE_OUT_OF_BOUNDS); |
| 716 | } | 729 | } |
| @@ -719,17 +732,20 @@ void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { | |||
| 719 | 732 | ||
| 720 | IPC::ResponseBuilder rb{ctx, 2}; | 733 | IPC::ResponseBuilder rb{ctx, 2}; |
| 721 | rb.Push(RESULT_SUCCESS); | 734 | rb.Push(RESULT_SUCCESS); |
| 722 | |||
| 723 | LOG_DEBUG(Service_AM, "called, offset={}", offset); | ||
| 724 | } | 735 | } |
| 725 | 736 | ||
| 726 | void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { | 737 | void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { |
| 727 | IPC::RequestParser rp{ctx}; | 738 | IPC::RequestParser rp{ctx}; |
| 728 | 739 | ||
| 729 | const u64 offset{rp.Pop<u64>()}; | 740 | const u64 offset{rp.Pop<u64>()}; |
| 741 | LOG_DEBUG(Service_AM, "called, offset={}", offset); | ||
| 742 | |||
| 730 | const std::size_t size{ctx.GetWriteBufferSize()}; | 743 | const std::size_t size{ctx.GetWriteBufferSize()}; |
| 731 | 744 | ||
| 732 | if (size > backing.buffer.size() - offset) { | 745 | if (size > backing.buffer.size() - offset) { |
| 746 | LOG_ERROR(Service_AM, "offset is out of bounds, backing_buffer_sz={}, size={}, offset={}", | ||
| 747 | backing.buffer.size(), size, offset); | ||
| 748 | |||
| 733 | IPC::ResponseBuilder rb{ctx, 2}; | 749 | IPC::ResponseBuilder rb{ctx, 2}; |
| 734 | rb.Push(ERR_SIZE_OUT_OF_BOUNDS); | 750 | rb.Push(ERR_SIZE_OUT_OF_BOUNDS); |
| 735 | } | 751 | } |
| @@ -738,8 +754,6 @@ void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { | |||
| 738 | 754 | ||
| 739 | IPC::ResponseBuilder rb{ctx, 2}; | 755 | IPC::ResponseBuilder rb{ctx, 2}; |
| 740 | rb.Push(RESULT_SUCCESS); | 756 | rb.Push(RESULT_SUCCESS); |
| 741 | |||
| 742 | LOG_DEBUG(Service_AM, "called, offset={}", offset); | ||
| 743 | } | 757 | } |
| 744 | 758 | ||
| 745 | ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") { | 759 | ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") { |
| @@ -761,8 +775,9 @@ static std::shared_ptr<Applets::Applet> GetAppletFromId(AppletId id) { | |||
| 761 | case AppletId::SoftwareKeyboard: | 775 | case AppletId::SoftwareKeyboard: |
| 762 | return std::make_shared<Applets::SoftwareKeyboard>(); | 776 | return std::make_shared<Applets::SoftwareKeyboard>(); |
| 763 | default: | 777 | default: |
| 764 | UNREACHABLE_MSG("Unimplemented AppletId [{:08X}]!", static_cast<u32>(id)); | 778 | LOG_ERROR(Service_AM, "Unimplemented AppletId [{:08X}]! -- Falling back to stub!", |
| 765 | return nullptr; | 779 | static_cast<u32>(id)); |
| 780 | return std::make_shared<Applets::StubApplet>(); | ||
| 766 | } | 781 | } |
| 767 | } | 782 | } |
| 768 | 783 | ||
| @@ -777,6 +792,8 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) | |||
| 777 | const auto applet = GetAppletFromId(applet_id); | 792 | const auto applet = GetAppletFromId(applet_id); |
| 778 | 793 | ||
| 779 | if (applet == nullptr) { | 794 | if (applet == nullptr) { |
| 795 | LOG_ERROR(Service_AM, "Applet doesn't exist! applet_id={}", static_cast<u32>(applet_id)); | ||
| 796 | |||
| 780 | IPC::ResponseBuilder rb{ctx, 2}; | 797 | IPC::ResponseBuilder rb{ctx, 2}; |
| 781 | rb.Push(ResultCode(-1)); | 798 | rb.Push(ResultCode(-1)); |
| 782 | return; | 799 | return; |
| @@ -786,23 +803,23 @@ void ILibraryAppletCreator::CreateLibraryApplet(Kernel::HLERequestContext& ctx) | |||
| 786 | 803 | ||
| 787 | rb.Push(RESULT_SUCCESS); | 804 | rb.Push(RESULT_SUCCESS); |
| 788 | rb.PushIpcInterface<AM::ILibraryAppletAccessor>(applet); | 805 | rb.PushIpcInterface<AM::ILibraryAppletAccessor>(applet); |
| 789 | |||
| 790 | LOG_DEBUG(Service_AM, "called"); | ||
| 791 | } | 806 | } |
| 792 | 807 | ||
| 793 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { | 808 | void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { |
| 794 | IPC::RequestParser rp{ctx}; | 809 | IPC::RequestParser rp{ctx}; |
| 795 | const u64 size{rp.Pop<u64>()}; | 810 | const u64 size{rp.Pop<u64>()}; |
| 811 | LOG_DEBUG(Service_AM, "called, size={}", size); | ||
| 812 | |||
| 796 | std::vector<u8> buffer(size); | 813 | std::vector<u8> buffer(size); |
| 797 | 814 | ||
| 798 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 815 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 799 | rb.Push(RESULT_SUCCESS); | 816 | rb.Push(RESULT_SUCCESS); |
| 800 | rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); | 817 | rb.PushIpcInterface<AM::IStorage>(std::move(buffer)); |
| 801 | |||
| 802 | LOG_DEBUG(Service_AM, "called, size={}", size); | ||
| 803 | } | 818 | } |
| 804 | 819 | ||
| 805 | void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { | 820 | void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { |
| 821 | LOG_DEBUG(Service_AM, "called"); | ||
| 822 | |||
| 806 | IPC::RequestParser rp{ctx}; | 823 | IPC::RequestParser rp{ctx}; |
| 807 | 824 | ||
| 808 | rp.SetCurrentOffset(3); | 825 | rp.SetCurrentOffset(3); |
| @@ -813,6 +830,7 @@ void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContex | |||
| 813 | handle); | 830 | handle); |
| 814 | 831 | ||
| 815 | if (shared_mem == nullptr) { | 832 | if (shared_mem == nullptr) { |
| 833 | LOG_ERROR(Service_AM, "shared_mem is a nullpr for handle={:08X}", handle); | ||
| 816 | IPC::ResponseBuilder rb{ctx, 2}; | 834 | IPC::ResponseBuilder rb{ctx, 2}; |
| 817 | rb.Push(ResultCode(-1)); | 835 | rb.Push(ResultCode(-1)); |
| 818 | return; | 836 | return; |
| @@ -876,38 +894,45 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF | |||
| 876 | IApplicationFunctions::~IApplicationFunctions() = default; | 894 | IApplicationFunctions::~IApplicationFunctions() = default; |
| 877 | 895 | ||
| 878 | void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) { | 896 | void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) { |
| 897 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 898 | |||
| 879 | IPC::ResponseBuilder rb{ctx, 2}; | 899 | IPC::ResponseBuilder rb{ctx, 2}; |
| 880 | rb.Push(RESULT_SUCCESS); | 900 | rb.Push(RESULT_SUCCESS); |
| 881 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 882 | } | 901 | } |
| 883 | 902 | ||
| 884 | void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed( | 903 | void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed( |
| 885 | Kernel::HLERequestContext& ctx) { | 904 | Kernel::HLERequestContext& ctx) { |
| 905 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 906 | |||
| 886 | IPC::ResponseBuilder rb{ctx, 2}; | 907 | IPC::ResponseBuilder rb{ctx, 2}; |
| 887 | rb.Push(RESULT_SUCCESS); | 908 | rb.Push(RESULT_SUCCESS); |
| 888 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 889 | } | 909 | } |
| 890 | 910 | ||
| 891 | void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed( | 911 | void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed( |
| 892 | Kernel::HLERequestContext& ctx) { | 912 | Kernel::HLERequestContext& ctx) { |
| 913 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 914 | |||
| 893 | IPC::ResponseBuilder rb{ctx, 2}; | 915 | IPC::ResponseBuilder rb{ctx, 2}; |
| 894 | rb.Push(RESULT_SUCCESS); | 916 | rb.Push(RESULT_SUCCESS); |
| 895 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 896 | } | 917 | } |
| 897 | 918 | ||
| 898 | void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) { | 919 | void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) { |
| 920 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 921 | |||
| 899 | IPC::ResponseBuilder rb{ctx, 2}; | 922 | IPC::ResponseBuilder rb{ctx, 2}; |
| 900 | rb.Push(RESULT_SUCCESS); | 923 | rb.Push(RESULT_SUCCESS); |
| 901 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 902 | } | 924 | } |
| 903 | 925 | ||
| 904 | void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) { | 926 | void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) { |
| 927 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 928 | |||
| 905 | IPC::ResponseBuilder rb{ctx, 2}; | 929 | IPC::ResponseBuilder rb{ctx, 2}; |
| 906 | rb.Push(RESULT_SUCCESS); | 930 | rb.Push(RESULT_SUCCESS); |
| 907 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 908 | } | 931 | } |
| 909 | 932 | ||
| 910 | void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | 933 | void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { |
| 934 | LOG_DEBUG(Service_AM, "called"); | ||
| 935 | |||
| 911 | LaunchParameters params{}; | 936 | LaunchParameters params{}; |
| 912 | 937 | ||
| 913 | params.magic = POP_LAUNCH_PARAMETER_MAGIC; | 938 | params.magic = POP_LAUNCH_PARAMETER_MAGIC; |
| @@ -926,21 +951,19 @@ void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { | |||
| 926 | std::memcpy(buffer.data(), ¶ms, buffer.size()); | 951 | std::memcpy(buffer.data(), ¶ms, buffer.size()); |
| 927 | 952 | ||
| 928 | rb.PushIpcInterface<AM::IStorage>(buffer); | 953 | rb.PushIpcInterface<AM::IStorage>(buffer); |
| 929 | |||
| 930 | LOG_DEBUG(Service_AM, "called"); | ||
| 931 | } | 954 | } |
| 932 | 955 | ||
| 933 | void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( | 956 | void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( |
| 934 | Kernel::HLERequestContext& ctx) { | 957 | Kernel::HLERequestContext& ctx) { |
| 958 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 959 | |||
| 935 | IPC::ResponseBuilder rb{ctx, 2}; | 960 | IPC::ResponseBuilder rb{ctx, 2}; |
| 936 | rb.Push(RESULT_SUCCESS); | 961 | rb.Push(RESULT_SUCCESS); |
| 937 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 938 | } | 962 | } |
| 939 | 963 | ||
| 940 | void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { | 964 | void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { |
| 941 | IPC::RequestParser rp{ctx}; | 965 | IPC::RequestParser rp{ctx}; |
| 942 | u128 uid = rp.PopRaw<u128>(); // What does this do? | 966 | u128 uid = rp.PopRaw<u128>(); // What does this do? |
| 943 | |||
| 944 | LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); | 967 | LOG_WARNING(Service, "(STUBBED) called uid = {:016X}{:016X}", uid[1], uid[0]); |
| 945 | 968 | ||
| 946 | IPC::ResponseBuilder rb{ctx, 4}; | 969 | IPC::ResponseBuilder rb{ctx, 4}; |
| @@ -955,60 +978,62 @@ void IApplicationFunctions::SetTerminateResult(Kernel::HLERequestContext& ctx) { | |||
| 955 | 978 | ||
| 956 | IPC::RequestParser rp{ctx}; | 979 | IPC::RequestParser rp{ctx}; |
| 957 | u32 result = rp.Pop<u32>(); | 980 | u32 result = rp.Pop<u32>(); |
| 981 | LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); | ||
| 958 | 982 | ||
| 959 | IPC::ResponseBuilder rb{ctx, 2}; | 983 | IPC::ResponseBuilder rb{ctx, 2}; |
| 960 | rb.Push(RESULT_SUCCESS); | 984 | rb.Push(RESULT_SUCCESS); |
| 961 | |||
| 962 | LOG_WARNING(Service_AM, "(STUBBED) called, result=0x{:08X}", result); | ||
| 963 | } | 985 | } |
| 964 | 986 | ||
| 965 | void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { | 987 | void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { |
| 988 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 989 | |||
| 966 | IPC::ResponseBuilder rb{ctx, 6}; | 990 | IPC::ResponseBuilder rb{ctx, 6}; |
| 967 | rb.Push(RESULT_SUCCESS); | 991 | rb.Push(RESULT_SUCCESS); |
| 968 | rb.Push<u64>(1); | 992 | rb.Push<u64>(1); |
| 969 | rb.Push<u64>(0); | 993 | rb.Push<u64>(0); |
| 970 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 971 | } | 994 | } |
| 972 | 995 | ||
| 973 | void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { | 996 | void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { |
| 974 | // TODO(bunnei): This should be configurable | 997 | // TODO(bunnei): This should be configurable |
| 998 | LOG_DEBUG(Service_AM, "called"); | ||
| 999 | |||
| 975 | IPC::ResponseBuilder rb{ctx, 4}; | 1000 | IPC::ResponseBuilder rb{ctx, 4}; |
| 976 | rb.Push(RESULT_SUCCESS); | 1001 | rb.Push(RESULT_SUCCESS); |
| 977 | rb.Push( | 1002 | rb.Push( |
| 978 | static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index))); | 1003 | static_cast<u64>(Service::Set::GetLanguageCodeFromIndex(Settings::values.language_index))); |
| 979 | LOG_DEBUG(Service_AM, "called"); | ||
| 980 | } | 1004 | } |
| 981 | 1005 | ||
| 982 | void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { | 1006 | void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { |
| 1007 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1008 | |||
| 983 | IPC::ResponseBuilder rb{ctx, 2}; | 1009 | IPC::ResponseBuilder rb{ctx, 2}; |
| 984 | rb.Push(RESULT_SUCCESS); | 1010 | rb.Push(RESULT_SUCCESS); |
| 985 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 986 | } | 1011 | } |
| 987 | 1012 | ||
| 988 | void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) { | 1013 | void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) { |
| 1014 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1015 | |||
| 989 | IPC::ResponseBuilder rb{ctx, 2}; | 1016 | IPC::ResponseBuilder rb{ctx, 2}; |
| 990 | rb.Push(RESULT_SUCCESS); | 1017 | rb.Push(RESULT_SUCCESS); |
| 991 | |||
| 992 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 993 | } | 1018 | } |
| 994 | 1019 | ||
| 995 | void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { | 1020 | void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { |
| 1021 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1022 | |||
| 996 | IPC::ResponseBuilder rb{ctx, 3}; | 1023 | IPC::ResponseBuilder rb{ctx, 3}; |
| 997 | rb.Push(RESULT_SUCCESS); | 1024 | rb.Push(RESULT_SUCCESS); |
| 998 | rb.Push<u8>(0); // Unknown, seems to be ignored by official processes | 1025 | rb.Push<u8>(0); // Unknown, seems to be ignored by official processes |
| 999 | |||
| 1000 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1001 | } | 1026 | } |
| 1002 | 1027 | ||
| 1003 | void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { | 1028 | void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { |
| 1029 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1030 | |||
| 1004 | IPC::ResponseBuilder rb{ctx, 6}; | 1031 | IPC::ResponseBuilder rb{ctx, 6}; |
| 1005 | rb.Push(RESULT_SUCCESS); | 1032 | rb.Push(RESULT_SUCCESS); |
| 1006 | 1033 | ||
| 1007 | // Returns a 128-bit UUID | 1034 | // Returns a 128-bit UUID |
| 1008 | rb.Push<u64>(0); | 1035 | rb.Push<u64>(0); |
| 1009 | rb.Push<u64>(0); | 1036 | rb.Push<u64>(0); |
| 1010 | |||
| 1011 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1012 | } | 1037 | } |
| 1013 | 1038 | ||
| 1014 | void InstallInterfaces(SM::ServiceManager& service_manager, | 1039 | void InstallInterfaces(SM::ServiceManager& service_manager, |
| @@ -1045,9 +1070,10 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions" | |||
| 1045 | IHomeMenuFunctions::~IHomeMenuFunctions() = default; | 1070 | IHomeMenuFunctions::~IHomeMenuFunctions() = default; |
| 1046 | 1071 | ||
| 1047 | void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { | 1072 | void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { |
| 1073 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1074 | |||
| 1048 | IPC::ResponseBuilder rb{ctx, 2}; | 1075 | IPC::ResponseBuilder rb{ctx, 2}; |
| 1049 | rb.Push(RESULT_SUCCESS); | 1076 | rb.Push(RESULT_SUCCESS); |
| 1050 | LOG_WARNING(Service_AM, "(STUBBED) called"); | ||
| 1051 | } | 1077 | } |
| 1052 | 1078 | ||
| 1053 | IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { | 1079 | IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { |
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp index ec93e3529..41a573a91 100644 --- a/src/core/hle/service/am/applet_ae.cpp +++ b/src/core/hle/service/am/applet_ae.cpp | |||
| @@ -32,66 +32,75 @@ public: | |||
| 32 | 32 | ||
| 33 | private: | 33 | private: |
| 34 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { | 34 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { |
| 35 | LOG_DEBUG(Service_AM, "called"); | ||
| 36 | |||
| 35 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 37 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 36 | rb.Push(RESULT_SUCCESS); | 38 | rb.Push(RESULT_SUCCESS); |
| 37 | rb.PushIpcInterface<ICommonStateGetter>(msg_queue); | 39 | rb.PushIpcInterface<ICommonStateGetter>(msg_queue); |
| 38 | LOG_DEBUG(Service_AM, "called"); | ||
| 39 | } | 40 | } |
| 40 | 41 | ||
| 41 | void GetSelfController(Kernel::HLERequestContext& ctx) { | 42 | void GetSelfController(Kernel::HLERequestContext& ctx) { |
| 43 | LOG_DEBUG(Service_AM, "called"); | ||
| 44 | |||
| 42 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 45 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 43 | rb.Push(RESULT_SUCCESS); | 46 | rb.Push(RESULT_SUCCESS); |
| 44 | rb.PushIpcInterface<ISelfController>(nvflinger); | 47 | rb.PushIpcInterface<ISelfController>(nvflinger); |
| 45 | LOG_DEBUG(Service_AM, "called"); | ||
| 46 | } | 48 | } |
| 47 | 49 | ||
| 48 | void GetWindowController(Kernel::HLERequestContext& ctx) { | 50 | void GetWindowController(Kernel::HLERequestContext& ctx) { |
| 51 | LOG_DEBUG(Service_AM, "called"); | ||
| 52 | |||
| 49 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 53 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 50 | rb.Push(RESULT_SUCCESS); | 54 | rb.Push(RESULT_SUCCESS); |
| 51 | rb.PushIpcInterface<IWindowController>(); | 55 | rb.PushIpcInterface<IWindowController>(); |
| 52 | LOG_DEBUG(Service_AM, "called"); | ||
| 53 | } | 56 | } |
| 54 | 57 | ||
| 55 | void GetAudioController(Kernel::HLERequestContext& ctx) { | 58 | void GetAudioController(Kernel::HLERequestContext& ctx) { |
| 59 | LOG_DEBUG(Service_AM, "called"); | ||
| 60 | |||
| 56 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 61 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 57 | rb.Push(RESULT_SUCCESS); | 62 | rb.Push(RESULT_SUCCESS); |
| 58 | rb.PushIpcInterface<IAudioController>(); | 63 | rb.PushIpcInterface<IAudioController>(); |
| 59 | LOG_DEBUG(Service_AM, "called"); | ||
| 60 | } | 64 | } |
| 61 | 65 | ||
| 62 | void GetDisplayController(Kernel::HLERequestContext& ctx) { | 66 | void GetDisplayController(Kernel::HLERequestContext& ctx) { |
| 67 | LOG_DEBUG(Service_AM, "called"); | ||
| 68 | |||
| 63 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 69 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 64 | rb.Push(RESULT_SUCCESS); | 70 | rb.Push(RESULT_SUCCESS); |
| 65 | rb.PushIpcInterface<IDisplayController>(); | 71 | rb.PushIpcInterface<IDisplayController>(); |
| 66 | LOG_DEBUG(Service_AM, "called"); | ||
| 67 | } | 72 | } |
| 68 | 73 | ||
| 69 | void GetProcessWindingController(Kernel::HLERequestContext& ctx) { | 74 | void GetProcessWindingController(Kernel::HLERequestContext& ctx) { |
| 75 | LOG_DEBUG(Service_AM, "called"); | ||
| 76 | |||
| 70 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 77 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 71 | rb.Push(RESULT_SUCCESS); | 78 | rb.Push(RESULT_SUCCESS); |
| 72 | rb.PushIpcInterface<IProcessWindingController>(); | 79 | rb.PushIpcInterface<IProcessWindingController>(); |
| 73 | LOG_DEBUG(Service_AM, "called"); | ||
| 74 | } | 80 | } |
| 75 | 81 | ||
| 76 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { | 82 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { |
| 83 | LOG_DEBUG(Service_AM, "called"); | ||
| 84 | |||
| 77 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 85 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 78 | rb.Push(RESULT_SUCCESS); | 86 | rb.Push(RESULT_SUCCESS); |
| 79 | rb.PushIpcInterface<IDebugFunctions>(); | 87 | rb.PushIpcInterface<IDebugFunctions>(); |
| 80 | LOG_DEBUG(Service_AM, "called"); | ||
| 81 | } | 88 | } |
| 82 | 89 | ||
| 83 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { | 90 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { |
| 91 | LOG_DEBUG(Service_AM, "called"); | ||
| 92 | |||
| 84 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 93 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 85 | rb.Push(RESULT_SUCCESS); | 94 | rb.Push(RESULT_SUCCESS); |
| 86 | rb.PushIpcInterface<ILibraryAppletCreator>(); | 95 | rb.PushIpcInterface<ILibraryAppletCreator>(); |
| 87 | LOG_DEBUG(Service_AM, "called"); | ||
| 88 | } | 96 | } |
| 89 | 97 | ||
| 90 | void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { | 98 | void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { |
| 99 | LOG_DEBUG(Service_AM, "called"); | ||
| 100 | |||
| 91 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 101 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 92 | rb.Push(RESULT_SUCCESS); | 102 | rb.Push(RESULT_SUCCESS); |
| 93 | rb.PushIpcInterface<IApplicationFunctions>(); | 103 | rb.PushIpcInterface<IApplicationFunctions>(); |
| 94 | LOG_DEBUG(Service_AM, "called"); | ||
| 95 | } | 104 | } |
| 96 | 105 | ||
| 97 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 106 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; |
| @@ -122,97 +131,110 @@ public: | |||
| 122 | 131 | ||
| 123 | private: | 132 | private: |
| 124 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { | 133 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { |
| 134 | LOG_DEBUG(Service_AM, "called"); | ||
| 135 | |||
| 125 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 136 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 126 | rb.Push(RESULT_SUCCESS); | 137 | rb.Push(RESULT_SUCCESS); |
| 127 | rb.PushIpcInterface<ICommonStateGetter>(msg_queue); | 138 | rb.PushIpcInterface<ICommonStateGetter>(msg_queue); |
| 128 | LOG_DEBUG(Service_AM, "called"); | ||
| 129 | } | 139 | } |
| 130 | 140 | ||
| 131 | void GetSelfController(Kernel::HLERequestContext& ctx) { | 141 | void GetSelfController(Kernel::HLERequestContext& ctx) { |
| 142 | LOG_DEBUG(Service_AM, "called"); | ||
| 143 | |||
| 132 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 144 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 133 | rb.Push(RESULT_SUCCESS); | 145 | rb.Push(RESULT_SUCCESS); |
| 134 | rb.PushIpcInterface<ISelfController>(nvflinger); | 146 | rb.PushIpcInterface<ISelfController>(nvflinger); |
| 135 | LOG_DEBUG(Service_AM, "called"); | ||
| 136 | } | 147 | } |
| 137 | 148 | ||
| 138 | void GetWindowController(Kernel::HLERequestContext& ctx) { | 149 | void GetWindowController(Kernel::HLERequestContext& ctx) { |
| 150 | LOG_DEBUG(Service_AM, "called"); | ||
| 151 | |||
| 139 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 152 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 140 | rb.Push(RESULT_SUCCESS); | 153 | rb.Push(RESULT_SUCCESS); |
| 141 | rb.PushIpcInterface<IWindowController>(); | 154 | rb.PushIpcInterface<IWindowController>(); |
| 142 | LOG_DEBUG(Service_AM, "called"); | ||
| 143 | } | 155 | } |
| 144 | 156 | ||
| 145 | void GetAudioController(Kernel::HLERequestContext& ctx) { | 157 | void GetAudioController(Kernel::HLERequestContext& ctx) { |
| 158 | LOG_DEBUG(Service_AM, "called"); | ||
| 159 | |||
| 146 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 160 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 147 | rb.Push(RESULT_SUCCESS); | 161 | rb.Push(RESULT_SUCCESS); |
| 148 | rb.PushIpcInterface<IAudioController>(); | 162 | rb.PushIpcInterface<IAudioController>(); |
| 149 | LOG_DEBUG(Service_AM, "called"); | ||
| 150 | } | 163 | } |
| 151 | 164 | ||
| 152 | void GetDisplayController(Kernel::HLERequestContext& ctx) { | 165 | void GetDisplayController(Kernel::HLERequestContext& ctx) { |
| 166 | LOG_DEBUG(Service_AM, "called"); | ||
| 167 | |||
| 153 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 168 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 154 | rb.Push(RESULT_SUCCESS); | 169 | rb.Push(RESULT_SUCCESS); |
| 155 | rb.PushIpcInterface<IDisplayController>(); | 170 | rb.PushIpcInterface<IDisplayController>(); |
| 156 | LOG_DEBUG(Service_AM, "called"); | ||
| 157 | } | 171 | } |
| 158 | 172 | ||
| 159 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { | 173 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { |
| 174 | LOG_DEBUG(Service_AM, "called"); | ||
| 175 | |||
| 160 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 176 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 161 | rb.Push(RESULT_SUCCESS); | 177 | rb.Push(RESULT_SUCCESS); |
| 162 | rb.PushIpcInterface<IDebugFunctions>(); | 178 | rb.PushIpcInterface<IDebugFunctions>(); |
| 163 | LOG_DEBUG(Service_AM, "called"); | ||
| 164 | } | 179 | } |
| 165 | 180 | ||
| 166 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { | 181 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { |
| 182 | LOG_DEBUG(Service_AM, "called"); | ||
| 183 | |||
| 167 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 184 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 168 | rb.Push(RESULT_SUCCESS); | 185 | rb.Push(RESULT_SUCCESS); |
| 169 | rb.PushIpcInterface<ILibraryAppletCreator>(); | 186 | rb.PushIpcInterface<ILibraryAppletCreator>(); |
| 170 | LOG_DEBUG(Service_AM, "called"); | ||
| 171 | } | 187 | } |
| 172 | 188 | ||
| 173 | void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { | 189 | void GetHomeMenuFunctions(Kernel::HLERequestContext& ctx) { |
| 190 | LOG_DEBUG(Service_AM, "called"); | ||
| 191 | |||
| 174 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 192 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 175 | rb.Push(RESULT_SUCCESS); | 193 | rb.Push(RESULT_SUCCESS); |
| 176 | rb.PushIpcInterface<IHomeMenuFunctions>(); | 194 | rb.PushIpcInterface<IHomeMenuFunctions>(); |
| 177 | LOG_DEBUG(Service_AM, "called"); | ||
| 178 | } | 195 | } |
| 179 | 196 | ||
| 180 | void GetGlobalStateController(Kernel::HLERequestContext& ctx) { | 197 | void GetGlobalStateController(Kernel::HLERequestContext& ctx) { |
| 198 | LOG_DEBUG(Service_AM, "called"); | ||
| 199 | |||
| 181 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 200 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 182 | rb.Push(RESULT_SUCCESS); | 201 | rb.Push(RESULT_SUCCESS); |
| 183 | rb.PushIpcInterface<IGlobalStateController>(); | 202 | rb.PushIpcInterface<IGlobalStateController>(); |
| 184 | LOG_DEBUG(Service_AM, "called"); | ||
| 185 | } | 203 | } |
| 186 | 204 | ||
| 187 | void GetApplicationCreator(Kernel::HLERequestContext& ctx) { | 205 | void GetApplicationCreator(Kernel::HLERequestContext& ctx) { |
| 206 | LOG_DEBUG(Service_AM, "called"); | ||
| 207 | |||
| 188 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 208 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 189 | rb.Push(RESULT_SUCCESS); | 209 | rb.Push(RESULT_SUCCESS); |
| 190 | rb.PushIpcInterface<IApplicationCreator>(); | 210 | rb.PushIpcInterface<IApplicationCreator>(); |
| 191 | LOG_DEBUG(Service_AM, "called"); | ||
| 192 | } | 211 | } |
| 193 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 212 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; |
| 194 | std::shared_ptr<AppletMessageQueue> msg_queue; | 213 | std::shared_ptr<AppletMessageQueue> msg_queue; |
| 195 | }; | 214 | }; |
| 196 | 215 | ||
| 197 | void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { | 216 | void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { |
| 217 | LOG_DEBUG(Service_AM, "called"); | ||
| 218 | |||
| 198 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 199 | rb.Push(RESULT_SUCCESS); | 220 | rb.Push(RESULT_SUCCESS); |
| 200 | rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue); | 221 | rb.PushIpcInterface<ISystemAppletProxy>(nvflinger, msg_queue); |
| 201 | LOG_DEBUG(Service_AM, "called"); | ||
| 202 | } | 222 | } |
| 203 | 223 | ||
| 204 | void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { | 224 | void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { |
| 225 | LOG_DEBUG(Service_AM, "called"); | ||
| 226 | |||
| 205 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 227 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 206 | rb.Push(RESULT_SUCCESS); | 228 | rb.Push(RESULT_SUCCESS); |
| 207 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); | 229 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); |
| 208 | LOG_DEBUG(Service_AM, "called"); | ||
| 209 | } | 230 | } |
| 210 | 231 | ||
| 211 | void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { | 232 | void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { |
| 233 | LOG_DEBUG(Service_AM, "called"); | ||
| 234 | |||
| 212 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 235 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 213 | rb.Push(RESULT_SUCCESS); | 236 | rb.Push(RESULT_SUCCESS); |
| 214 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); | 237 | rb.PushIpcInterface<ILibraryAppletProxy>(nvflinger, msg_queue); |
| 215 | LOG_DEBUG(Service_AM, "called"); | ||
| 216 | } | 238 | } |
| 217 | 239 | ||
| 218 | AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 240 | AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, |
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp index 20c8d5fff..d3a0a1568 100644 --- a/src/core/hle/service/am/applet_oe.cpp +++ b/src/core/hle/service/am/applet_oe.cpp | |||
| @@ -35,59 +35,67 @@ public: | |||
| 35 | 35 | ||
| 36 | private: | 36 | private: |
| 37 | void GetAudioController(Kernel::HLERequestContext& ctx) { | 37 | void GetAudioController(Kernel::HLERequestContext& ctx) { |
| 38 | LOG_DEBUG(Service_AM, "called"); | ||
| 39 | |||
| 38 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 40 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 39 | rb.Push(RESULT_SUCCESS); | 41 | rb.Push(RESULT_SUCCESS); |
| 40 | rb.PushIpcInterface<IAudioController>(); | 42 | rb.PushIpcInterface<IAudioController>(); |
| 41 | LOG_DEBUG(Service_AM, "called"); | ||
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | void GetDisplayController(Kernel::HLERequestContext& ctx) { | 45 | void GetDisplayController(Kernel::HLERequestContext& ctx) { |
| 46 | LOG_DEBUG(Service_AM, "called"); | ||
| 47 | |||
| 45 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 48 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 46 | rb.Push(RESULT_SUCCESS); | 49 | rb.Push(RESULT_SUCCESS); |
| 47 | rb.PushIpcInterface<IDisplayController>(); | 50 | rb.PushIpcInterface<IDisplayController>(); |
| 48 | LOG_DEBUG(Service_AM, "called"); | ||
| 49 | } | 51 | } |
| 50 | 52 | ||
| 51 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { | 53 | void GetDebugFunctions(Kernel::HLERequestContext& ctx) { |
| 54 | LOG_DEBUG(Service_AM, "called"); | ||
| 55 | |||
| 52 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 56 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 53 | rb.Push(RESULT_SUCCESS); | 57 | rb.Push(RESULT_SUCCESS); |
| 54 | rb.PushIpcInterface<IDebugFunctions>(); | 58 | rb.PushIpcInterface<IDebugFunctions>(); |
| 55 | LOG_DEBUG(Service_AM, "called"); | ||
| 56 | } | 59 | } |
| 57 | 60 | ||
| 58 | void GetWindowController(Kernel::HLERequestContext& ctx) { | 61 | void GetWindowController(Kernel::HLERequestContext& ctx) { |
| 62 | LOG_DEBUG(Service_AM, "called"); | ||
| 63 | |||
| 59 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 64 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 60 | rb.Push(RESULT_SUCCESS); | 65 | rb.Push(RESULT_SUCCESS); |
| 61 | rb.PushIpcInterface<IWindowController>(); | 66 | rb.PushIpcInterface<IWindowController>(); |
| 62 | LOG_DEBUG(Service_AM, "called"); | ||
| 63 | } | 67 | } |
| 64 | 68 | ||
| 65 | void GetSelfController(Kernel::HLERequestContext& ctx) { | 69 | void GetSelfController(Kernel::HLERequestContext& ctx) { |
| 70 | LOG_DEBUG(Service_AM, "called"); | ||
| 71 | |||
| 66 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 72 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 67 | rb.Push(RESULT_SUCCESS); | 73 | rb.Push(RESULT_SUCCESS); |
| 68 | rb.PushIpcInterface<ISelfController>(nvflinger); | 74 | rb.PushIpcInterface<ISelfController>(nvflinger); |
| 69 | LOG_DEBUG(Service_AM, "called"); | ||
| 70 | } | 75 | } |
| 71 | 76 | ||
| 72 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { | 77 | void GetCommonStateGetter(Kernel::HLERequestContext& ctx) { |
| 78 | LOG_DEBUG(Service_AM, "called"); | ||
| 79 | |||
| 73 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 80 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 74 | rb.Push(RESULT_SUCCESS); | 81 | rb.Push(RESULT_SUCCESS); |
| 75 | rb.PushIpcInterface<ICommonStateGetter>(msg_queue); | 82 | rb.PushIpcInterface<ICommonStateGetter>(msg_queue); |
| 76 | LOG_DEBUG(Service_AM, "called"); | ||
| 77 | } | 83 | } |
| 78 | 84 | ||
| 79 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { | 85 | void GetLibraryAppletCreator(Kernel::HLERequestContext& ctx) { |
| 86 | LOG_DEBUG(Service_AM, "called"); | ||
| 87 | |||
| 80 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 88 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 81 | rb.Push(RESULT_SUCCESS); | 89 | rb.Push(RESULT_SUCCESS); |
| 82 | rb.PushIpcInterface<ILibraryAppletCreator>(); | 90 | rb.PushIpcInterface<ILibraryAppletCreator>(); |
| 83 | LOG_DEBUG(Service_AM, "called"); | ||
| 84 | } | 91 | } |
| 85 | 92 | ||
| 86 | void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { | 93 | void GetApplicationFunctions(Kernel::HLERequestContext& ctx) { |
| 94 | LOG_DEBUG(Service_AM, "called"); | ||
| 95 | |||
| 87 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 96 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 88 | rb.Push(RESULT_SUCCESS); | 97 | rb.Push(RESULT_SUCCESS); |
| 89 | rb.PushIpcInterface<IApplicationFunctions>(); | 98 | rb.PushIpcInterface<IApplicationFunctions>(); |
| 90 | LOG_DEBUG(Service_AM, "called"); | ||
| 91 | } | 99 | } |
| 92 | 100 | ||
| 93 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; | 101 | std::shared_ptr<NVFlinger::NVFlinger> nvflinger; |
| @@ -95,10 +103,11 @@ private: | |||
| 95 | }; | 103 | }; |
| 96 | 104 | ||
| 97 | void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { | 105 | void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { |
| 106 | LOG_DEBUG(Service_AM, "called"); | ||
| 107 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 108 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 99 | rb.Push(RESULT_SUCCESS); | 109 | rb.Push(RESULT_SUCCESS); |
| 100 | rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue); | 110 | rb.PushIpcInterface<IApplicationProxy>(nvflinger, msg_queue); |
| 101 | LOG_DEBUG(Service_AM, "called"); | ||
| 102 | } | 111 | } |
| 103 | 112 | ||
| 104 | AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, | 113 | AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, |
diff --git a/src/core/hle/service/am/applets/stub_applet.cpp b/src/core/hle/service/am/applets/stub_applet.cpp new file mode 100644 index 000000000..ed166b87d --- /dev/null +++ b/src/core/hle/service/am/applets/stub_applet.cpp | |||
| @@ -0,0 +1,70 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <string> | ||
| 6 | |||
| 7 | #include "common/hex_util.h" | ||
| 8 | #include "common/logging/log.h" | ||
| 9 | #include "core/hle/result.h" | ||
| 10 | #include "core/hle/service/am/am.h" | ||
| 11 | #include "core/hle/service/am/applets/stub_applet.h" | ||
| 12 | |||
| 13 | namespace Service::AM::Applets { | ||
| 14 | |||
| 15 | static void LogCurrentStorage(AppletDataBroker& broker, std::string prefix) { | ||
| 16 | std::unique_ptr<IStorage> storage = broker.PopNormalDataToApplet(); | ||
| 17 | for (; storage != nullptr; storage = broker.PopNormalDataToApplet()) { | ||
| 18 | const auto data = storage->GetData(); | ||
| 19 | LOG_INFO(Service_AM, | ||
| 20 | "called (STUBBED), during {} recieved normal data with size={:08X}, data={}", | ||
| 21 | prefix, data.size(), Common::HexVectorToString(data)); | ||
| 22 | } | ||
| 23 | |||
| 24 | storage = broker.PopInteractiveDataToApplet(); | ||
| 25 | for (; storage != nullptr; storage = broker.PopInteractiveDataToApplet()) { | ||
| 26 | const auto data = storage->GetData(); | ||
| 27 | LOG_INFO(Service_AM, | ||
| 28 | "called (STUBBED), during {} recieved interactive data with size={:08X}, data={}", | ||
| 29 | prefix, data.size(), Common::HexVectorToString(data)); | ||
| 30 | } | ||
| 31 | } | ||
| 32 | |||
| 33 | StubApplet::StubApplet() = default; | ||
| 34 | |||
| 35 | StubApplet::~StubApplet() = default; | ||
| 36 | |||
| 37 | void StubApplet::Initialize() { | ||
| 38 | LOG_WARNING(Service_AM, "called (STUBBED)"); | ||
| 39 | Applet::Initialize(); | ||
| 40 | LogCurrentStorage(broker, "Initialize"); | ||
| 41 | } | ||
| 42 | |||
| 43 | bool StubApplet::TransactionComplete() const { | ||
| 44 | LOG_WARNING(Service_AM, "called (STUBBED)"); | ||
| 45 | return true; | ||
| 46 | } | ||
| 47 | |||
| 48 | ResultCode StubApplet::GetStatus() const { | ||
| 49 | LOG_WARNING(Service_AM, "called (STUBBED)"); | ||
| 50 | return RESULT_SUCCESS; | ||
| 51 | } | ||
| 52 | |||
| 53 | void StubApplet::ExecuteInteractive() { | ||
| 54 | LOG_WARNING(Service_AM, "called (STUBBED)"); | ||
| 55 | LogCurrentStorage(broker, "ExecuteInteractive"); | ||
| 56 | |||
| 57 | broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)}); | ||
| 58 | broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)}); | ||
| 59 | broker.SignalStateChanged(); | ||
| 60 | } | ||
| 61 | |||
| 62 | void StubApplet::Execute() { | ||
| 63 | LOG_WARNING(Service_AM, "called (STUBBED)"); | ||
| 64 | LogCurrentStorage(broker, "Execute"); | ||
| 65 | |||
| 66 | broker.PushNormalDataFromApplet(IStorage{std::vector<u8>(0x1000)}); | ||
| 67 | broker.PushInteractiveDataFromApplet(IStorage{std::vector<u8>(0x1000)}); | ||
| 68 | broker.SignalStateChanged(); | ||
| 69 | } | ||
| 70 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/am/applets/stub_applet.h b/src/core/hle/service/am/applets/stub_applet.h new file mode 100644 index 000000000..7d8dc968d --- /dev/null +++ b/src/core/hle/service/am/applets/stub_applet.h | |||
| @@ -0,0 +1,24 @@ | |||
| 1 | // Copyright 2018 yuzu emulator team | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #pragma once | ||
| 6 | |||
| 7 | #include "core/hle/service/am/applets/applets.h" | ||
| 8 | |||
| 9 | namespace Service::AM::Applets { | ||
| 10 | |||
| 11 | class StubApplet final : public Applet { | ||
| 12 | public: | ||
| 13 | StubApplet(); | ||
| 14 | ~StubApplet() override; | ||
| 15 | |||
| 16 | void Initialize() override; | ||
| 17 | |||
| 18 | bool TransactionComplete() const override; | ||
| 19 | ResultCode GetStatus() const override; | ||
| 20 | void ExecuteInteractive() override; | ||
| 21 | void Execute() override; | ||
| 22 | }; | ||
| 23 | |||
| 24 | } // namespace Service::AM::Applets | ||
diff --git a/src/core/hle/service/aoc/aoc_u.cpp b/src/core/hle/service/aoc/aoc_u.cpp index 54305cf05..bacf19de2 100644 --- a/src/core/hle/service/aoc/aoc_u.cpp +++ b/src/core/hle/service/aoc/aoc_u.cpp | |||
| @@ -68,6 +68,8 @@ AOC_U::AOC_U() : ServiceFramework("aoc:u"), add_on_content(AccumulateAOCTitleIDs | |||
| 68 | AOC_U::~AOC_U() = default; | 68 | AOC_U::~AOC_U() = default; |
| 69 | 69 | ||
| 70 | void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { | 70 | void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { |
| 71 | LOG_DEBUG(Service_AOC, "called"); | ||
| 72 | |||
| 71 | IPC::ResponseBuilder rb{ctx, 3}; | 73 | IPC::ResponseBuilder rb{ctx, 3}; |
| 72 | rb.Push(RESULT_SUCCESS); | 74 | rb.Push(RESULT_SUCCESS); |
| 73 | 75 | ||
| @@ -82,6 +84,7 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { | |||
| 82 | 84 | ||
| 83 | const auto offset = rp.PopRaw<u32>(); | 85 | const auto offset = rp.PopRaw<u32>(); |
| 84 | auto count = rp.PopRaw<u32>(); | 86 | auto count = rp.PopRaw<u32>(); |
| 87 | LOG_DEBUG(Service_AOC, "called with offset={}, count={}", offset, count); | ||
| 85 | 88 | ||
| 86 | const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | 89 | const auto current = Core::System::GetInstance().CurrentProcess()->GetTitleID(); |
| 87 | 90 | ||
| @@ -110,6 +113,8 @@ void AOC_U::ListAddOnContent(Kernel::HLERequestContext& ctx) { | |||
| 110 | } | 113 | } |
| 111 | 114 | ||
| 112 | void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { | 115 | void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { |
| 116 | LOG_DEBUG(Service_AOC, "called"); | ||
| 117 | |||
| 113 | IPC::ResponseBuilder rb{ctx, 4}; | 118 | IPC::ResponseBuilder rb{ctx, 4}; |
| 114 | rb.Push(RESULT_SUCCESS); | 119 | rb.Push(RESULT_SUCCESS); |
| 115 | const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); | 120 | const auto title_id = Core::System::GetInstance().CurrentProcess()->GetTitleID(); |
| @@ -128,7 +133,6 @@ void AOC_U::PrepareAddOnContent(Kernel::HLERequestContext& ctx) { | |||
| 128 | IPC::RequestParser rp{ctx}; | 133 | IPC::RequestParser rp{ctx}; |
| 129 | 134 | ||
| 130 | const auto aoc_id = rp.PopRaw<u32>(); | 135 | const auto aoc_id = rp.PopRaw<u32>(); |
| 131 | |||
| 132 | LOG_WARNING(Service_AOC, "(STUBBED) called with aoc_id={:08X}", aoc_id); | 136 | LOG_WARNING(Service_AOC, "(STUBBED) called with aoc_id={:08X}", aoc_id); |
| 133 | 137 | ||
| 134 | IPC::ResponseBuilder rb{ctx, 2}; | 138 | IPC::ResponseBuilder rb{ctx, 2}; |
diff --git a/src/core/hle/service/apm/interface.cpp b/src/core/hle/service/apm/interface.cpp index c22bd3859..fcacbab72 100644 --- a/src/core/hle/service/apm/interface.cpp +++ b/src/core/hle/service/apm/interface.cpp | |||
| @@ -40,24 +40,22 @@ private: | |||
| 40 | 40 | ||
| 41 | auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); | 41 | auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); |
| 42 | u32 config = rp.Pop<u32>(); | 42 | u32 config = rp.Pop<u32>(); |
| 43 | LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode), | ||
| 44 | config); | ||
| 43 | 45 | ||
| 44 | IPC::ResponseBuilder rb{ctx, 2}; | 46 | IPC::ResponseBuilder rb{ctx, 2}; |
| 45 | rb.Push(RESULT_SUCCESS); | 47 | rb.Push(RESULT_SUCCESS); |
| 46 | |||
| 47 | LOG_WARNING(Service_APM, "(STUBBED) called mode={} config={}", static_cast<u32>(mode), | ||
| 48 | config); | ||
| 49 | } | 48 | } |
| 50 | 49 | ||
| 51 | void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { | 50 | void GetPerformanceConfiguration(Kernel::HLERequestContext& ctx) { |
| 52 | IPC::RequestParser rp{ctx}; | 51 | IPC::RequestParser rp{ctx}; |
| 53 | 52 | ||
| 54 | auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); | 53 | auto mode = static_cast<PerformanceMode>(rp.Pop<u32>()); |
| 54 | LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode)); | ||
| 55 | 55 | ||
| 56 | IPC::ResponseBuilder rb{ctx, 3}; | 56 | IPC::ResponseBuilder rb{ctx, 3}; |
| 57 | rb.Push(RESULT_SUCCESS); | 57 | rb.Push(RESULT_SUCCESS); |
| 58 | rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1)); | 58 | rb.Push<u32>(static_cast<u32>(PerformanceConfiguration::Config1)); |
| 59 | |||
| 60 | LOG_WARNING(Service_APM, "(STUBBED) called mode={}", static_cast<u32>(mode)); | ||
| 61 | } | 59 | } |
| 62 | }; | 60 | }; |
| 63 | 61 | ||
| @@ -73,11 +71,11 @@ APM::APM(std::shared_ptr<Module> apm, const char* name) | |||
| 73 | APM::~APM() = default; | 71 | APM::~APM() = default; |
| 74 | 72 | ||
| 75 | void APM::OpenSession(Kernel::HLERequestContext& ctx) { | 73 | void APM::OpenSession(Kernel::HLERequestContext& ctx) { |
| 74 | LOG_DEBUG(Service_APM, "called"); | ||
| 75 | |||
| 76 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 76 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 77 | rb.Push(RESULT_SUCCESS); | 77 | rb.Push(RESULT_SUCCESS); |
| 78 | rb.PushIpcInterface<ISession>(); | 78 | rb.PushIpcInterface<ISession>(); |
| 79 | |||
| 80 | LOG_DEBUG(Service_APM, "called"); | ||
| 81 | } | 79 | } |
| 82 | 80 | ||
| 83 | APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { | 81 | APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { |
| @@ -98,11 +96,11 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { | |||
| 98 | APM_Sys::~APM_Sys() = default; | 96 | APM_Sys::~APM_Sys() = default; |
| 99 | 97 | ||
| 100 | void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { | 98 | void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { |
| 99 | LOG_DEBUG(Service_APM, "called"); | ||
| 100 | |||
| 101 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 101 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 102 | rb.Push(RESULT_SUCCESS); | 102 | rb.Push(RESULT_SUCCESS); |
| 103 | rb.PushIpcInterface<ISession>(); | 103 | rb.PushIpcInterface<ISession>(); |
| 104 | |||
| 105 | LOG_DEBUG(Service_APM, "called"); | ||
| 106 | } | 104 | } |
| 107 | 105 | ||
| 108 | } // namespace Service::APM | 106 | } // namespace Service::APM |
diff --git a/src/core/hle/service/arp/arp.cpp b/src/core/hle/service/arp/arp.cpp index 358ef2576..e675b0188 100644 --- a/src/core/hle/service/arp/arp.cpp +++ b/src/core/hle/service/arp/arp.cpp | |||
| @@ -59,11 +59,11 @@ public: | |||
| 59 | 59 | ||
| 60 | private: | 60 | private: |
| 61 | void AcquireRegistrar(Kernel::HLERequestContext& ctx) { | 61 | void AcquireRegistrar(Kernel::HLERequestContext& ctx) { |
| 62 | LOG_DEBUG(Service_ARP, "called"); | ||
| 63 | |||
| 62 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 64 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 63 | rb.Push(RESULT_SUCCESS); | 65 | rb.Push(RESULT_SUCCESS); |
| 64 | rb.PushIpcInterface<IRegistrar>(); | 66 | rb.PushIpcInterface<IRegistrar>(); |
| 65 | |||
| 66 | LOG_DEBUG(Service_ARP, "called"); | ||
| 67 | } | 67 | } |
| 68 | }; | 68 | }; |
| 69 | 69 | ||
diff --git a/src/core/hle/service/audio/audout_u.cpp b/src/core/hle/service/audio/audout_u.cpp index ff1edefbb..2ee9bc273 100644 --- a/src/core/hle/service/audio/audout_u.cpp +++ b/src/core/hle/service/audio/audout_u.cpp | |||
| @@ -44,8 +44,10 @@ enum class AudioState : u32 { | |||
| 44 | 44 | ||
| 45 | class IAudioOut final : public ServiceFramework<IAudioOut> { | 45 | class IAudioOut final : public ServiceFramework<IAudioOut> { |
| 46 | public: | 46 | public: |
| 47 | IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core) | 47 | IAudioOut(AudoutParams audio_params, AudioCore::AudioOut& audio_core, std::string&& device_name, |
| 48 | : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params) { | 48 | std::string&& unique_name) |
| 49 | : ServiceFramework("IAudioOut"), audio_core(audio_core), audio_params(audio_params), | ||
| 50 | device_name(std::move(device_name)) { | ||
| 49 | 51 | ||
| 50 | static const FunctionInfo functions[] = { | 52 | static const FunctionInfo functions[] = { |
| 51 | {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, | 53 | {0, &IAudioOut::GetAudioOutState, "GetAudioOutState"}, |
| @@ -69,7 +71,7 @@ public: | |||
| 69 | Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased"); | 71 | Kernel::Event::Create(kernel, Kernel::ResetType::Sticky, "IAudioOutBufferReleased"); |
| 70 | 72 | ||
| 71 | stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count, | 73 | stream = audio_core.OpenStream(audio_params.sample_rate, audio_params.channel_count, |
| 72 | "IAudioOut", [=]() { buffer_event->Signal(); }); | 74 | std::move(unique_name), [=]() { buffer_event->Signal(); }); |
| 73 | } | 75 | } |
| 74 | 76 | ||
| 75 | private: | 77 | private: |
| @@ -84,6 +86,7 @@ private: | |||
| 84 | 86 | ||
| 85 | void GetAudioOutState(Kernel::HLERequestContext& ctx) { | 87 | void GetAudioOutState(Kernel::HLERequestContext& ctx) { |
| 86 | LOG_DEBUG(Service_Audio, "called"); | 88 | LOG_DEBUG(Service_Audio, "called"); |
| 89 | |||
| 87 | IPC::ResponseBuilder rb{ctx, 3}; | 90 | IPC::ResponseBuilder rb{ctx, 3}; |
| 88 | rb.Push(RESULT_SUCCESS); | 91 | rb.Push(RESULT_SUCCESS); |
| 89 | rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped)); | 92 | rb.Push(static_cast<u32>(stream->IsPlaying() ? AudioState::Started : AudioState::Stopped)); |
| @@ -146,6 +149,7 @@ private: | |||
| 146 | 149 | ||
| 147 | void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { | 150 | void GetReleasedAudioOutBufferImpl(Kernel::HLERequestContext& ctx) { |
| 148 | LOG_DEBUG(Service_Audio, "called {}", ctx.Description()); | 151 | LOG_DEBUG(Service_Audio, "called {}", ctx.Description()); |
| 152 | |||
| 149 | IPC::RequestParser rp{ctx}; | 153 | IPC::RequestParser rp{ctx}; |
| 150 | const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)}; | 154 | const u64 max_count{ctx.GetWriteBufferSize() / sizeof(u64)}; |
| 151 | const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)}; | 155 | const auto released_buffers{audio_core.GetTagsAndReleaseBuffers(stream, max_count)}; |
| @@ -161,6 +165,7 @@ private: | |||
| 161 | 165 | ||
| 162 | void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) { | 166 | void ContainsAudioOutBuffer(Kernel::HLERequestContext& ctx) { |
| 163 | LOG_DEBUG(Service_Audio, "called"); | 167 | LOG_DEBUG(Service_Audio, "called"); |
| 168 | |||
| 164 | IPC::RequestParser rp{ctx}; | 169 | IPC::RequestParser rp{ctx}; |
| 165 | const u64 tag{rp.Pop<u64>()}; | 170 | const u64 tag{rp.Pop<u64>()}; |
| 166 | IPC::ResponseBuilder rb{ctx, 3}; | 171 | IPC::ResponseBuilder rb{ctx, 3}; |
| @@ -170,6 +175,7 @@ private: | |||
| 170 | 175 | ||
| 171 | void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) { | 176 | void GetAudioOutBufferCount(Kernel::HLERequestContext& ctx) { |
| 172 | LOG_DEBUG(Service_Audio, "called"); | 177 | LOG_DEBUG(Service_Audio, "called"); |
| 178 | |||
| 173 | IPC::ResponseBuilder rb{ctx, 3}; | 179 | IPC::ResponseBuilder rb{ctx, 3}; |
| 174 | rb.Push(RESULT_SUCCESS); | 180 | rb.Push(RESULT_SUCCESS); |
| 175 | rb.Push(static_cast<u32>(stream->GetQueueSize())); | 181 | rb.Push(static_cast<u32>(stream->GetQueueSize())); |
| @@ -177,6 +183,7 @@ private: | |||
| 177 | 183 | ||
| 178 | AudioCore::AudioOut& audio_core; | 184 | AudioCore::AudioOut& audio_core; |
| 179 | AudioCore::StreamPtr stream; | 185 | AudioCore::StreamPtr stream; |
| 186 | std::string device_name; | ||
| 180 | 187 | ||
| 181 | AudoutParams audio_params{}; | 188 | AudoutParams audio_params{}; |
| 182 | 189 | ||
| @@ -186,6 +193,7 @@ private: | |||
| 186 | 193 | ||
| 187 | void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { | 194 | void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { |
| 188 | LOG_DEBUG(Service_Audio, "called"); | 195 | LOG_DEBUG(Service_Audio, "called"); |
| 196 | |||
| 189 | IPC::RequestParser rp{ctx}; | 197 | IPC::RequestParser rp{ctx}; |
| 190 | 198 | ||
| 191 | ctx.WriteBuffer(DefaultDevice); | 199 | ctx.WriteBuffer(DefaultDevice); |
| @@ -199,7 +207,15 @@ void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { | |||
| 199 | void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { | 207 | void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { |
| 200 | LOG_DEBUG(Service_Audio, "called"); | 208 | LOG_DEBUG(Service_Audio, "called"); |
| 201 | 209 | ||
| 202 | ctx.WriteBuffer(DefaultDevice); | 210 | const auto device_name_data{ctx.ReadBuffer()}; |
| 211 | std::string device_name; | ||
| 212 | if (device_name_data[0] != '\0') { | ||
| 213 | device_name.assign(device_name_data.begin(), device_name_data.end()); | ||
| 214 | } else { | ||
| 215 | device_name.assign(DefaultDevice.begin(), DefaultDevice.end()); | ||
| 216 | } | ||
| 217 | ctx.WriteBuffer(device_name); | ||
| 218 | |||
| 203 | IPC::RequestParser rp{ctx}; | 219 | IPC::RequestParser rp{ctx}; |
| 204 | auto params{rp.PopRaw<AudoutParams>()}; | 220 | auto params{rp.PopRaw<AudoutParams>()}; |
| 205 | if (params.channel_count <= 2) { | 221 | if (params.channel_count <= 2) { |
| @@ -212,10 +228,9 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { | |||
| 212 | params.sample_rate = DefaultSampleRate; | 228 | params.sample_rate = DefaultSampleRate; |
| 213 | } | 229 | } |
| 214 | 230 | ||
| 215 | // TODO(bunnei): Support more than one IAudioOut interface. When we add this, ListAudioOutsImpl | 231 | std::string unique_name{fmt::format("{}-{}", device_name, audio_out_interfaces.size())}; |
| 216 | // will likely need to be updated as well. | 232 | auto audio_out_interface = std::make_shared<IAudioOut>( |
| 217 | ASSERT_MSG(!audio_out_interface, "Unimplemented"); | 233 | params, *audio_core, std::move(device_name), std::move(unique_name)); |
| 218 | audio_out_interface = std::make_shared<IAudioOut>(params, *audio_core); | ||
| 219 | 234 | ||
| 220 | IPC::ResponseBuilder rb{ctx, 6, 0, 1}; | 235 | IPC::ResponseBuilder rb{ctx, 6, 0, 1}; |
| 221 | rb.Push(RESULT_SUCCESS); | 236 | rb.Push(RESULT_SUCCESS); |
| @@ -224,6 +239,8 @@ void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { | |||
| 224 | rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16)); | 239 | rb.Push<u32>(static_cast<u32>(AudioCore::Codec::PcmFormat::Int16)); |
| 225 | rb.Push<u32>(static_cast<u32>(AudioState::Stopped)); | 240 | rb.Push<u32>(static_cast<u32>(AudioState::Stopped)); |
| 226 | rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface); | 241 | rb.PushIpcInterface<Audio::IAudioOut>(audio_out_interface); |
| 242 | |||
| 243 | audio_out_interfaces.push_back(std::move(audio_out_interface)); | ||
| 227 | } | 244 | } |
| 228 | 245 | ||
| 229 | AudOutU::AudOutU() : ServiceFramework("audout:u") { | 246 | AudOutU::AudOutU() : ServiceFramework("audout:u") { |
diff --git a/src/core/hle/service/audio/audout_u.h b/src/core/hle/service/audio/audout_u.h index dcaf64708..aed4c43b2 100644 --- a/src/core/hle/service/audio/audout_u.h +++ b/src/core/hle/service/audio/audout_u.h | |||
| @@ -4,6 +4,7 @@ | |||
| 4 | 4 | ||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <vector> | ||
| 7 | #include "core/hle/service/service.h" | 8 | #include "core/hle/service/service.h" |
| 8 | 9 | ||
| 9 | namespace AudioCore { | 10 | namespace AudioCore { |
| @@ -24,7 +25,7 @@ public: | |||
| 24 | ~AudOutU() override; | 25 | ~AudOutU() override; |
| 25 | 26 | ||
| 26 | private: | 27 | private: |
| 27 | std::shared_ptr<IAudioOut> audio_out_interface; | 28 | std::vector<std::shared_ptr<IAudioOut>> audio_out_interfaces; |
| 28 | std::unique_ptr<AudioCore::AudioOut> audio_core; | 29 | std::unique_ptr<AudioCore::AudioOut> audio_core; |
| 29 | 30 | ||
| 30 | void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); | 31 | void ListAudioOutsImpl(Kernel::HLERequestContext& ctx); |
diff --git a/src/core/hle/service/audio/audren_u.cpp b/src/core/hle/service/audio/audren_u.cpp index d3ea57ea7..1c418a9bb 100644 --- a/src/core/hle/service/audio/audren_u.cpp +++ b/src/core/hle/service/audio/audren_u.cpp | |||
| @@ -52,74 +52,79 @@ private: | |||
| 52 | } | 52 | } |
| 53 | 53 | ||
| 54 | void GetSampleRate(Kernel::HLERequestContext& ctx) { | 54 | void GetSampleRate(Kernel::HLERequestContext& ctx) { |
| 55 | LOG_DEBUG(Service_Audio, "called"); | ||
| 56 | |||
| 55 | IPC::ResponseBuilder rb{ctx, 3}; | 57 | IPC::ResponseBuilder rb{ctx, 3}; |
| 56 | rb.Push(RESULT_SUCCESS); | 58 | rb.Push(RESULT_SUCCESS); |
| 57 | rb.Push<u32>(renderer->GetSampleRate()); | 59 | rb.Push<u32>(renderer->GetSampleRate()); |
| 58 | LOG_DEBUG(Service_Audio, "called"); | ||
| 59 | } | 60 | } |
| 60 | 61 | ||
| 61 | void GetSampleCount(Kernel::HLERequestContext& ctx) { | 62 | void GetSampleCount(Kernel::HLERequestContext& ctx) { |
| 63 | LOG_DEBUG(Service_Audio, "called"); | ||
| 64 | |||
| 62 | IPC::ResponseBuilder rb{ctx, 3}; | 65 | IPC::ResponseBuilder rb{ctx, 3}; |
| 63 | rb.Push(RESULT_SUCCESS); | 66 | rb.Push(RESULT_SUCCESS); |
| 64 | rb.Push<u32>(renderer->GetSampleCount()); | 67 | rb.Push<u32>(renderer->GetSampleCount()); |
| 65 | LOG_DEBUG(Service_Audio, "called"); | ||
| 66 | } | 68 | } |
| 67 | 69 | ||
| 68 | void GetState(Kernel::HLERequestContext& ctx) { | 70 | void GetState(Kernel::HLERequestContext& ctx) { |
| 71 | LOG_DEBUG(Service_Audio, "called"); | ||
| 72 | |||
| 69 | IPC::ResponseBuilder rb{ctx, 3}; | 73 | IPC::ResponseBuilder rb{ctx, 3}; |
| 70 | rb.Push(RESULT_SUCCESS); | 74 | rb.Push(RESULT_SUCCESS); |
| 71 | rb.Push<u32>(static_cast<u32>(renderer->GetStreamState())); | 75 | rb.Push<u32>(static_cast<u32>(renderer->GetStreamState())); |
| 72 | LOG_DEBUG(Service_Audio, "called"); | ||
| 73 | } | 76 | } |
| 74 | 77 | ||
| 75 | void GetMixBufferCount(Kernel::HLERequestContext& ctx) { | 78 | void GetMixBufferCount(Kernel::HLERequestContext& ctx) { |
| 79 | LOG_DEBUG(Service_Audio, "called"); | ||
| 80 | |||
| 76 | IPC::ResponseBuilder rb{ctx, 3}; | 81 | IPC::ResponseBuilder rb{ctx, 3}; |
| 77 | rb.Push(RESULT_SUCCESS); | 82 | rb.Push(RESULT_SUCCESS); |
| 78 | rb.Push<u32>(renderer->GetMixBufferCount()); | 83 | rb.Push<u32>(renderer->GetMixBufferCount()); |
| 79 | LOG_DEBUG(Service_Audio, "called"); | ||
| 80 | } | 84 | } |
| 81 | 85 | ||
| 82 | void RequestUpdateImpl(Kernel::HLERequestContext& ctx) { | 86 | void RequestUpdateImpl(Kernel::HLERequestContext& ctx) { |
| 87 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 88 | |||
| 83 | ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer())); | 89 | ctx.WriteBuffer(renderer->UpdateAudioRenderer(ctx.ReadBuffer())); |
| 84 | IPC::ResponseBuilder rb{ctx, 2}; | 90 | IPC::ResponseBuilder rb{ctx, 2}; |
| 85 | rb.Push(RESULT_SUCCESS); | 91 | rb.Push(RESULT_SUCCESS); |
| 86 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 87 | } | 92 | } |
| 88 | 93 | ||
| 89 | void Start(Kernel::HLERequestContext& ctx) { | 94 | void Start(Kernel::HLERequestContext& ctx) { |
| 95 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 96 | |||
| 90 | IPC::ResponseBuilder rb{ctx, 2}; | 97 | IPC::ResponseBuilder rb{ctx, 2}; |
| 91 | 98 | ||
| 92 | rb.Push(RESULT_SUCCESS); | 99 | rb.Push(RESULT_SUCCESS); |
| 93 | |||
| 94 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 95 | } | 100 | } |
| 96 | 101 | ||
| 97 | void Stop(Kernel::HLERequestContext& ctx) { | 102 | void Stop(Kernel::HLERequestContext& ctx) { |
| 103 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 104 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2}; | 105 | IPC::ResponseBuilder rb{ctx, 2}; |
| 99 | 106 | ||
| 100 | rb.Push(RESULT_SUCCESS); | 107 | rb.Push(RESULT_SUCCESS); |
| 101 | |||
| 102 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 103 | } | 108 | } |
| 104 | 109 | ||
| 105 | void QuerySystemEvent(Kernel::HLERequestContext& ctx) { | 110 | void QuerySystemEvent(Kernel::HLERequestContext& ctx) { |
| 111 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 112 | |||
| 106 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 113 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 107 | rb.Push(RESULT_SUCCESS); | 114 | rb.Push(RESULT_SUCCESS); |
| 108 | rb.PushCopyObjects(system_event); | 115 | rb.PushCopyObjects(system_event); |
| 109 | |||
| 110 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 111 | } | 116 | } |
| 112 | 117 | ||
| 113 | void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { | 118 | void SetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { |
| 114 | IPC::RequestParser rp{ctx}; | 119 | IPC::RequestParser rp{ctx}; |
| 115 | rendering_time_limit_percent = rp.Pop<u32>(); | 120 | rendering_time_limit_percent = rp.Pop<u32>(); |
| 121 | LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}", | ||
| 122 | rendering_time_limit_percent); | ||
| 123 | |||
| 116 | ASSERT(rendering_time_limit_percent >= 0 && rendering_time_limit_percent <= 100); | 124 | ASSERT(rendering_time_limit_percent >= 0 && rendering_time_limit_percent <= 100); |
| 117 | 125 | ||
| 118 | IPC::ResponseBuilder rb{ctx, 2}; | 126 | IPC::ResponseBuilder rb{ctx, 2}; |
| 119 | rb.Push(RESULT_SUCCESS); | 127 | rb.Push(RESULT_SUCCESS); |
| 120 | |||
| 121 | LOG_DEBUG(Service_Audio, "called. rendering_time_limit_percent={}", | ||
| 122 | rendering_time_limit_percent); | ||
| 123 | } | 128 | } |
| 124 | 129 | ||
| 125 | void GetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { | 130 | void GetRenderingTimeLimit(Kernel::HLERequestContext& ctx) { |
| @@ -211,6 +216,7 @@ private: | |||
| 211 | 216 | ||
| 212 | void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { | 217 | void GetActiveChannelCount(Kernel::HLERequestContext& ctx) { |
| 213 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | 218 | LOG_WARNING(Service_Audio, "(STUBBED) called"); |
| 219 | |||
| 214 | IPC::ResponseBuilder rb{ctx, 3}; | 220 | IPC::ResponseBuilder rb{ctx, 3}; |
| 215 | rb.Push(RESULT_SUCCESS); | 221 | rb.Push(RESULT_SUCCESS); |
| 216 | rb.Push<u32>(1); | 222 | rb.Push<u32>(1); |
| @@ -235,19 +241,20 @@ AudRenU::AudRenU() : ServiceFramework("audren:u") { | |||
| 235 | AudRenU::~AudRenU() = default; | 241 | AudRenU::~AudRenU() = default; |
| 236 | 242 | ||
| 237 | void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { | 243 | void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { |
| 244 | LOG_DEBUG(Service_Audio, "called"); | ||
| 245 | |||
| 238 | IPC::RequestParser rp{ctx}; | 246 | IPC::RequestParser rp{ctx}; |
| 239 | auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); | 247 | auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); |
| 240 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 248 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 241 | 249 | ||
| 242 | rb.Push(RESULT_SUCCESS); | 250 | rb.Push(RESULT_SUCCESS); |
| 243 | rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params)); | 251 | rb.PushIpcInterface<Audio::IAudioRenderer>(std::move(params)); |
| 244 | |||
| 245 | LOG_DEBUG(Service_Audio, "called"); | ||
| 246 | } | 252 | } |
| 247 | 253 | ||
| 248 | void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | 254 | void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { |
| 249 | IPC::RequestParser rp{ctx}; | 255 | IPC::RequestParser rp{ctx}; |
| 250 | auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); | 256 | auto params = rp.PopRaw<AudioCore::AudioRendererParameter>(); |
| 257 | LOG_DEBUG(Service_Audio, "called"); | ||
| 251 | 258 | ||
| 252 | u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40); | 259 | u64 buffer_sz = Common::AlignUp(4 * params.mix_buffer_count, 0x40); |
| 253 | buffer_sz += params.unknown_c * 1024; | 260 | buffer_sz += params.unknown_c * 1024; |
| @@ -301,26 +308,26 @@ void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { | |||
| 301 | rb.Push(RESULT_SUCCESS); | 308 | rb.Push(RESULT_SUCCESS); |
| 302 | rb.Push<u64>(output_sz); | 309 | rb.Push<u64>(output_sz); |
| 303 | 310 | ||
| 304 | LOG_DEBUG(Service_Audio, "called, buffer_size=0x{:X}", output_sz); | 311 | LOG_DEBUG(Service_Audio, "buffer_size=0x{:X}", output_sz); |
| 305 | } | 312 | } |
| 306 | 313 | ||
| 307 | void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) { | 314 | void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) { |
| 315 | LOG_DEBUG(Service_Audio, "called"); | ||
| 316 | |||
| 308 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 317 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 309 | 318 | ||
| 310 | rb.Push(RESULT_SUCCESS); | 319 | rb.Push(RESULT_SUCCESS); |
| 311 | rb.PushIpcInterface<Audio::IAudioDevice>(); | 320 | rb.PushIpcInterface<Audio::IAudioDevice>(); |
| 312 | |||
| 313 | LOG_DEBUG(Service_Audio, "called"); | ||
| 314 | } | 321 | } |
| 315 | 322 | ||
| 316 | void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { | 323 | void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { |
| 324 | LOG_WARNING(Service_Audio, "(STUBBED) called"); | ||
| 325 | |||
| 317 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 326 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 318 | 327 | ||
| 319 | rb.Push(RESULT_SUCCESS); | 328 | rb.Push(RESULT_SUCCESS); |
| 320 | rb.PushIpcInterface<Audio::IAudioDevice>(); | 329 | rb.PushIpcInterface<Audio::IAudioDevice>(); // TODO(ogniK): Figure out what is different |
| 321 | 330 | // based on the current revision | |
| 322 | LOG_WARNING(Service_Audio, "(STUBBED) called"); // TODO(ogniK): Figure out what is different | ||
| 323 | // based on the current revision | ||
| 324 | } | 331 | } |
| 325 | 332 | ||
| 326 | bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { | 333 | bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { |
diff --git a/src/core/hle/service/audio/hwopus.cpp b/src/core/hle/service/audio/hwopus.cpp index 763e619a4..a850cadc8 100644 --- a/src/core/hle/service/audio/hwopus.cpp +++ b/src/core/hle/service/audio/hwopus.cpp | |||
| @@ -46,10 +46,13 @@ public: | |||
| 46 | 46 | ||
| 47 | private: | 47 | private: |
| 48 | void DecodeInterleaved(Kernel::HLERequestContext& ctx) { | 48 | void DecodeInterleaved(Kernel::HLERequestContext& ctx) { |
| 49 | LOG_DEBUG(Audio, "called"); | ||
| 50 | |||
| 49 | u32 consumed = 0; | 51 | u32 consumed = 0; |
| 50 | u32 sample_count = 0; | 52 | u32 sample_count = 0; |
| 51 | std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); | 53 | std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); |
| 52 | if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) { | 54 | if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples)) { |
| 55 | LOG_ERROR(Audio, "Failed to decode opus data"); | ||
| 53 | IPC::ResponseBuilder rb{ctx, 2}; | 56 | IPC::ResponseBuilder rb{ctx, 2}; |
| 54 | // TODO(ogniK): Use correct error code | 57 | // TODO(ogniK): Use correct error code |
| 55 | rb.Push(ResultCode(-1)); | 58 | rb.Push(ResultCode(-1)); |
| @@ -63,12 +66,15 @@ private: | |||
| 63 | } | 66 | } |
| 64 | 67 | ||
| 65 | void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) { | 68 | void DecodeInterleavedWithPerformance(Kernel::HLERequestContext& ctx) { |
| 69 | LOG_DEBUG(Audio, "called"); | ||
| 70 | |||
| 66 | u32 consumed = 0; | 71 | u32 consumed = 0; |
| 67 | u32 sample_count = 0; | 72 | u32 sample_count = 0; |
| 68 | u64 performance = 0; | 73 | u64 performance = 0; |
| 69 | std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); | 74 | std::vector<opus_int16> samples(ctx.GetWriteBufferSize() / sizeof(opus_int16)); |
| 70 | if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples, | 75 | if (!Decoder_DecodeInterleaved(consumed, sample_count, ctx.ReadBuffer(), samples, |
| 71 | performance)) { | 76 | performance)) { |
| 77 | LOG_ERROR(Audio, "Failed to decode opus data"); | ||
| 72 | IPC::ResponseBuilder rb{ctx, 2}; | 78 | IPC::ResponseBuilder rb{ctx, 2}; |
| 73 | // TODO(ogniK): Use correct error code | 79 | // TODO(ogniK): Use correct error code |
| 74 | rb.Push(ResultCode(-1)); | 80 | rb.Push(ResultCode(-1)); |
| @@ -88,24 +94,39 @@ private: | |||
| 88 | std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) { | 94 | std::optional<std::reference_wrapper<u64>> performance_time = std::nullopt) { |
| 89 | const auto start_time = std::chrono::high_resolution_clock::now(); | 95 | const auto start_time = std::chrono::high_resolution_clock::now(); |
| 90 | std::size_t raw_output_sz = output.size() * sizeof(opus_int16); | 96 | std::size_t raw_output_sz = output.size() * sizeof(opus_int16); |
| 91 | if (sizeof(OpusHeader) > input.size()) | 97 | if (sizeof(OpusHeader) > input.size()) { |
| 98 | LOG_ERROR(Audio, "Input is smaller than the header size, header_sz={}, input_sz={}", | ||
| 99 | sizeof(OpusHeader), input.size()); | ||
| 92 | return false; | 100 | return false; |
| 101 | } | ||
| 93 | OpusHeader hdr{}; | 102 | OpusHeader hdr{}; |
| 94 | std::memcpy(&hdr, input.data(), sizeof(OpusHeader)); | 103 | std::memcpy(&hdr, input.data(), sizeof(OpusHeader)); |
| 95 | if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) { | 104 | if (sizeof(OpusHeader) + static_cast<u32>(hdr.sz) > input.size()) { |
| 105 | LOG_ERROR(Audio, "Input does not fit in the opus header size. data_sz={}, input_sz={}", | ||
| 106 | sizeof(OpusHeader) + static_cast<u32>(hdr.sz), input.size()); | ||
| 96 | return false; | 107 | return false; |
| 97 | } | 108 | } |
| 98 | auto frame = input.data() + sizeof(OpusHeader); | 109 | auto frame = input.data() + sizeof(OpusHeader); |
| 99 | auto decoded_sample_count = opus_packet_get_nb_samples( | 110 | auto decoded_sample_count = opus_packet_get_nb_samples( |
| 100 | frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)), | 111 | frame, static_cast<opus_int32>(input.size() - sizeof(OpusHeader)), |
| 101 | static_cast<opus_int32>(sample_rate)); | 112 | static_cast<opus_int32>(sample_rate)); |
| 102 | if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) | 113 | if (decoded_sample_count * channel_count * sizeof(u16) > raw_output_sz) { |
| 114 | LOG_ERROR( | ||
| 115 | Audio, | ||
| 116 | "Decoded data does not fit into the output data, decoded_sz={}, raw_output_sz={}", | ||
| 117 | decoded_sample_count * channel_count * sizeof(u16), raw_output_sz); | ||
| 103 | return false; | 118 | return false; |
| 119 | } | ||
| 120 | const int frame_size = (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)); | ||
| 104 | auto out_sample_count = | 121 | auto out_sample_count = |
| 105 | opus_decode(decoder.get(), frame, hdr.sz, output.data(), | 122 | opus_decode(decoder.get(), frame, hdr.sz, output.data(), frame_size, 0); |
| 106 | (static_cast<int>(raw_output_sz / sizeof(s16) / channel_count)), 0); | 123 | if (out_sample_count < 0) { |
| 107 | if (out_sample_count < 0) | 124 | LOG_ERROR(Audio, |
| 125 | "Incorrect sample count received from opus_decode, " | ||
| 126 | "output_sample_count={}, frame_size={}, data_sz_from_hdr={}", | ||
| 127 | out_sample_count, frame_size, static_cast<u32>(hdr.sz)); | ||
| 108 | return false; | 128 | return false; |
| 129 | } | ||
| 109 | const auto end_time = std::chrono::high_resolution_clock::now() - start_time; | 130 | const auto end_time = std::chrono::high_resolution_clock::now() - start_time; |
| 110 | sample_count = out_sample_count; | 131 | sample_count = out_sample_count; |
| 111 | consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz); | 132 | consumed = static_cast<u32>(sizeof(OpusHeader) + hdr.sz); |
| @@ -134,14 +155,17 @@ static std::size_t WorkerBufferSize(u32 channel_count) { | |||
| 134 | 155 | ||
| 135 | void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) { | 156 | void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) { |
| 136 | IPC::RequestParser rp{ctx}; | 157 | IPC::RequestParser rp{ctx}; |
| 137 | auto sample_rate = rp.Pop<u32>(); | 158 | const auto sample_rate = rp.Pop<u32>(); |
| 138 | auto channel_count = rp.Pop<u32>(); | 159 | const auto channel_count = rp.Pop<u32>(); |
| 160 | LOG_DEBUG(Audio, "called with sample_rate={}, channel_count={}", sample_rate, channel_count); | ||
| 161 | |||
| 139 | ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || | 162 | ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || |
| 140 | sample_rate == 12000 || sample_rate == 8000, | 163 | sample_rate == 12000 || sample_rate == 8000, |
| 141 | "Invalid sample rate"); | 164 | "Invalid sample rate"); |
| 142 | ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); | 165 | ASSERT_MSG(channel_count == 1 || channel_count == 2, "Invalid channel count"); |
| 143 | u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count)); | 166 | |
| 144 | LOG_DEBUG(Audio, "called worker_buffer_sz={}", worker_buffer_sz); | 167 | const u32 worker_buffer_sz = static_cast<u32>(WorkerBufferSize(channel_count)); |
| 168 | LOG_DEBUG(Audio, "worker_buffer_sz={}", worker_buffer_sz); | ||
| 145 | 169 | ||
| 146 | IPC::ResponseBuilder rb{ctx, 3}; | 170 | IPC::ResponseBuilder rb{ctx, 3}; |
| 147 | rb.Push(RESULT_SUCCESS); | 171 | rb.Push(RESULT_SUCCESS); |
| @@ -155,6 +179,7 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { | |||
| 155 | auto buffer_sz = rp.Pop<u32>(); | 179 | auto buffer_sz = rp.Pop<u32>(); |
| 156 | LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate, | 180 | LOG_DEBUG(Audio, "called sample_rate={}, channel_count={}, buffer_size={}", sample_rate, |
| 157 | channel_count, buffer_sz); | 181 | channel_count, buffer_sz); |
| 182 | |||
| 158 | ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || | 183 | ASSERT_MSG(sample_rate == 48000 || sample_rate == 24000 || sample_rate == 16000 || |
| 159 | sample_rate == 12000 || sample_rate == 8000, | 184 | sample_rate == 12000 || sample_rate == 8000, |
| 160 | "Invalid sample rate"); | 185 | "Invalid sample rate"); |
| @@ -164,7 +189,8 @@ void HwOpus::OpenOpusDecoder(Kernel::HLERequestContext& ctx) { | |||
| 164 | ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large"); | 189 | ASSERT_MSG(buffer_sz >= worker_sz, "Worker buffer too large"); |
| 165 | std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ | 190 | std::unique_ptr<OpusDecoder, OpusDeleter> decoder{ |
| 166 | static_cast<OpusDecoder*>(operator new(worker_sz))}; | 191 | static_cast<OpusDecoder*>(operator new(worker_sz))}; |
| 167 | if (opus_decoder_init(decoder.get(), sample_rate, channel_count)) { | 192 | if (const int err = opus_decoder_init(decoder.get(), sample_rate, channel_count)) { |
| 193 | LOG_ERROR(Audio, "Failed to init opus decoder with error={}", err); | ||
| 168 | IPC::ResponseBuilder rb{ctx, 2}; | 194 | IPC::ResponseBuilder rb{ctx, 2}; |
| 169 | // TODO(ogniK): Use correct error code | 195 | // TODO(ogniK): Use correct error code |
| 170 | rb.Push(ResultCode(-1)); | 196 | rb.Push(ResultCode(-1)); |
diff --git a/src/core/hle/service/bcat/module.cpp b/src/core/hle/service/bcat/module.cpp index 6e7b795fb..b7bd738fc 100644 --- a/src/core/hle/service/bcat/module.cpp +++ b/src/core/hle/service/bcat/module.cpp | |||
| @@ -33,10 +33,11 @@ public: | |||
| 33 | }; | 33 | }; |
| 34 | 34 | ||
| 35 | void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { | 35 | void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { |
| 36 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 37 | |||
| 36 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 38 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 37 | rb.Push(RESULT_SUCCESS); | 39 | rb.Push(RESULT_SUCCESS); |
| 38 | rb.PushIpcInterface<IBcatService>(); | 40 | rb.PushIpcInterface<IBcatService>(); |
| 39 | LOG_DEBUG(Service_BCAT, "called"); | ||
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 43 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) |
diff --git a/src/core/hle/service/btdrv/btdrv.cpp b/src/core/hle/service/btdrv/btdrv.cpp index f3bde6d0d..2eadcdd05 100644 --- a/src/core/hle/service/btdrv/btdrv.cpp +++ b/src/core/hle/service/btdrv/btdrv.cpp | |||
| @@ -34,13 +34,14 @@ public: | |||
| 34 | 34 | ||
| 35 | private: | 35 | private: |
| 36 | void RegisterEvent(Kernel::HLERequestContext& ctx) { | 36 | void RegisterEvent(Kernel::HLERequestContext& ctx) { |
| 37 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 38 | |||
| 37 | auto& kernel = Core::System::GetInstance().Kernel(); | 39 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 38 | register_event = | 40 | register_event = |
| 39 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "BT:RegisterEvent"); | 41 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "BT:RegisterEvent"); |
| 40 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 42 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 41 | rb.Push(RESULT_SUCCESS); | 43 | rb.Push(RESULT_SUCCESS); |
| 42 | rb.PushCopyObjects(register_event); | 44 | rb.PushCopyObjects(register_event); |
| 43 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 44 | } | 45 | } |
| 45 | Kernel::SharedPtr<Kernel::Event> register_event; | 46 | Kernel::SharedPtr<Kernel::Event> register_event; |
| 46 | }; | 47 | }; |
diff --git a/src/core/hle/service/btm/btm.cpp b/src/core/hle/service/btm/btm.cpp index a02f6b53a..463a79351 100644 --- a/src/core/hle/service/btm/btm.cpp +++ b/src/core/hle/service/btm/btm.cpp | |||
| @@ -57,40 +57,44 @@ public: | |||
| 57 | 57 | ||
| 58 | private: | 58 | private: |
| 59 | void GetScanEvent(Kernel::HLERequestContext& ctx) { | 59 | void GetScanEvent(Kernel::HLERequestContext& ctx) { |
| 60 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 61 | |||
| 60 | auto& kernel = Core::System::GetInstance().Kernel(); | 62 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 61 | scan_event = | 63 | scan_event = |
| 62 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ScanEvent"); | 64 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ScanEvent"); |
| 63 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 65 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 64 | rb.Push(RESULT_SUCCESS); | 66 | rb.Push(RESULT_SUCCESS); |
| 65 | rb.PushCopyObjects(scan_event); | 67 | rb.PushCopyObjects(scan_event); |
| 66 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 67 | } | 68 | } |
| 68 | void GetConnectionEvent(Kernel::HLERequestContext& ctx) { | 69 | void GetConnectionEvent(Kernel::HLERequestContext& ctx) { |
| 70 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 71 | |||
| 69 | auto& kernel = Core::System::GetInstance().Kernel(); | 72 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 70 | connection_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, | 73 | connection_event = Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, |
| 71 | "IBtmUserCore:ConnectionEvent"); | 74 | "IBtmUserCore:ConnectionEvent"); |
| 72 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 75 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 73 | rb.Push(RESULT_SUCCESS); | 76 | rb.Push(RESULT_SUCCESS); |
| 74 | rb.PushCopyObjects(connection_event); | 77 | rb.PushCopyObjects(connection_event); |
| 75 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 76 | } | 78 | } |
| 77 | void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) { | 79 | void GetDiscoveryEvent(Kernel::HLERequestContext& ctx) { |
| 80 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 81 | |||
| 78 | auto& kernel = Core::System::GetInstance().Kernel(); | 82 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 79 | service_discovery = | 83 | service_discovery = |
| 80 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery"); | 84 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:Discovery"); |
| 81 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 85 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 82 | rb.Push(RESULT_SUCCESS); | 86 | rb.Push(RESULT_SUCCESS); |
| 83 | rb.PushCopyObjects(service_discovery); | 87 | rb.PushCopyObjects(service_discovery); |
| 84 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 85 | } | 88 | } |
| 86 | void GetConfigEvent(Kernel::HLERequestContext& ctx) { | 89 | void GetConfigEvent(Kernel::HLERequestContext& ctx) { |
| 90 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 91 | |||
| 87 | auto& kernel = Core::System::GetInstance().Kernel(); | 92 | auto& kernel = Core::System::GetInstance().Kernel(); |
| 88 | config_event = | 93 | config_event = |
| 89 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConfigEvent"); | 94 | Kernel::Event::Create(kernel, Kernel::ResetType::OneShot, "IBtmUserCore:ConfigEvent"); |
| 90 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 95 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 91 | rb.Push(RESULT_SUCCESS); | 96 | rb.Push(RESULT_SUCCESS); |
| 92 | rb.PushCopyObjects(config_event); | 97 | rb.PushCopyObjects(config_event); |
| 93 | LOG_WARNING(Service_BTM, "(STUBBED) called"); | ||
| 94 | } | 98 | } |
| 95 | Kernel::SharedPtr<Kernel::Event> scan_event; | 99 | Kernel::SharedPtr<Kernel::Event> scan_event; |
| 96 | Kernel::SharedPtr<Kernel::Event> connection_event; | 100 | Kernel::SharedPtr<Kernel::Event> connection_event; |
| @@ -111,10 +115,11 @@ public: | |||
| 111 | 115 | ||
| 112 | private: | 116 | private: |
| 113 | void GetCoreImpl(Kernel::HLERequestContext& ctx) { | 117 | void GetCoreImpl(Kernel::HLERequestContext& ctx) { |
| 118 | LOG_DEBUG(Service_BTM, "called"); | ||
| 119 | |||
| 114 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 120 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 115 | rb.Push(RESULT_SUCCESS); | 121 | rb.Push(RESULT_SUCCESS); |
| 116 | rb.PushIpcInterface<IBtmUserCore>(); | 122 | rb.PushIpcInterface<IBtmUserCore>(); |
| 117 | LOG_DEBUG(Service_BTM, "called"); | ||
| 118 | } | 123 | } |
| 119 | }; | 124 | }; |
| 120 | 125 | ||
| @@ -209,11 +214,11 @@ public: | |||
| 209 | 214 | ||
| 210 | private: | 215 | private: |
| 211 | void GetCoreImpl(Kernel::HLERequestContext& ctx) { | 216 | void GetCoreImpl(Kernel::HLERequestContext& ctx) { |
| 217 | LOG_DEBUG(Service_BTM, "called"); | ||
| 218 | |||
| 212 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 213 | rb.Push(RESULT_SUCCESS); | 220 | rb.Push(RESULT_SUCCESS); |
| 214 | rb.PushIpcInterface<IBtmSystemCore>(); | 221 | rb.PushIpcInterface<IBtmSystemCore>(); |
| 215 | |||
| 216 | LOG_DEBUG(Service_BTM, "called"); | ||
| 217 | } | 222 | } |
| 218 | }; | 223 | }; |
| 219 | 224 | ||
diff --git a/src/core/hle/service/fgm/fgm.cpp b/src/core/hle/service/fgm/fgm.cpp index 566fbf924..e461274c1 100644 --- a/src/core/hle/service/fgm/fgm.cpp +++ b/src/core/hle/service/fgm/fgm.cpp | |||
| @@ -42,11 +42,11 @@ public: | |||
| 42 | 42 | ||
| 43 | private: | 43 | private: |
| 44 | void Initialize(Kernel::HLERequestContext& ctx) { | 44 | void Initialize(Kernel::HLERequestContext& ctx) { |
| 45 | LOG_DEBUG(Service_FGM, "called"); | ||
| 46 | |||
| 45 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 47 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 46 | rb.Push(RESULT_SUCCESS); | 48 | rb.Push(RESULT_SUCCESS); |
| 47 | rb.PushIpcInterface<IRequest>(); | 49 | rb.PushIpcInterface<IRequest>(); |
| 48 | |||
| 49 | LOG_DEBUG(Service_FGM, "called"); | ||
| 50 | } | 50 | } |
| 51 | }; | 51 | }; |
| 52 | 52 | ||
diff --git a/src/core/hle/service/filesystem/filesystem.cpp b/src/core/hle/service/filesystem/filesystem.cpp index 5d6294016..2aa77f68d 100644 --- a/src/core/hle/service/filesystem/filesystem.cpp +++ b/src/core/hle/service/filesystem/filesystem.cpp | |||
| @@ -341,6 +341,10 @@ std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents() { | |||
| 341 | return registered_cache_union; | 341 | return registered_cache_union; |
| 342 | } | 342 | } |
| 343 | 343 | ||
| 344 | void ClearUnionContents() { | ||
| 345 | registered_cache_union = nullptr; | ||
| 346 | } | ||
| 347 | |||
| 344 | FileSys::RegisteredCache* GetSystemNANDContents() { | 348 | FileSys::RegisteredCache* GetSystemNANDContents() { |
| 345 | LOG_TRACE(Service_FS, "Opening System NAND Contents"); | 349 | LOG_TRACE(Service_FS, "Opening System NAND Contents"); |
| 346 | 350 | ||
| @@ -391,6 +395,7 @@ void CreateFactories(FileSys::VfsFilesystem& vfs, bool overwrite) { | |||
| 391 | bis_factory = nullptr; | 395 | bis_factory = nullptr; |
| 392 | save_data_factory = nullptr; | 396 | save_data_factory = nullptr; |
| 393 | sdmc_factory = nullptr; | 397 | sdmc_factory = nullptr; |
| 398 | ClearUnionContents(); | ||
| 394 | } | 399 | } |
| 395 | 400 | ||
| 396 | auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), | 401 | auto nand_directory = vfs.OpenDirectory(FileUtil::GetUserPath(FileUtil::UserPath::NANDDir), |
diff --git a/src/core/hle/service/filesystem/filesystem.h b/src/core/hle/service/filesystem/filesystem.h index ff9182e84..0a6cb6635 100644 --- a/src/core/hle/service/filesystem/filesystem.h +++ b/src/core/hle/service/filesystem/filesystem.h | |||
| @@ -49,6 +49,7 @@ ResultVal<FileSys::VirtualDir> OpenSaveDataSpace(FileSys::SaveDataSpaceId space) | |||
| 49 | ResultVal<FileSys::VirtualDir> OpenSDMC(); | 49 | ResultVal<FileSys::VirtualDir> OpenSDMC(); |
| 50 | 50 | ||
| 51 | std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); | 51 | std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); |
| 52 | void ClearUnionContents(); | ||
| 52 | 53 | ||
| 53 | FileSys::RegisteredCache* GetSystemNANDContents(); | 54 | FileSys::RegisteredCache* GetSystemNANDContents(); |
| 54 | FileSys::RegisteredCache* GetUserNANDContents(); | 55 | FileSys::RegisteredCache* GetUserNANDContents(); |
diff --git a/src/core/hle/service/filesystem/fsp_srv.cpp b/src/core/hle/service/filesystem/fsp_srv.cpp index 038dc80b1..99d9ebc39 100644 --- a/src/core/hle/service/filesystem/fsp_srv.cpp +++ b/src/core/hle/service/filesystem/fsp_srv.cpp | |||
| @@ -62,11 +62,13 @@ private: | |||
| 62 | 62 | ||
| 63 | // Error checking | 63 | // Error checking |
| 64 | if (length < 0) { | 64 | if (length < 0) { |
| 65 | LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); | ||
| 65 | IPC::ResponseBuilder rb{ctx, 2}; | 66 | IPC::ResponseBuilder rb{ctx, 2}; |
| 66 | rb.Push(FileSys::ERROR_INVALID_SIZE); | 67 | rb.Push(FileSys::ERROR_INVALID_SIZE); |
| 67 | return; | 68 | return; |
| 68 | } | 69 | } |
| 69 | if (offset < 0) { | 70 | if (offset < 0) { |
| 71 | LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); | ||
| 70 | IPC::ResponseBuilder rb{ctx, 2}; | 72 | IPC::ResponseBuilder rb{ctx, 2}; |
| 71 | rb.Push(FileSys::ERROR_INVALID_OFFSET); | 73 | rb.Push(FileSys::ERROR_INVALID_OFFSET); |
| 72 | return; | 74 | return; |
| @@ -107,11 +109,13 @@ private: | |||
| 107 | 109 | ||
| 108 | // Error checking | 110 | // Error checking |
| 109 | if (length < 0) { | 111 | if (length < 0) { |
| 112 | LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); | ||
| 110 | IPC::ResponseBuilder rb{ctx, 2}; | 113 | IPC::ResponseBuilder rb{ctx, 2}; |
| 111 | rb.Push(FileSys::ERROR_INVALID_SIZE); | 114 | rb.Push(FileSys::ERROR_INVALID_SIZE); |
| 112 | return; | 115 | return; |
| 113 | } | 116 | } |
| 114 | if (offset < 0) { | 117 | if (offset < 0) { |
| 118 | LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); | ||
| 115 | IPC::ResponseBuilder rb{ctx, 2}; | 119 | IPC::ResponseBuilder rb{ctx, 2}; |
| 116 | rb.Push(FileSys::ERROR_INVALID_OFFSET); | 120 | rb.Push(FileSys::ERROR_INVALID_OFFSET); |
| 117 | return; | 121 | return; |
| @@ -138,11 +142,13 @@ private: | |||
| 138 | 142 | ||
| 139 | // Error checking | 143 | // Error checking |
| 140 | if (length < 0) { | 144 | if (length < 0) { |
| 145 | LOG_ERROR(Service_FS, "Length is less than 0, length={}", length); | ||
| 141 | IPC::ResponseBuilder rb{ctx, 2}; | 146 | IPC::ResponseBuilder rb{ctx, 2}; |
| 142 | rb.Push(FileSys::ERROR_INVALID_SIZE); | 147 | rb.Push(FileSys::ERROR_INVALID_SIZE); |
| 143 | return; | 148 | return; |
| 144 | } | 149 | } |
| 145 | if (offset < 0) { | 150 | if (offset < 0) { |
| 151 | LOG_ERROR(Service_FS, "Offset is less than 0, offset={}", offset); | ||
| 146 | IPC::ResponseBuilder rb{ctx, 2}; | 152 | IPC::ResponseBuilder rb{ctx, 2}; |
| 147 | rb.Push(FileSys::ERROR_INVALID_OFFSET); | 153 | rb.Push(FileSys::ERROR_INVALID_OFFSET); |
| 148 | return; | 154 | return; |
| @@ -180,9 +186,10 @@ private: | |||
| 180 | void SetSize(Kernel::HLERequestContext& ctx) { | 186 | void SetSize(Kernel::HLERequestContext& ctx) { |
| 181 | IPC::RequestParser rp{ctx}; | 187 | IPC::RequestParser rp{ctx}; |
| 182 | const u64 size = rp.Pop<u64>(); | 188 | const u64 size = rp.Pop<u64>(); |
| 183 | backend->Resize(size); | ||
| 184 | LOG_DEBUG(Service_FS, "called, size={}", size); | 189 | LOG_DEBUG(Service_FS, "called, size={}", size); |
| 185 | 190 | ||
| 191 | backend->Resize(size); | ||
| 192 | |||
| 186 | IPC::ResponseBuilder rb{ctx, 2}; | 193 | IPC::ResponseBuilder rb{ctx, 2}; |
| 187 | rb.Push(RESULT_SUCCESS); | 194 | rb.Push(RESULT_SUCCESS); |
| 188 | } | 195 | } |
| @@ -465,6 +472,8 @@ public: | |||
| 465 | } | 472 | } |
| 466 | 473 | ||
| 467 | void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) { | 474 | void ReadSaveDataInfo(Kernel::HLERequestContext& ctx) { |
| 475 | LOG_DEBUG(Service_FS, "called"); | ||
| 476 | |||
| 468 | // Calculate how many entries we can fit in the output buffer | 477 | // Calculate how many entries we can fit in the output buffer |
| 469 | const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo); | 478 | const u64 count_entries = ctx.GetWriteBufferSize() / sizeof(SaveDataInfo); |
| 470 | 479 | ||
| @@ -703,6 +712,8 @@ void FSP_SRV::OpenFileSystemWithPatch(Kernel::HLERequestContext& ctx) { | |||
| 703 | 712 | ||
| 704 | const auto type = rp.PopRaw<FileSystemType>(); | 713 | const auto type = rp.PopRaw<FileSystemType>(); |
| 705 | const auto title_id = rp.PopRaw<u64>(); | 714 | const auto title_id = rp.PopRaw<u64>(); |
| 715 | LOG_WARNING(Service_FS, "(STUBBED) called with type={}, title_id={:016X}", | ||
| 716 | static_cast<u8>(type), title_id); | ||
| 706 | 717 | ||
| 707 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; | 718 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; |
| 708 | rb.Push(ResultCode(-1)); | 719 | rb.Push(ResultCode(-1)); |
| @@ -738,6 +749,7 @@ void FSP_SRV::MountSaveData(Kernel::HLERequestContext& ctx) { | |||
| 738 | auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>(); | 749 | auto space_id = rp.PopRaw<FileSys::SaveDataSpaceId>(); |
| 739 | auto unk = rp.Pop<u32>(); | 750 | auto unk = rp.Pop<u32>(); |
| 740 | LOG_INFO(Service_FS, "called with unknown={:08X}", unk); | 751 | LOG_INFO(Service_FS, "called with unknown={:08X}", unk); |
| 752 | |||
| 741 | auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); | 753 | auto save_struct = rp.PopRaw<FileSys::SaveDataDescriptor>(); |
| 742 | 754 | ||
| 743 | auto dir = OpenSaveData(space_id, save_struct); | 755 | auto dir = OpenSaveData(space_id, save_struct); |
| @@ -763,6 +775,7 @@ void FSP_SRV::OpenReadOnlySaveDataFileSystem(Kernel::HLERequestContext& ctx) { | |||
| 763 | void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) { | 775 | void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) { |
| 764 | IPC::RequestParser rp{ctx}; | 776 | IPC::RequestParser rp{ctx}; |
| 765 | const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>(); | 777 | const auto space = rp.PopRaw<FileSys::SaveDataSpaceId>(); |
| 778 | LOG_INFO(Service_FS, "called, space={}", static_cast<u8>(space)); | ||
| 766 | 779 | ||
| 767 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 780 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 768 | rb.Push(RESULT_SUCCESS); | 781 | rb.Push(RESULT_SUCCESS); |
diff --git a/src/core/hle/service/hid/controllers/debug_pad.cpp b/src/core/hle/service/hid/controllers/debug_pad.cpp index e76c83aee..c22357d8c 100644 --- a/src/core/hle/service/hid/controllers/debug_pad.cpp +++ b/src/core/hle/service/hid/controllers/debug_pad.cpp | |||
| @@ -71,8 +71,9 @@ void Controller_DebugPad::OnUpdate(u8* data, std::size_t size) { | |||
| 71 | 71 | ||
| 72 | void Controller_DebugPad::OnLoadInputDevices() { | 72 | void Controller_DebugPad::OnLoadInputDevices() { |
| 73 | std::transform(Settings::values.debug_pad_buttons.begin(), | 73 | std::transform(Settings::values.debug_pad_buttons.begin(), |
| 74 | Settings::values.debug_pad_buttons.end(), buttons.begin(), | 74 | Settings::values.debug_pad_buttons.begin() + |
| 75 | Input::CreateDevice<Input::ButtonDevice>); | 75 | Settings::NativeButton::NUM_BUTTONS_HID, |
| 76 | buttons.begin(), Input::CreateDevice<Input::ButtonDevice>); | ||
| 76 | std::transform(Settings::values.debug_pad_analogs.begin(), | 77 | std::transform(Settings::values.debug_pad_analogs.begin(), |
| 77 | Settings::values.debug_pad_analogs.end(), analogs.begin(), | 78 | Settings::values.debug_pad_analogs.end(), analogs.begin(), |
| 78 | Input::CreateDevice<Input::AnalogDevice>); | 79 | Input::CreateDevice<Input::AnalogDevice>); |
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp index 46604887c..22e87a50a 100644 --- a/src/core/hle/service/hid/controllers/npad.cpp +++ b/src/core/hle/service/hid/controllers/npad.cpp | |||
| @@ -524,6 +524,8 @@ void Controller_NPad::SetNpadMode(u32 npad_id, NPadAssignments assignment_mode) | |||
| 524 | 524 | ||
| 525 | void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, | 525 | void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, |
| 526 | const std::vector<Vibration>& vibrations) { | 526 | const std::vector<Vibration>& vibrations) { |
| 527 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 528 | |||
| 527 | if (!can_controllers_vibrate) { | 529 | if (!can_controllers_vibrate) { |
| 528 | return; | 530 | return; |
| 529 | } | 531 | } |
| @@ -533,7 +535,6 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, | |||
| 533 | // TODO(ogniK): Vibrate the physical controller | 535 | // TODO(ogniK): Vibrate the physical controller |
| 534 | } | 536 | } |
| 535 | } | 537 | } |
| 536 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 537 | last_processed_vibration = vibrations.back(); | 538 | last_processed_vibration = vibrations.back(); |
| 538 | } | 539 | } |
| 539 | 540 | ||
| @@ -575,8 +576,8 @@ void Controller_NPad::AddNewControllerAt(NPadControllerType controller, u32 npad | |||
| 575 | return; | 576 | return; |
| 576 | } | 577 | } |
| 577 | 578 | ||
| 578 | connected_controllers[npad_id] = {controller, true}; | 579 | connected_controllers[NPadIdToIndex(npad_id)] = {controller, true}; |
| 579 | InitNewlyAddedControler(npad_id); | 580 | InitNewlyAddedControler(NPadIdToIndex(npad_id)); |
| 580 | } | 581 | } |
| 581 | 582 | ||
| 582 | void Controller_NPad::ConnectNPad(u32 npad_id) { | 583 | void Controller_NPad::ConnectNPad(u32 npad_id) { |
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h index ea8057b80..abff6544d 100644 --- a/src/core/hle/service/hid/controllers/npad.h +++ b/src/core/hle/service/hid/controllers/npad.h | |||
| @@ -80,9 +80,9 @@ public: | |||
| 80 | struct LedPattern { | 80 | struct LedPattern { |
| 81 | explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { | 81 | explicit LedPattern(u64 light1, u64 light2, u64 light3, u64 light4) { |
| 82 | position1.Assign(light1); | 82 | position1.Assign(light1); |
| 83 | position1.Assign(light2); | 83 | position2.Assign(light2); |
| 84 | position1.Assign(light3); | 84 | position3.Assign(light3); |
| 85 | position1.Assign(light4); | 85 | position4.Assign(light4); |
| 86 | } | 86 | } |
| 87 | union { | 87 | union { |
| 88 | u64 raw{}; | 88 | u64 raw{}; |
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp index 7c0dac5dc..46496e9bb 100644 --- a/src/core/hle/service/hid/hid.cpp +++ b/src/core/hle/service/hid/hid.cpp | |||
| @@ -124,10 +124,11 @@ public: | |||
| 124 | 124 | ||
| 125 | private: | 125 | private: |
| 126 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | 126 | void GetSharedMemoryHandle(Kernel::HLERequestContext& ctx) { |
| 127 | LOG_DEBUG(Service_HID, "called"); | ||
| 128 | |||
| 127 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 129 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 128 | rb.Push(RESULT_SUCCESS); | 130 | rb.Push(RESULT_SUCCESS); |
| 129 | rb.PushCopyObjects(shared_mem); | 131 | rb.PushCopyObjects(shared_mem); |
| 130 | LOG_DEBUG(Service_HID, "called"); | ||
| 131 | } | 132 | } |
| 132 | 133 | ||
| 133 | void UpdateControllers(u64 userdata, int cycles_late) { | 134 | void UpdateControllers(u64 userdata, int cycles_late) { |
| @@ -163,9 +164,10 @@ public: | |||
| 163 | 164 | ||
| 164 | private: | 165 | private: |
| 165 | void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { | 166 | void ActivateVibrationDevice(Kernel::HLERequestContext& ctx) { |
| 167 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 168 | |||
| 166 | IPC::ResponseBuilder rb{ctx, 2}; | 169 | IPC::ResponseBuilder rb{ctx, 2}; |
| 167 | rb.Push(RESULT_SUCCESS); | 170 | rb.Push(RESULT_SUCCESS); |
| 168 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 169 | } | 171 | } |
| 170 | }; | 172 | }; |
| 171 | 173 | ||
| @@ -303,6 +305,8 @@ private: | |||
| 303 | std::shared_ptr<IAppletResource> applet_resource; | 305 | std::shared_ptr<IAppletResource> applet_resource; |
| 304 | 306 | ||
| 305 | void CreateAppletResource(Kernel::HLERequestContext& ctx) { | 307 | void CreateAppletResource(Kernel::HLERequestContext& ctx) { |
| 308 | LOG_DEBUG(Service_HID, "called"); | ||
| 309 | |||
| 306 | if (applet_resource == nullptr) { | 310 | if (applet_resource == nullptr) { |
| 307 | applet_resource = std::make_shared<IAppletResource>(); | 311 | applet_resource = std::make_shared<IAppletResource>(); |
| 308 | } | 312 | } |
| @@ -310,206 +314,228 @@ private: | |||
| 310 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 314 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 311 | rb.Push(RESULT_SUCCESS); | 315 | rb.Push(RESULT_SUCCESS); |
| 312 | rb.PushIpcInterface<IAppletResource>(applet_resource); | 316 | rb.PushIpcInterface<IAppletResource>(applet_resource); |
| 313 | LOG_DEBUG(Service_HID, "called"); | ||
| 314 | } | 317 | } |
| 315 | 318 | ||
| 316 | void ActivateXpad(Kernel::HLERequestContext& ctx) { | 319 | void ActivateXpad(Kernel::HLERequestContext& ctx) { |
| 320 | LOG_DEBUG(Service_HID, "called"); | ||
| 321 | |||
| 317 | applet_resource->ActivateController(HidController::XPad); | 322 | applet_resource->ActivateController(HidController::XPad); |
| 318 | IPC::ResponseBuilder rb{ctx, 2}; | 323 | IPC::ResponseBuilder rb{ctx, 2}; |
| 319 | rb.Push(RESULT_SUCCESS); | 324 | rb.Push(RESULT_SUCCESS); |
| 320 | LOG_DEBUG(Service_HID, "called"); | ||
| 321 | } | 325 | } |
| 322 | 326 | ||
| 323 | void ActivateDebugPad(Kernel::HLERequestContext& ctx) { | 327 | void ActivateDebugPad(Kernel::HLERequestContext& ctx) { |
| 328 | LOG_DEBUG(Service_HID, "called"); | ||
| 329 | |||
| 324 | applet_resource->ActivateController(HidController::DebugPad); | 330 | applet_resource->ActivateController(HidController::DebugPad); |
| 325 | IPC::ResponseBuilder rb{ctx, 2}; | 331 | IPC::ResponseBuilder rb{ctx, 2}; |
| 326 | rb.Push(RESULT_SUCCESS); | 332 | rb.Push(RESULT_SUCCESS); |
| 327 | LOG_DEBUG(Service_HID, "called"); | ||
| 328 | } | 333 | } |
| 329 | 334 | ||
| 330 | void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { | 335 | void ActivateTouchScreen(Kernel::HLERequestContext& ctx) { |
| 336 | LOG_DEBUG(Service_HID, "called"); | ||
| 337 | |||
| 331 | applet_resource->ActivateController(HidController::Touchscreen); | 338 | applet_resource->ActivateController(HidController::Touchscreen); |
| 332 | IPC::ResponseBuilder rb{ctx, 2}; | 339 | IPC::ResponseBuilder rb{ctx, 2}; |
| 333 | rb.Push(RESULT_SUCCESS); | 340 | rb.Push(RESULT_SUCCESS); |
| 334 | LOG_DEBUG(Service_HID, "called"); | ||
| 335 | } | 341 | } |
| 336 | 342 | ||
| 337 | void ActivateMouse(Kernel::HLERequestContext& ctx) { | 343 | void ActivateMouse(Kernel::HLERequestContext& ctx) { |
| 344 | LOG_DEBUG(Service_HID, "called"); | ||
| 345 | |||
| 338 | applet_resource->ActivateController(HidController::Mouse); | 346 | applet_resource->ActivateController(HidController::Mouse); |
| 339 | IPC::ResponseBuilder rb{ctx, 2}; | 347 | IPC::ResponseBuilder rb{ctx, 2}; |
| 340 | rb.Push(RESULT_SUCCESS); | 348 | rb.Push(RESULT_SUCCESS); |
| 341 | LOG_DEBUG(Service_HID, "called"); | ||
| 342 | } | 349 | } |
| 343 | 350 | ||
| 344 | void ActivateKeyboard(Kernel::HLERequestContext& ctx) { | 351 | void ActivateKeyboard(Kernel::HLERequestContext& ctx) { |
| 352 | LOG_DEBUG(Service_HID, "called"); | ||
| 353 | |||
| 345 | applet_resource->ActivateController(HidController::Keyboard); | 354 | applet_resource->ActivateController(HidController::Keyboard); |
| 346 | IPC::ResponseBuilder rb{ctx, 2}; | 355 | IPC::ResponseBuilder rb{ctx, 2}; |
| 347 | rb.Push(RESULT_SUCCESS); | 356 | rb.Push(RESULT_SUCCESS); |
| 348 | LOG_DEBUG(Service_HID, "called"); | ||
| 349 | } | 357 | } |
| 350 | 358 | ||
| 351 | void ActivateGesture(Kernel::HLERequestContext& ctx) { | 359 | void ActivateGesture(Kernel::HLERequestContext& ctx) { |
| 360 | LOG_DEBUG(Service_HID, "called"); | ||
| 361 | |||
| 352 | applet_resource->ActivateController(HidController::Gesture); | 362 | applet_resource->ActivateController(HidController::Gesture); |
| 353 | IPC::ResponseBuilder rb{ctx, 2}; | 363 | IPC::ResponseBuilder rb{ctx, 2}; |
| 354 | rb.Push(RESULT_SUCCESS); | 364 | rb.Push(RESULT_SUCCESS); |
| 355 | LOG_DEBUG(Service_HID, "called"); | ||
| 356 | } | 365 | } |
| 357 | 366 | ||
| 358 | void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { | 367 | void ActivateNpadWithRevision(Kernel::HLERequestContext& ctx) { |
| 359 | // Should have no effect with how our npad sets up the data | 368 | // Should have no effect with how our npad sets up the data |
| 369 | LOG_DEBUG(Service_HID, "called"); | ||
| 370 | |||
| 360 | applet_resource->ActivateController(HidController::NPad); | 371 | applet_resource->ActivateController(HidController::NPad); |
| 361 | IPC::ResponseBuilder rb{ctx, 2}; | 372 | IPC::ResponseBuilder rb{ctx, 2}; |
| 362 | rb.Push(RESULT_SUCCESS); | 373 | rb.Push(RESULT_SUCCESS); |
| 363 | LOG_DEBUG(Service_HID, "called"); | ||
| 364 | } | 374 | } |
| 365 | 375 | ||
| 366 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { | 376 | void StartSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 367 | IPC::RequestParser rp{ctx}; | 377 | IPC::RequestParser rp{ctx}; |
| 368 | auto handle = rp.PopRaw<u32>(); | 378 | auto handle = rp.PopRaw<u32>(); |
| 379 | LOG_WARNING(Service_HID, "(STUBBED) called with handle={}", handle); | ||
| 380 | |||
| 369 | IPC::ResponseBuilder rb{ctx, 2}; | 381 | IPC::ResponseBuilder rb{ctx, 2}; |
| 370 | rb.Push(RESULT_SUCCESS); | 382 | rb.Push(RESULT_SUCCESS); |
| 371 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 372 | } | 383 | } |
| 373 | 384 | ||
| 374 | void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { | 385 | void SetGyroscopeZeroDriftMode(Kernel::HLERequestContext& ctx) { |
| 386 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 387 | |||
| 375 | IPC::ResponseBuilder rb{ctx, 2}; | 388 | IPC::ResponseBuilder rb{ctx, 2}; |
| 376 | rb.Push(RESULT_SUCCESS); | 389 | rb.Push(RESULT_SUCCESS); |
| 377 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 378 | } | 390 | } |
| 379 | 391 | ||
| 380 | void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { | 392 | void IsSixAxisSensorAtRest(Kernel::HLERequestContext& ctx) { |
| 393 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 394 | |||
| 381 | IPC::ResponseBuilder rb{ctx, 3}; | 395 | IPC::ResponseBuilder rb{ctx, 3}; |
| 382 | rb.Push(RESULT_SUCCESS); | 396 | rb.Push(RESULT_SUCCESS); |
| 383 | // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. | 397 | // TODO (Hexagon12): Properly implement reading gyroscope values from controllers. |
| 384 | rb.Push(true); | 398 | rb.Push(true); |
| 385 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 386 | } | 399 | } |
| 387 | 400 | ||
| 388 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | 401 | void SetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { |
| 389 | IPC::RequestParser rp{ctx}; | 402 | IPC::RequestParser rp{ctx}; |
| 390 | auto supported_styleset = rp.PopRaw<u32>(); | 403 | auto supported_styleset = rp.PopRaw<u32>(); |
| 404 | LOG_DEBUG(Service_HID, "called with supported_styleset={}", supported_styleset); | ||
| 405 | |||
| 391 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 406 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 392 | .SetSupportedStyleSet({supported_styleset}); | 407 | .SetSupportedStyleSet({supported_styleset}); |
| 393 | 408 | ||
| 394 | IPC::ResponseBuilder rb{ctx, 2}; | 409 | IPC::ResponseBuilder rb{ctx, 2}; |
| 395 | rb.Push(RESULT_SUCCESS); | 410 | rb.Push(RESULT_SUCCESS); |
| 396 | |||
| 397 | LOG_DEBUG(Service_HID, "called"); | ||
| 398 | } | 411 | } |
| 399 | 412 | ||
| 400 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { | 413 | void GetSupportedNpadStyleSet(Kernel::HLERequestContext& ctx) { |
| 414 | LOG_DEBUG(Service_HID, "called"); | ||
| 415 | |||
| 401 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | 416 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); |
| 402 | 417 | ||
| 403 | IPC::ResponseBuilder rb{ctx, 3}; | 418 | IPC::ResponseBuilder rb{ctx, 3}; |
| 404 | rb.Push(RESULT_SUCCESS); | 419 | rb.Push(RESULT_SUCCESS); |
| 405 | rb.Push<u32>(controller.GetSupportedStyleSet().raw); | 420 | rb.Push<u32>(controller.GetSupportedStyleSet().raw); |
| 406 | LOG_DEBUG(Service_HID, "called"); | ||
| 407 | } | 421 | } |
| 408 | 422 | ||
| 409 | void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { | 423 | void SetSupportedNpadIdType(Kernel::HLERequestContext& ctx) { |
| 424 | LOG_DEBUG(Service_HID, "called"); | ||
| 425 | |||
| 410 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 426 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 411 | .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); | 427 | .SetSupportedNPadIdTypes(ctx.ReadBuffer().data(), ctx.GetReadBufferSize()); |
| 412 | IPC::ResponseBuilder rb{ctx, 2}; | 428 | IPC::ResponseBuilder rb{ctx, 2}; |
| 413 | rb.Push(RESULT_SUCCESS); | 429 | rb.Push(RESULT_SUCCESS); |
| 414 | LOG_DEBUG(Service_HID, "called"); | ||
| 415 | } | 430 | } |
| 416 | 431 | ||
| 417 | void ActivateNpad(Kernel::HLERequestContext& ctx) { | 432 | void ActivateNpad(Kernel::HLERequestContext& ctx) { |
| 433 | LOG_DEBUG(Service_HID, "called"); | ||
| 434 | |||
| 418 | IPC::ResponseBuilder rb{ctx, 2}; | 435 | IPC::ResponseBuilder rb{ctx, 2}; |
| 419 | rb.Push(RESULT_SUCCESS); | 436 | rb.Push(RESULT_SUCCESS); |
| 420 | applet_resource->ActivateController(HidController::NPad); | 437 | applet_resource->ActivateController(HidController::NPad); |
| 421 | LOG_DEBUG(Service_HID, "called"); | ||
| 422 | } | 438 | } |
| 423 | 439 | ||
| 424 | void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { | 440 | void AcquireNpadStyleSetUpdateEventHandle(Kernel::HLERequestContext& ctx) { |
| 425 | IPC::RequestParser rp{ctx}; | 441 | IPC::RequestParser rp{ctx}; |
| 426 | auto npad_id = rp.PopRaw<u32>(); | 442 | auto npad_id = rp.PopRaw<u32>(); |
| 443 | LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); | ||
| 444 | |||
| 427 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 445 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 428 | rb.Push(RESULT_SUCCESS); | 446 | rb.Push(RESULT_SUCCESS); |
| 429 | rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 447 | rb.PushCopyObjects(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 430 | .GetStyleSetChangedEvent()); | 448 | .GetStyleSetChangedEvent()); |
| 431 | LOG_DEBUG(Service_HID, "called"); | ||
| 432 | } | 449 | } |
| 433 | 450 | ||
| 434 | void DisconnectNpad(Kernel::HLERequestContext& ctx) { | 451 | void DisconnectNpad(Kernel::HLERequestContext& ctx) { |
| 435 | IPC::RequestParser rp{ctx}; | 452 | IPC::RequestParser rp{ctx}; |
| 436 | auto npad_id = rp.PopRaw<u32>(); | 453 | auto npad_id = rp.PopRaw<u32>(); |
| 454 | LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); | ||
| 455 | |||
| 437 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 456 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 438 | .DisconnectNPad(npad_id); | 457 | .DisconnectNPad(npad_id); |
| 439 | IPC::ResponseBuilder rb{ctx, 2}; | 458 | IPC::ResponseBuilder rb{ctx, 2}; |
| 440 | rb.Push(RESULT_SUCCESS); | 459 | rb.Push(RESULT_SUCCESS); |
| 441 | LOG_DEBUG(Service_HID, "called"); | ||
| 442 | } | 460 | } |
| 443 | 461 | ||
| 444 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { | 462 | void GetPlayerLedPattern(Kernel::HLERequestContext& ctx) { |
| 445 | IPC::RequestParser rp{ctx}; | 463 | IPC::RequestParser rp{ctx}; |
| 446 | auto npad_id = rp.PopRaw<u32>(); | 464 | auto npad_id = rp.PopRaw<u32>(); |
| 465 | LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); | ||
| 466 | |||
| 447 | IPC::ResponseBuilder rb{ctx, 4}; | 467 | IPC::ResponseBuilder rb{ctx, 4}; |
| 448 | rb.Push(RESULT_SUCCESS); | 468 | rb.Push(RESULT_SUCCESS); |
| 449 | rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) | 469 | rb.PushRaw<u64>(applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 450 | .GetLedPattern(npad_id) | 470 | .GetLedPattern(npad_id) |
| 451 | .raw); | 471 | .raw); |
| 452 | LOG_DEBUG(Service_HID, "called"); | ||
| 453 | } | 472 | } |
| 454 | 473 | ||
| 455 | void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | 474 | void SetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { |
| 456 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 457 | IPC::RequestParser rp{ctx}; | 475 | IPC::RequestParser rp{ctx}; |
| 458 | const auto hold_type = rp.PopRaw<u64>(); | 476 | const auto hold_type = rp.PopRaw<u64>(); |
| 477 | LOG_DEBUG(Service_HID, "called with hold_type={}", hold_type); | ||
| 478 | |||
| 479 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | ||
| 459 | controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); | 480 | controller.SetHoldType(Controller_NPad::NpadHoldType{hold_type}); |
| 460 | 481 | ||
| 461 | IPC::ResponseBuilder rb{ctx, 2}; | 482 | IPC::ResponseBuilder rb{ctx, 2}; |
| 462 | rb.Push(RESULT_SUCCESS); | 483 | rb.Push(RESULT_SUCCESS); |
| 463 | LOG_DEBUG(Service_HID, "called"); | ||
| 464 | } | 484 | } |
| 465 | 485 | ||
| 466 | void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { | 486 | void GetNpadJoyHoldType(Kernel::HLERequestContext& ctx) { |
| 487 | LOG_DEBUG(Service_HID, "called"); | ||
| 488 | |||
| 467 | const auto& controller = | 489 | const auto& controller = |
| 468 | applet_resource->GetController<Controller_NPad>(HidController::NPad); | 490 | applet_resource->GetController<Controller_NPad>(HidController::NPad); |
| 469 | IPC::ResponseBuilder rb{ctx, 4}; | 491 | IPC::ResponseBuilder rb{ctx, 4}; |
| 470 | rb.Push(RESULT_SUCCESS); | 492 | rb.Push(RESULT_SUCCESS); |
| 471 | rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); | 493 | rb.Push<u64>(static_cast<u64>(controller.GetHoldType())); |
| 472 | LOG_DEBUG(Service_HID, "called"); | ||
| 473 | } | 494 | } |
| 474 | 495 | ||
| 475 | void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { | 496 | void SetNpadJoyAssignmentModeSingleByDefault(Kernel::HLERequestContext& ctx) { |
| 476 | IPC::RequestParser rp{ctx}; | 497 | IPC::RequestParser rp{ctx}; |
| 477 | auto npad_id = rp.PopRaw<u32>(); | 498 | auto npad_id = rp.PopRaw<u32>(); |
| 499 | LOG_WARNING(Service_HID, "(STUBBED) called with npad_id={}", npad_id); | ||
| 500 | |||
| 478 | IPC::ResponseBuilder rb{ctx, 2}; | 501 | IPC::ResponseBuilder rb{ctx, 2}; |
| 479 | rb.Push(RESULT_SUCCESS); | 502 | rb.Push(RESULT_SUCCESS); |
| 480 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 481 | } | 503 | } |
| 482 | 504 | ||
| 483 | void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { | 505 | void BeginPermitVibrationSession(Kernel::HLERequestContext& ctx) { |
| 506 | LOG_DEBUG(Service_HID, "called"); | ||
| 507 | |||
| 484 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 508 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 485 | .SetVibrationEnabled(true); | 509 | .SetVibrationEnabled(true); |
| 486 | IPC::ResponseBuilder rb{ctx, 2}; | 510 | IPC::ResponseBuilder rb{ctx, 2}; |
| 487 | rb.Push(RESULT_SUCCESS); | 511 | rb.Push(RESULT_SUCCESS); |
| 488 | LOG_DEBUG(Service_HID, "called"); | ||
| 489 | } | 512 | } |
| 490 | 513 | ||
| 491 | void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { | 514 | void EndPermitVibrationSession(Kernel::HLERequestContext& ctx) { |
| 515 | LOG_DEBUG(Service_HID, "called"); | ||
| 516 | |||
| 492 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 517 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 493 | .SetVibrationEnabled(false); | 518 | .SetVibrationEnabled(false); |
| 494 | IPC::ResponseBuilder rb{ctx, 2}; | 519 | IPC::ResponseBuilder rb{ctx, 2}; |
| 495 | rb.Push(RESULT_SUCCESS); | 520 | rb.Push(RESULT_SUCCESS); |
| 496 | LOG_DEBUG(Service_HID, "called"); | ||
| 497 | } | 521 | } |
| 498 | 522 | ||
| 499 | void SendVibrationValue(Kernel::HLERequestContext& ctx) { | 523 | void SendVibrationValue(Kernel::HLERequestContext& ctx) { |
| 500 | IPC::RequestParser rp{ctx}; | 524 | IPC::RequestParser rp{ctx}; |
| 501 | const auto controller_id = rp.PopRaw<u32>(); | 525 | const auto controller_id = rp.PopRaw<u32>(); |
| 502 | const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>(); | 526 | const auto vibration_values = rp.PopRaw<Controller_NPad::Vibration>(); |
| 527 | LOG_DEBUG(Service_HID, "called with controller_id={}", controller_id); | ||
| 503 | 528 | ||
| 504 | IPC::ResponseBuilder rb{ctx, 2}; | 529 | IPC::ResponseBuilder rb{ctx, 2}; |
| 505 | rb.Push(RESULT_SUCCESS); | 530 | rb.Push(RESULT_SUCCESS); |
| 506 | 531 | ||
| 507 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 532 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 508 | .VibrateController({controller_id}, {vibration_values}); | 533 | .VibrateController({controller_id}, {vibration_values}); |
| 509 | LOG_DEBUG(Service_HID, "called"); | ||
| 510 | } | 534 | } |
| 511 | 535 | ||
| 512 | void SendVibrationValues(Kernel::HLERequestContext& ctx) { | 536 | void SendVibrationValues(Kernel::HLERequestContext& ctx) { |
| 537 | LOG_DEBUG(Service_HID, "called"); | ||
| 538 | |||
| 513 | const auto controllers = ctx.ReadBuffer(0); | 539 | const auto controllers = ctx.ReadBuffer(0); |
| 514 | const auto vibrations = ctx.ReadBuffer(1); | 540 | const auto vibrations = ctx.ReadBuffer(1); |
| 515 | 541 | ||
| @@ -527,86 +553,96 @@ private: | |||
| 527 | 553 | ||
| 528 | IPC::ResponseBuilder rb{ctx, 2}; | 554 | IPC::ResponseBuilder rb{ctx, 2}; |
| 529 | rb.Push(RESULT_SUCCESS); | 555 | rb.Push(RESULT_SUCCESS); |
| 530 | LOG_DEBUG(Service_HID, "called"); | ||
| 531 | } | 556 | } |
| 532 | 557 | ||
| 533 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { | 558 | void GetActualVibrationValue(Kernel::HLERequestContext& ctx) { |
| 559 | LOG_DEBUG(Service_HID, "called"); | ||
| 560 | |||
| 534 | IPC::ResponseBuilder rb{ctx, 6}; | 561 | IPC::ResponseBuilder rb{ctx, 6}; |
| 535 | rb.Push(RESULT_SUCCESS); | 562 | rb.Push(RESULT_SUCCESS); |
| 536 | rb.PushRaw<Controller_NPad::Vibration>( | 563 | rb.PushRaw<Controller_NPad::Vibration>( |
| 537 | applet_resource->GetController<Controller_NPad>(HidController::NPad) | 564 | applet_resource->GetController<Controller_NPad>(HidController::NPad) |
| 538 | .GetLastVibration()); | 565 | .GetLastVibration()); |
| 539 | LOG_DEBUG(Service_HID, "called"); | ||
| 540 | } | 566 | } |
| 541 | 567 | ||
| 542 | void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { | 568 | void SetNpadJoyAssignmentModeDual(Kernel::HLERequestContext& ctx) { |
| 543 | IPC::RequestParser rp{ctx}; | 569 | IPC::RequestParser rp{ctx}; |
| 544 | const auto npad_id = rp.PopRaw<u32>(); | 570 | const auto npad_id = rp.PopRaw<u32>(); |
| 571 | LOG_DEBUG(Service_HID, "called with npad_id={}", npad_id); | ||
| 572 | |||
| 545 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); | 573 | auto& controller = applet_resource->GetController<Controller_NPad>(HidController::NPad); |
| 546 | controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); | 574 | controller.SetNpadMode(npad_id, Controller_NPad::NPadAssignments::Dual); |
| 547 | 575 | ||
| 548 | IPC::ResponseBuilder rb{ctx, 2}; | 576 | IPC::ResponseBuilder rb{ctx, 2}; |
| 549 | rb.Push(RESULT_SUCCESS); | 577 | rb.Push(RESULT_SUCCESS); |
| 550 | LOG_DEBUG(Service_HID, "called"); | ||
| 551 | } | 578 | } |
| 552 | 579 | ||
| 553 | void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { | 580 | void MergeSingleJoyAsDualJoy(Kernel::HLERequestContext& ctx) { |
| 581 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 582 | |||
| 554 | IPC::ResponseBuilder rb{ctx, 2}; | 583 | IPC::ResponseBuilder rb{ctx, 2}; |
| 555 | rb.Push(RESULT_SUCCESS); | 584 | rb.Push(RESULT_SUCCESS); |
| 556 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 557 | } | 585 | } |
| 558 | 586 | ||
| 559 | void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { | 587 | void SetNpadHandheldActivationMode(Kernel::HLERequestContext& ctx) { |
| 560 | IPC::RequestParser rp{ctx}; | 588 | IPC::RequestParser rp{ctx}; |
| 561 | auto mode = rp.PopRaw<u32>(); | 589 | auto mode = rp.PopRaw<u32>(); |
| 590 | LOG_WARNING(Service_HID, "(STUBBED) called with mode={}", mode); | ||
| 591 | |||
| 562 | IPC::ResponseBuilder rb{ctx, 2}; | 592 | IPC::ResponseBuilder rb{ctx, 2}; |
| 563 | rb.Push(RESULT_SUCCESS); | 593 | rb.Push(RESULT_SUCCESS); |
| 564 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 565 | } | 594 | } |
| 566 | 595 | ||
| 567 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { | 596 | void GetVibrationDeviceInfo(Kernel::HLERequestContext& ctx) { |
| 597 | LOG_DEBUG(Service_HID, "called"); | ||
| 598 | |||
| 568 | IPC::ResponseBuilder rb{ctx, 4}; | 599 | IPC::ResponseBuilder rb{ctx, 4}; |
| 569 | rb.Push(RESULT_SUCCESS); | 600 | rb.Push(RESULT_SUCCESS); |
| 570 | rb.Push<u32>(1); | 601 | rb.Push<u32>(1); |
| 571 | rb.Push<u32>(0); | 602 | rb.Push<u32>(0); |
| 572 | LOG_DEBUG(Service_HID, "called"); | ||
| 573 | } | 603 | } |
| 574 | 604 | ||
| 575 | void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { | 605 | void CreateActiveVibrationDeviceList(Kernel::HLERequestContext& ctx) { |
| 606 | LOG_DEBUG(Service_HID, "called"); | ||
| 607 | |||
| 576 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 608 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 577 | rb.Push(RESULT_SUCCESS); | 609 | rb.Push(RESULT_SUCCESS); |
| 578 | rb.PushIpcInterface<IActiveVibrationDeviceList>(); | 610 | rb.PushIpcInterface<IActiveVibrationDeviceList>(); |
| 579 | LOG_DEBUG(Service_HID, "called"); | ||
| 580 | } | 611 | } |
| 581 | 612 | ||
| 582 | void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | 613 | void ActivateConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 614 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 615 | |||
| 583 | IPC::ResponseBuilder rb{ctx, 2}; | 616 | IPC::ResponseBuilder rb{ctx, 2}; |
| 584 | rb.Push(RESULT_SUCCESS); | 617 | rb.Push(RESULT_SUCCESS); |
| 585 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 586 | } | 618 | } |
| 587 | 619 | ||
| 588 | void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { | 620 | void StartConsoleSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 621 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 622 | |||
| 589 | IPC::ResponseBuilder rb{ctx, 2}; | 623 | IPC::ResponseBuilder rb{ctx, 2}; |
| 590 | rb.Push(RESULT_SUCCESS); | 624 | rb.Push(RESULT_SUCCESS); |
| 591 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 592 | } | 625 | } |
| 593 | 626 | ||
| 594 | void StopSixAxisSensor(Kernel::HLERequestContext& ctx) { | 627 | void StopSixAxisSensor(Kernel::HLERequestContext& ctx) { |
| 628 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 629 | |||
| 595 | IPC::ResponseBuilder rb{ctx, 2}; | 630 | IPC::ResponseBuilder rb{ctx, 2}; |
| 596 | rb.Push(RESULT_SUCCESS); | 631 | rb.Push(RESULT_SUCCESS); |
| 597 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 598 | } | 632 | } |
| 599 | 633 | ||
| 600 | void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) { | 634 | void SetIsPalmaAllConnectable(Kernel::HLERequestContext& ctx) { |
| 635 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 636 | |||
| 601 | IPC::ResponseBuilder rb{ctx, 2}; | 637 | IPC::ResponseBuilder rb{ctx, 2}; |
| 602 | rb.Push(RESULT_SUCCESS); | 638 | rb.Push(RESULT_SUCCESS); |
| 603 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 604 | } | 639 | } |
| 605 | 640 | ||
| 606 | void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { | 641 | void SetPalmaBoostMode(Kernel::HLERequestContext& ctx) { |
| 642 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 643 | |||
| 607 | IPC::ResponseBuilder rb{ctx, 2}; | 644 | IPC::ResponseBuilder rb{ctx, 2}; |
| 608 | rb.Push(RESULT_SUCCESS); | 645 | rb.Push(RESULT_SUCCESS); |
| 609 | LOG_WARNING(Service_HID, "(STUBBED) called"); | ||
| 610 | } | 646 | } |
| 611 | }; | 647 | }; |
| 612 | 648 | ||
diff --git a/src/core/hle/service/hid/irs.cpp b/src/core/hle/service/hid/irs.cpp index 872e3c344..3c7f8b1ee 100644 --- a/src/core/hle/service/hid/irs.cpp +++ b/src/core/hle/service/hid/irs.cpp | |||
| @@ -44,115 +44,133 @@ IRS::IRS() : ServiceFramework{"irs"} { | |||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { | 46 | void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { |
| 47 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 48 | |||
| 47 | IPC::ResponseBuilder rb{ctx, 2}; | 49 | IPC::ResponseBuilder rb{ctx, 2}; |
| 48 | rb.Push(RESULT_SUCCESS); | 50 | rb.Push(RESULT_SUCCESS); |
| 49 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { | 53 | void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { |
| 54 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 55 | |||
| 53 | IPC::ResponseBuilder rb{ctx, 2}; | 56 | IPC::ResponseBuilder rb{ctx, 2}; |
| 54 | rb.Push(RESULT_SUCCESS); | 57 | rb.Push(RESULT_SUCCESS); |
| 55 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 56 | } | 58 | } |
| 57 | 59 | ||
| 58 | void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { | 60 | void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { |
| 61 | LOG_DEBUG(Service_IRS, "called"); | ||
| 62 | |||
| 59 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 63 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 60 | rb.Push(RESULT_SUCCESS); | 64 | rb.Push(RESULT_SUCCESS); |
| 61 | rb.PushCopyObjects(shared_mem); | 65 | rb.PushCopyObjects(shared_mem); |
| 62 | LOG_DEBUG(Service_IRS, "called"); | ||
| 63 | } | 66 | } |
| 64 | 67 | ||
| 65 | void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { | 68 | void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { |
| 69 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 70 | |||
| 66 | IPC::ResponseBuilder rb{ctx, 2}; | 71 | IPC::ResponseBuilder rb{ctx, 2}; |
| 67 | rb.Push(RESULT_SUCCESS); | 72 | rb.Push(RESULT_SUCCESS); |
| 68 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 69 | } | 73 | } |
| 70 | 74 | ||
| 71 | void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { | 75 | void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { |
| 76 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 77 | |||
| 72 | IPC::ResponseBuilder rb{ctx, 2}; | 78 | IPC::ResponseBuilder rb{ctx, 2}; |
| 73 | rb.Push(RESULT_SUCCESS); | 79 | rb.Push(RESULT_SUCCESS); |
| 74 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 75 | } | 80 | } |
| 76 | 81 | ||
| 77 | void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { | 82 | void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { |
| 83 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 84 | |||
| 78 | IPC::ResponseBuilder rb{ctx, 2}; | 85 | IPC::ResponseBuilder rb{ctx, 2}; |
| 79 | rb.Push(RESULT_SUCCESS); | 86 | rb.Push(RESULT_SUCCESS); |
| 80 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 81 | } | 87 | } |
| 82 | 88 | ||
| 83 | void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { | 89 | void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { |
| 90 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 91 | |||
| 84 | IPC::ResponseBuilder rb{ctx, 2}; | 92 | IPC::ResponseBuilder rb{ctx, 2}; |
| 85 | rb.Push(RESULT_SUCCESS); | 93 | rb.Push(RESULT_SUCCESS); |
| 86 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 87 | } | 94 | } |
| 88 | 95 | ||
| 89 | void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { | 96 | void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { |
| 97 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 98 | |||
| 90 | IPC::ResponseBuilder rb{ctx, 5}; | 99 | IPC::ResponseBuilder rb{ctx, 5}; |
| 91 | rb.Push(RESULT_SUCCESS); | 100 | rb.Push(RESULT_SUCCESS); |
| 92 | rb.PushRaw<u64>(CoreTiming::GetTicks()); | 101 | rb.PushRaw<u64>(CoreTiming::GetTicks()); |
| 93 | rb.PushRaw<u32>(0); | 102 | rb.PushRaw<u32>(0); |
| 94 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 95 | } | 103 | } |
| 96 | 104 | ||
| 97 | void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { | 105 | void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { |
| 106 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 107 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2}; | 108 | IPC::ResponseBuilder rb{ctx, 2}; |
| 99 | rb.Push(RESULT_SUCCESS); | 109 | rb.Push(RESULT_SUCCESS); |
| 100 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 101 | } | 110 | } |
| 102 | 111 | ||
| 103 | void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { | 112 | void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { |
| 113 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 114 | |||
| 104 | IPC::ResponseBuilder rb{ctx, 3}; | 115 | IPC::ResponseBuilder rb{ctx, 3}; |
| 105 | rb.Push(RESULT_SUCCESS); | 116 | rb.Push(RESULT_SUCCESS); |
| 106 | rb.PushRaw<u32>(device_handle); | 117 | rb.PushRaw<u32>(device_handle); |
| 107 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 108 | } | 118 | } |
| 109 | 119 | ||
| 110 | void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { | 120 | void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { |
| 121 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 122 | |||
| 111 | IPC::ResponseBuilder rb{ctx, 2}; | 123 | IPC::ResponseBuilder rb{ctx, 2}; |
| 112 | rb.Push(RESULT_SUCCESS); | 124 | rb.Push(RESULT_SUCCESS); |
| 113 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 114 | } | 125 | } |
| 115 | 126 | ||
| 116 | void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { | 127 | void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { |
| 128 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 129 | |||
| 117 | IPC::ResponseBuilder rb{ctx, 2}; | 130 | IPC::ResponseBuilder rb{ctx, 2}; |
| 118 | rb.Push(RESULT_SUCCESS); | 131 | rb.Push(RESULT_SUCCESS); |
| 119 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 120 | } | 132 | } |
| 121 | 133 | ||
| 122 | void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { | 134 | void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { |
| 135 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 136 | |||
| 123 | IPC::ResponseBuilder rb{ctx, 2}; | 137 | IPC::ResponseBuilder rb{ctx, 2}; |
| 124 | rb.Push(RESULT_SUCCESS); | 138 | rb.Push(RESULT_SUCCESS); |
| 125 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 126 | } | 139 | } |
| 127 | 140 | ||
| 128 | void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { | 141 | void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { |
| 142 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 143 | |||
| 129 | IPC::ResponseBuilder rb{ctx, 2}; | 144 | IPC::ResponseBuilder rb{ctx, 2}; |
| 130 | rb.Push(RESULT_SUCCESS); | 145 | rb.Push(RESULT_SUCCESS); |
| 131 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 132 | } | 146 | } |
| 133 | 147 | ||
| 134 | void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { | 148 | void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { |
| 149 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 150 | |||
| 135 | IPC::ResponseBuilder rb{ctx, 2}; | 151 | IPC::ResponseBuilder rb{ctx, 2}; |
| 136 | rb.Push(RESULT_SUCCESS); | 152 | rb.Push(RESULT_SUCCESS); |
| 137 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 138 | } | 153 | } |
| 139 | 154 | ||
| 140 | void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { | 155 | void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { |
| 156 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 157 | |||
| 141 | IPC::ResponseBuilder rb{ctx, 2}; | 158 | IPC::ResponseBuilder rb{ctx, 2}; |
| 142 | rb.Push(RESULT_SUCCESS); | 159 | rb.Push(RESULT_SUCCESS); |
| 143 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 144 | } | 160 | } |
| 145 | 161 | ||
| 146 | void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { | 162 | void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { |
| 163 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 164 | |||
| 147 | IPC::ResponseBuilder rb{ctx, 2}; | 165 | IPC::ResponseBuilder rb{ctx, 2}; |
| 148 | rb.Push(RESULT_SUCCESS); | 166 | rb.Push(RESULT_SUCCESS); |
| 149 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 150 | } | 167 | } |
| 151 | 168 | ||
| 152 | void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { | 169 | void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { |
| 170 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 171 | |||
| 153 | IPC::ResponseBuilder rb{ctx, 2}; | 172 | IPC::ResponseBuilder rb{ctx, 2}; |
| 154 | rb.Push(RESULT_SUCCESS); | 173 | rb.Push(RESULT_SUCCESS); |
| 155 | LOG_WARNING(Service_IRS, "(STUBBED) called"); | ||
| 156 | } | 174 | } |
| 157 | 175 | ||
| 158 | IRS::~IRS() = default; | 176 | IRS::~IRS() = default; |
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp index 164c57e18..e8f9f2d29 100644 --- a/src/core/hle/service/lbl/lbl.cpp +++ b/src/core/hle/service/lbl/lbl.cpp | |||
| @@ -55,29 +55,29 @@ public: | |||
| 55 | 55 | ||
| 56 | private: | 56 | private: |
| 57 | void EnableVrMode(Kernel::HLERequestContext& ctx) { | 57 | void EnableVrMode(Kernel::HLERequestContext& ctx) { |
| 58 | LOG_DEBUG(Service_LBL, "called"); | ||
| 59 | |||
| 58 | IPC::ResponseBuilder rb{ctx, 2}; | 60 | IPC::ResponseBuilder rb{ctx, 2}; |
| 59 | rb.Push(RESULT_SUCCESS); | 61 | rb.Push(RESULT_SUCCESS); |
| 60 | 62 | ||
| 61 | vr_mode_enabled = true; | 63 | vr_mode_enabled = true; |
| 62 | |||
| 63 | LOG_DEBUG(Service_LBL, "called"); | ||
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | void DisableVrMode(Kernel::HLERequestContext& ctx) { | 66 | void DisableVrMode(Kernel::HLERequestContext& ctx) { |
| 67 | LOG_DEBUG(Service_LBL, "called"); | ||
| 68 | |||
| 67 | IPC::ResponseBuilder rb{ctx, 2}; | 69 | IPC::ResponseBuilder rb{ctx, 2}; |
| 68 | rb.Push(RESULT_SUCCESS); | 70 | rb.Push(RESULT_SUCCESS); |
| 69 | 71 | ||
| 70 | vr_mode_enabled = false; | 72 | vr_mode_enabled = false; |
| 71 | |||
| 72 | LOG_DEBUG(Service_LBL, "called"); | ||
| 73 | } | 73 | } |
| 74 | 74 | ||
| 75 | void IsVrModeEnabled(Kernel::HLERequestContext& ctx) { | 75 | void IsVrModeEnabled(Kernel::HLERequestContext& ctx) { |
| 76 | LOG_DEBUG(Service_LBL, "called"); | ||
| 77 | |||
| 76 | IPC::ResponseBuilder rb{ctx, 3}; | 78 | IPC::ResponseBuilder rb{ctx, 3}; |
| 77 | rb.Push(RESULT_SUCCESS); | 79 | rb.Push(RESULT_SUCCESS); |
| 78 | rb.Push(vr_mode_enabled); | 80 | rb.Push(vr_mode_enabled); |
| 79 | |||
| 80 | LOG_DEBUG(Service_LBL, "called"); | ||
| 81 | } | 81 | } |
| 82 | 82 | ||
| 83 | bool vr_mode_enabled = false; | 83 | bool vr_mode_enabled = false; |
diff --git a/src/core/hle/service/ldn/ldn.cpp b/src/core/hle/service/ldn/ldn.cpp index 167f2c66a..e250595e3 100644 --- a/src/core/hle/service/ldn/ldn.cpp +++ b/src/core/hle/service/ldn/ldn.cpp | |||
| @@ -44,11 +44,11 @@ public: | |||
| 44 | } | 44 | } |
| 45 | 45 | ||
| 46 | void CreateMonitorService(Kernel::HLERequestContext& ctx) { | 46 | void CreateMonitorService(Kernel::HLERequestContext& ctx) { |
| 47 | LOG_DEBUG(Service_LDN, "called"); | ||
| 48 | |||
| 47 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 49 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 48 | rb.Push(RESULT_SUCCESS); | 50 | rb.Push(RESULT_SUCCESS); |
| 49 | rb.PushIpcInterface<IMonitorService>(); | 51 | rb.PushIpcInterface<IMonitorService>(); |
| 50 | |||
| 51 | LOG_DEBUG(Service_LDN, "called"); | ||
| 52 | } | 52 | } |
| 53 | }; | 53 | }; |
| 54 | 54 | ||
| @@ -104,11 +104,11 @@ public: | |||
| 104 | } | 104 | } |
| 105 | 105 | ||
| 106 | void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) { | 106 | void CreateSystemLocalCommunicationService(Kernel::HLERequestContext& ctx) { |
| 107 | LOG_DEBUG(Service_LDN, "called"); | ||
| 108 | |||
| 107 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 109 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 108 | rb.Push(RESULT_SUCCESS); | 110 | rb.Push(RESULT_SUCCESS); |
| 109 | rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService"); | 111 | rb.PushIpcInterface<ILocalCommunicationService>("ISystemLocalCommunicationService"); |
| 110 | |||
| 111 | LOG_DEBUG(Service_LDN, "called"); | ||
| 112 | } | 112 | } |
| 113 | }; | 113 | }; |
| 114 | 114 | ||
| @@ -125,11 +125,11 @@ public: | |||
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) { | 127 | void CreateUserLocalCommunicationService(Kernel::HLERequestContext& ctx) { |
| 128 | LOG_DEBUG(Service_LDN, "called"); | ||
| 129 | |||
| 128 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 130 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 129 | rb.Push(RESULT_SUCCESS); | 131 | rb.Push(RESULT_SUCCESS); |
| 130 | rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService"); | 132 | rb.PushIpcInterface<ILocalCommunicationService>("IUserLocalCommunicationService"); |
| 131 | |||
| 132 | LOG_DEBUG(Service_LDN, "called"); | ||
| 133 | } | 133 | } |
| 134 | }; | 134 | }; |
| 135 | 135 | ||
diff --git a/src/core/hle/service/ldr/ldr.cpp b/src/core/hle/service/ldr/ldr.cpp index 7a9d0d0dd..ca119dd3a 100644 --- a/src/core/hle/service/ldr/ldr.cpp +++ b/src/core/hle/service/ldr/ldr.cpp | |||
| @@ -97,6 +97,8 @@ public: | |||
| 97 | rp.Skip(2, false); | 97 | rp.Skip(2, false); |
| 98 | const VAddr nrr_addr{rp.Pop<VAddr>()}; | 98 | const VAddr nrr_addr{rp.Pop<VAddr>()}; |
| 99 | const u64 nrr_size{rp.Pop<u64>()}; | 99 | const u64 nrr_size{rp.Pop<u64>()}; |
| 100 | LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}, nrr_size={:016X}", nrr_addr, | ||
| 101 | nrr_size); | ||
| 100 | 102 | ||
| 101 | if (!initialized) { | 103 | if (!initialized) { |
| 102 | LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); | 104 | LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); |
| @@ -189,6 +191,7 @@ public: | |||
| 189 | IPC::RequestParser rp{ctx}; | 191 | IPC::RequestParser rp{ctx}; |
| 190 | rp.Skip(2, false); | 192 | rp.Skip(2, false); |
| 191 | const auto nrr_addr{rp.Pop<VAddr>()}; | 193 | const auto nrr_addr{rp.Pop<VAddr>()}; |
| 194 | LOG_DEBUG(Service_LDR, "called with nrr_addr={:016X}", nrr_addr); | ||
| 192 | 195 | ||
| 193 | if (!Common::Is4KBAligned(nrr_addr)) { | 196 | if (!Common::Is4KBAligned(nrr_addr)) { |
| 194 | LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr); | 197 | LOG_ERROR(Service_LDR, "NRR Address has invalid alignment (actual {:016X})!", nrr_addr); |
| @@ -219,6 +222,10 @@ public: | |||
| 219 | const u64 nro_size{rp.Pop<u64>()}; | 222 | const u64 nro_size{rp.Pop<u64>()}; |
| 220 | const VAddr bss_addr{rp.Pop<VAddr>()}; | 223 | const VAddr bss_addr{rp.Pop<VAddr>()}; |
| 221 | const u64 bss_size{rp.Pop<u64>()}; | 224 | const u64 bss_size{rp.Pop<u64>()}; |
| 225 | LOG_DEBUG( | ||
| 226 | Service_LDR, | ||
| 227 | "called with nro_addr={:016X}, nro_size={:016X}, bss_addr={:016X}, bss_size={:016X}", | ||
| 228 | nro_addr, nro_size, bss_addr, bss_size); | ||
| 222 | 229 | ||
| 223 | if (!initialized) { | 230 | if (!initialized) { |
| 224 | LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); | 231 | LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); |
| @@ -345,6 +352,8 @@ public: | |||
| 345 | rp.Skip(2, false); | 352 | rp.Skip(2, false); |
| 346 | const VAddr mapped_addr{rp.PopRaw<VAddr>()}; | 353 | const VAddr mapped_addr{rp.PopRaw<VAddr>()}; |
| 347 | const VAddr heap_addr{rp.PopRaw<VAddr>()}; | 354 | const VAddr heap_addr{rp.PopRaw<VAddr>()}; |
| 355 | LOG_DEBUG(Service_LDR, "called with mapped_addr={:016X}, heap_addr={:016X}", mapped_addr, | ||
| 356 | heap_addr); | ||
| 348 | 357 | ||
| 349 | if (!initialized) { | 358 | if (!initialized) { |
| 350 | LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); | 359 | LOG_ERROR(Service_LDR, "LDR:RO not initialized before use!"); |
| @@ -393,11 +402,12 @@ public: | |||
| 393 | } | 402 | } |
| 394 | 403 | ||
| 395 | void Initialize(Kernel::HLERequestContext& ctx) { | 404 | void Initialize(Kernel::HLERequestContext& ctx) { |
| 405 | LOG_WARNING(Service_LDR, "(STUBBED) called"); | ||
| 406 | |||
| 396 | initialized = true; | 407 | initialized = true; |
| 397 | 408 | ||
| 398 | IPC::ResponseBuilder rb{ctx, 2}; | 409 | IPC::ResponseBuilder rb{ctx, 2}; |
| 399 | rb.Push(RESULT_SUCCESS); | 410 | rb.Push(RESULT_SUCCESS); |
| 400 | LOG_WARNING(Service_LDR, "(STUBBED) called"); | ||
| 401 | } | 411 | } |
| 402 | 412 | ||
| 403 | private: | 413 | private: |
diff --git a/src/core/hle/service/lm/lm.cpp b/src/core/hle/service/lm/lm.cpp index 4e5fdb16e..1f462e087 100644 --- a/src/core/hle/service/lm/lm.cpp +++ b/src/core/hle/service/lm/lm.cpp | |||
| @@ -209,11 +209,11 @@ public: | |||
| 209 | * 0: ResultCode | 209 | * 0: ResultCode |
| 210 | */ | 210 | */ |
| 211 | void OpenLogger(Kernel::HLERequestContext& ctx) { | 211 | void OpenLogger(Kernel::HLERequestContext& ctx) { |
| 212 | LOG_DEBUG(Service_LM, "called"); | ||
| 213 | |||
| 212 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 214 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 213 | rb.Push(RESULT_SUCCESS); | 215 | rb.Push(RESULT_SUCCESS); |
| 214 | rb.PushIpcInterface<ILogger>(); | 216 | rb.PushIpcInterface<ILogger>(); |
| 215 | |||
| 216 | LOG_DEBUG(Service_LM, "called"); | ||
| 217 | } | 217 | } |
| 218 | }; | 218 | }; |
| 219 | 219 | ||
diff --git a/src/core/hle/service/mm/mm_u.cpp b/src/core/hle/service/mm/mm_u.cpp index e1f17a926..def63dc8a 100644 --- a/src/core/hle/service/mm/mm_u.cpp +++ b/src/core/hle/service/mm/mm_u.cpp | |||
| @@ -31,12 +31,14 @@ public: | |||
| 31 | private: | 31 | private: |
| 32 | void Initialize(Kernel::HLERequestContext& ctx) { | 32 | void Initialize(Kernel::HLERequestContext& ctx) { |
| 33 | LOG_WARNING(Service_MM, "(STUBBED) called"); | 33 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 34 | |||
| 34 | IPC::ResponseBuilder rb{ctx, 2}; | 35 | IPC::ResponseBuilder rb{ctx, 2}; |
| 35 | rb.Push(RESULT_SUCCESS); | 36 | rb.Push(RESULT_SUCCESS); |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | void Finalize(Kernel::HLERequestContext& ctx) { | 39 | void Finalize(Kernel::HLERequestContext& ctx) { |
| 39 | LOG_WARNING(Service_MM, "(STUBBED) called"); | 40 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 41 | |||
| 40 | IPC::ResponseBuilder rb{ctx, 2}; | 42 | IPC::ResponseBuilder rb{ctx, 2}; |
| 41 | rb.Push(RESULT_SUCCESS); | 43 | rb.Push(RESULT_SUCCESS); |
| 42 | } | 44 | } |
| @@ -45,15 +47,16 @@ private: | |||
| 45 | IPC::RequestParser rp{ctx}; | 47 | IPC::RequestParser rp{ctx}; |
| 46 | min = rp.Pop<u32>(); | 48 | min = rp.Pop<u32>(); |
| 47 | max = rp.Pop<u32>(); | 49 | max = rp.Pop<u32>(); |
| 48 | current = min; | ||
| 49 | |||
| 50 | LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); | 50 | LOG_WARNING(Service_MM, "(STUBBED) called, min=0x{:X}, max=0x{:X}", min, max); |
| 51 | |||
| 52 | current = min; | ||
| 51 | IPC::ResponseBuilder rb{ctx, 2}; | 53 | IPC::ResponseBuilder rb{ctx, 2}; |
| 52 | rb.Push(RESULT_SUCCESS); | 54 | rb.Push(RESULT_SUCCESS); |
| 53 | } | 55 | } |
| 54 | 56 | ||
| 55 | void Get(Kernel::HLERequestContext& ctx) { | 57 | void Get(Kernel::HLERequestContext& ctx) { |
| 56 | LOG_WARNING(Service_MM, "(STUBBED) called"); | 58 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 59 | |||
| 57 | IPC::ResponseBuilder rb{ctx, 3}; | 60 | IPC::ResponseBuilder rb{ctx, 3}; |
| 58 | rb.Push(RESULT_SUCCESS); | 61 | rb.Push(RESULT_SUCCESS); |
| 59 | rb.Push(current); | 62 | rb.Push(current); |
| @@ -61,6 +64,7 @@ private: | |||
| 61 | 64 | ||
| 62 | void InitializeWithId(Kernel::HLERequestContext& ctx) { | 65 | void InitializeWithId(Kernel::HLERequestContext& ctx) { |
| 63 | LOG_WARNING(Service_MM, "(STUBBED) called"); | 66 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 67 | |||
| 64 | IPC::ResponseBuilder rb{ctx, 3}; | 68 | IPC::ResponseBuilder rb{ctx, 3}; |
| 65 | rb.Push(RESULT_SUCCESS); | 69 | rb.Push(RESULT_SUCCESS); |
| 66 | rb.Push<u32>(id); // Any non zero value | 70 | rb.Push<u32>(id); // Any non zero value |
| @@ -68,6 +72,7 @@ private: | |||
| 68 | 72 | ||
| 69 | void FinalizeWithId(Kernel::HLERequestContext& ctx) { | 73 | void FinalizeWithId(Kernel::HLERequestContext& ctx) { |
| 70 | LOG_WARNING(Service_MM, "(STUBBED) called"); | 74 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 75 | |||
| 71 | IPC::ResponseBuilder rb{ctx, 2}; | 76 | IPC::ResponseBuilder rb{ctx, 2}; |
| 72 | rb.Push(RESULT_SUCCESS); | 77 | rb.Push(RESULT_SUCCESS); |
| 73 | } | 78 | } |
| @@ -77,16 +82,17 @@ private: | |||
| 77 | u32 input_id = rp.Pop<u32>(); | 82 | u32 input_id = rp.Pop<u32>(); |
| 78 | min = rp.Pop<u32>(); | 83 | min = rp.Pop<u32>(); |
| 79 | max = rp.Pop<u32>(); | 84 | max = rp.Pop<u32>(); |
| 80 | current = min; | ||
| 81 | |||
| 82 | LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", | 85 | LOG_WARNING(Service_MM, "(STUBBED) called, input_id=0x{:X}, min=0x{:X}, max=0x{:X}", |
| 83 | input_id, min, max); | 86 | input_id, min, max); |
| 87 | |||
| 88 | current = min; | ||
| 84 | IPC::ResponseBuilder rb{ctx, 2}; | 89 | IPC::ResponseBuilder rb{ctx, 2}; |
| 85 | rb.Push(RESULT_SUCCESS); | 90 | rb.Push(RESULT_SUCCESS); |
| 86 | } | 91 | } |
| 87 | 92 | ||
| 88 | void GetWithId(Kernel::HLERequestContext& ctx) { | 93 | void GetWithId(Kernel::HLERequestContext& ctx) { |
| 89 | LOG_WARNING(Service_MM, "(STUBBED) called"); | 94 | LOG_WARNING(Service_MM, "(STUBBED) called"); |
| 95 | |||
| 90 | IPC::ResponseBuilder rb{ctx, 3}; | 96 | IPC::ResponseBuilder rb{ctx, 3}; |
| 91 | rb.Push(RESULT_SUCCESS); | 97 | rb.Push(RESULT_SUCCESS); |
| 92 | rb.Push(current); | 98 | rb.Push(current); |
diff --git a/src/core/hle/service/nfc/nfc.cpp b/src/core/hle/service/nfc/nfc.cpp index 30e542542..5c62d42ba 100644 --- a/src/core/hle/service/nfc/nfc.cpp +++ b/src/core/hle/service/nfc/nfc.cpp | |||
| @@ -43,11 +43,11 @@ public: | |||
| 43 | 43 | ||
| 44 | private: | 44 | private: |
| 45 | void CreateAmInterface(Kernel::HLERequestContext& ctx) { | 45 | void CreateAmInterface(Kernel::HLERequestContext& ctx) { |
| 46 | LOG_DEBUG(Service_NFC, "called"); | ||
| 47 | |||
| 46 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 48 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 47 | rb.Push(RESULT_SUCCESS); | 49 | rb.Push(RESULT_SUCCESS); |
| 48 | rb.PushIpcInterface<IAm>(); | 50 | rb.PushIpcInterface<IAm>(); |
| 49 | |||
| 50 | LOG_DEBUG(Service_NFC, "called"); | ||
| 51 | } | 51 | } |
| 52 | }; | 52 | }; |
| 53 | 53 | ||
| @@ -91,11 +91,11 @@ public: | |||
| 91 | 91 | ||
| 92 | private: | 92 | private: |
| 93 | void CreateUserInterface(Kernel::HLERequestContext& ctx) { | 93 | void CreateUserInterface(Kernel::HLERequestContext& ctx) { |
| 94 | LOG_DEBUG(Service_NFC, "called"); | ||
| 95 | |||
| 94 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 96 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 95 | rb.Push(RESULT_SUCCESS); | 97 | rb.Push(RESULT_SUCCESS); |
| 96 | rb.PushIpcInterface<MFIUser>(); | 98 | rb.PushIpcInterface<MFIUser>(); |
| 97 | |||
| 98 | LOG_DEBUG(Service_NFC, "called"); | ||
| 99 | } | 99 | } |
| 100 | }; | 100 | }; |
| 101 | 101 | ||
| @@ -138,19 +138,19 @@ private: | |||
| 138 | }; | 138 | }; |
| 139 | 139 | ||
| 140 | void InitializeOld(Kernel::HLERequestContext& ctx) { | 140 | void InitializeOld(Kernel::HLERequestContext& ctx) { |
| 141 | LOG_DEBUG(Service_NFC, "called"); | ||
| 142 | |||
| 141 | IPC::ResponseBuilder rb{ctx, 2, 0}; | 143 | IPC::ResponseBuilder rb{ctx, 2, 0}; |
| 142 | rb.Push(RESULT_SUCCESS); | 144 | rb.Push(RESULT_SUCCESS); |
| 143 | |||
| 144 | // We don't deal with hardware initialization so we can just stub this. | 145 | // We don't deal with hardware initialization so we can just stub this. |
| 145 | LOG_DEBUG(Service_NFC, "called"); | ||
| 146 | } | 146 | } |
| 147 | 147 | ||
| 148 | void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) { | 148 | void IsNfcEnabledOld(Kernel::HLERequestContext& ctx) { |
| 149 | LOG_DEBUG(Service_NFC, "IsNfcEnabledOld"); | ||
| 150 | |||
| 149 | IPC::ResponseBuilder rb{ctx, 3}; | 151 | IPC::ResponseBuilder rb{ctx, 3}; |
| 150 | rb.Push(RESULT_SUCCESS); | 152 | rb.Push(RESULT_SUCCESS); |
| 151 | rb.PushRaw<u8>(Settings::values.enable_nfc); | 153 | rb.PushRaw<u8>(Settings::values.enable_nfc); |
| 152 | |||
| 153 | LOG_DEBUG(Service_NFC, "IsNfcEnabledOld"); | ||
| 154 | } | 154 | } |
| 155 | 155 | ||
| 156 | void GetStateOld(Kernel::HLERequestContext& ctx) { | 156 | void GetStateOld(Kernel::HLERequestContext& ctx) { |
| @@ -183,11 +183,11 @@ public: | |||
| 183 | 183 | ||
| 184 | private: | 184 | private: |
| 185 | void CreateUserInterface(Kernel::HLERequestContext& ctx) { | 185 | void CreateUserInterface(Kernel::HLERequestContext& ctx) { |
| 186 | LOG_DEBUG(Service_NFC, "called"); | ||
| 187 | |||
| 186 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 188 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 187 | rb.Push(RESULT_SUCCESS); | 189 | rb.Push(RESULT_SUCCESS); |
| 188 | rb.PushIpcInterface<IUser>(); | 190 | rb.PushIpcInterface<IUser>(); |
| 189 | |||
| 190 | LOG_DEBUG(Service_NFC, "called"); | ||
| 191 | } | 191 | } |
| 192 | }; | 192 | }; |
| 193 | 193 | ||
| @@ -241,11 +241,11 @@ public: | |||
| 241 | 241 | ||
| 242 | private: | 242 | private: |
| 243 | void CreateSystemInterface(Kernel::HLERequestContext& ctx) { | 243 | void CreateSystemInterface(Kernel::HLERequestContext& ctx) { |
| 244 | LOG_DEBUG(Service_NFC, "called"); | ||
| 245 | |||
| 244 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 246 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 245 | rb.Push(RESULT_SUCCESS); | 247 | rb.Push(RESULT_SUCCESS); |
| 246 | rb.PushIpcInterface<ISystem>(); | 248 | rb.PushIpcInterface<ISystem>(); |
| 247 | |||
| 248 | LOG_DEBUG(Service_NFC, "called"); | ||
| 249 | } | 249 | } |
| 250 | }; | 250 | }; |
| 251 | 251 | ||
diff --git a/src/core/hle/service/nfp/nfp.cpp b/src/core/hle/service/nfp/nfp.cpp index 1d6e7756f..ff9170c24 100644 --- a/src/core/hle/service/nfp/nfp.cpp +++ b/src/core/hle/service/nfp/nfp.cpp | |||
| @@ -108,30 +108,29 @@ private: | |||
| 108 | static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); | 108 | static_assert(sizeof(CommonInfo) == 0x40, "CommonInfo is an invalid size"); |
| 109 | 109 | ||
| 110 | void Initialize(Kernel::HLERequestContext& ctx) { | 110 | void Initialize(Kernel::HLERequestContext& ctx) { |
| 111 | LOG_DEBUG(Service_NFC, "called"); | ||
| 112 | |||
| 111 | IPC::ResponseBuilder rb{ctx, 2, 0}; | 113 | IPC::ResponseBuilder rb{ctx, 2, 0}; |
| 112 | rb.Push(RESULT_SUCCESS); | 114 | rb.Push(RESULT_SUCCESS); |
| 113 | 115 | ||
| 114 | state = State::Initialized; | 116 | state = State::Initialized; |
| 115 | |||
| 116 | LOG_DEBUG(Service_NFC, "called"); | ||
| 117 | } | 117 | } |
| 118 | 118 | ||
| 119 | void GetState(Kernel::HLERequestContext& ctx) { | 119 | void GetState(Kernel::HLERequestContext& ctx) { |
| 120 | LOG_DEBUG(Service_NFC, "called"); | ||
| 121 | |||
| 120 | IPC::ResponseBuilder rb{ctx, 3, 0}; | 122 | IPC::ResponseBuilder rb{ctx, 3, 0}; |
| 121 | rb.Push(RESULT_SUCCESS); | 123 | rb.Push(RESULT_SUCCESS); |
| 122 | rb.PushRaw<u32>(static_cast<u32>(state)); | 124 | rb.PushRaw<u32>(static_cast<u32>(state)); |
| 123 | |||
| 124 | LOG_DEBUG(Service_NFC, "called"); | ||
| 125 | } | 125 | } |
| 126 | 126 | ||
| 127 | void ListDevices(Kernel::HLERequestContext& ctx) { | 127 | void ListDevices(Kernel::HLERequestContext& ctx) { |
| 128 | IPC::RequestParser rp{ctx}; | 128 | IPC::RequestParser rp{ctx}; |
| 129 | const u32 array_size = rp.Pop<u32>(); | 129 | const u32 array_size = rp.Pop<u32>(); |
| 130 | LOG_DEBUG(Service_NFP, "called, array_size={}", array_size); | ||
| 130 | 131 | ||
| 131 | ctx.WriteBuffer(&device_handle, sizeof(device_handle)); | 132 | ctx.WriteBuffer(&device_handle, sizeof(device_handle)); |
| 132 | 133 | ||
| 133 | LOG_DEBUG(Service_NFP, "called, array_size={}", array_size); | ||
| 134 | |||
| 135 | IPC::ResponseBuilder rb{ctx, 3}; | 134 | IPC::ResponseBuilder rb{ctx, 3}; |
| 136 | rb.Push(RESULT_SUCCESS); | 135 | rb.Push(RESULT_SUCCESS); |
| 137 | rb.Push<u32>(1); | 136 | rb.Push<u32>(1); |
| @@ -141,6 +140,7 @@ private: | |||
| 141 | IPC::RequestParser rp{ctx}; | 140 | IPC::RequestParser rp{ctx}; |
| 142 | const u64 dev_handle = rp.Pop<u64>(); | 141 | const u64 dev_handle = rp.Pop<u64>(); |
| 143 | LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); | 142 | LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); |
| 143 | |||
| 144 | IPC::ResponseBuilder rb{ctx, 3}; | 144 | IPC::ResponseBuilder rb{ctx, 3}; |
| 145 | rb.Push(RESULT_SUCCESS); | 145 | rb.Push(RESULT_SUCCESS); |
| 146 | rb.Push<u32>(npad_id); | 146 | rb.Push<u32>(npad_id); |
| @@ -150,6 +150,7 @@ private: | |||
| 150 | IPC::RequestParser rp{ctx}; | 150 | IPC::RequestParser rp{ctx}; |
| 151 | const u64 dev_handle = rp.Pop<u64>(); | 151 | const u64 dev_handle = rp.Pop<u64>(); |
| 152 | LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); | 152 | LOG_DEBUG(Service_NFP, "called, dev_handle=0x{:X}", dev_handle); |
| 153 | |||
| 153 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 154 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 154 | rb.Push(RESULT_SUCCESS); | 155 | rb.Push(RESULT_SUCCESS); |
| 155 | rb.PushCopyObjects(nfp_interface.GetNFCEvent()); | 156 | rb.PushCopyObjects(nfp_interface.GetNFCEvent()); |
| @@ -168,6 +169,7 @@ private: | |||
| 168 | 169 | ||
| 169 | void StopDetection(Kernel::HLERequestContext& ctx) { | 170 | void StopDetection(Kernel::HLERequestContext& ctx) { |
| 170 | LOG_DEBUG(Service_NFP, "called"); | 171 | LOG_DEBUG(Service_NFP, "called"); |
| 172 | |||
| 171 | switch (device_state) { | 173 | switch (device_state) { |
| 172 | case DeviceState::TagFound: | 174 | case DeviceState::TagFound: |
| 173 | case DeviceState::TagNearby: | 175 | case DeviceState::TagNearby: |
| @@ -185,6 +187,7 @@ private: | |||
| 185 | 187 | ||
| 186 | void GetDeviceState(Kernel::HLERequestContext& ctx) { | 188 | void GetDeviceState(Kernel::HLERequestContext& ctx) { |
| 187 | LOG_DEBUG(Service_NFP, "called"); | 189 | LOG_DEBUG(Service_NFP, "called"); |
| 190 | |||
| 188 | auto nfc_event = nfp_interface.GetNFCEvent(); | 191 | auto nfc_event = nfp_interface.GetNFCEvent(); |
| 189 | if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) { | 192 | if (!nfc_event->ShouldWait(Kernel::GetCurrentThread()) && !has_attached_handle) { |
| 190 | device_state = DeviceState::TagFound; | 193 | device_state = DeviceState::TagFound; |
| @@ -323,6 +326,7 @@ private: | |||
| 323 | 326 | ||
| 324 | void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { | 327 | void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { |
| 325 | LOG_DEBUG(Service_NFP, "called"); | 328 | LOG_DEBUG(Service_NFP, "called"); |
| 329 | |||
| 326 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 330 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 327 | rb.Push(RESULT_SUCCESS); | 331 | rb.Push(RESULT_SUCCESS); |
| 328 | rb.PushIpcInterface<IUser>(*this); | 332 | rb.PushIpcInterface<IUser>(*this); |
diff --git a/src/core/hle/service/nifm/nifm.cpp b/src/core/hle/service/nifm/nifm.cpp index 75dcd94a3..dee391201 100644 --- a/src/core/hle/service/nifm/nifm.cpp +++ b/src/core/hle/service/nifm/nifm.cpp | |||
| @@ -63,12 +63,14 @@ public: | |||
| 63 | private: | 63 | private: |
| 64 | void Submit(Kernel::HLERequestContext& ctx) { | 64 | void Submit(Kernel::HLERequestContext& ctx) { |
| 65 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 65 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 66 | |||
| 66 | IPC::ResponseBuilder rb{ctx, 2}; | 67 | IPC::ResponseBuilder rb{ctx, 2}; |
| 67 | rb.Push(RESULT_SUCCESS); | 68 | rb.Push(RESULT_SUCCESS); |
| 68 | } | 69 | } |
| 69 | 70 | ||
| 70 | void GetRequestState(Kernel::HLERequestContext& ctx) { | 71 | void GetRequestState(Kernel::HLERequestContext& ctx) { |
| 71 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 72 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 73 | |||
| 72 | IPC::ResponseBuilder rb{ctx, 3}; | 74 | IPC::ResponseBuilder rb{ctx, 3}; |
| 73 | rb.Push(RESULT_SUCCESS); | 75 | rb.Push(RESULT_SUCCESS); |
| 74 | rb.Push<u32>(0); | 76 | rb.Push<u32>(0); |
| @@ -76,12 +78,14 @@ private: | |||
| 76 | 78 | ||
| 77 | void GetResult(Kernel::HLERequestContext& ctx) { | 79 | void GetResult(Kernel::HLERequestContext& ctx) { |
| 78 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 80 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 81 | |||
| 79 | IPC::ResponseBuilder rb{ctx, 2}; | 82 | IPC::ResponseBuilder rb{ctx, 2}; |
| 80 | rb.Push(RESULT_SUCCESS); | 83 | rb.Push(RESULT_SUCCESS); |
| 81 | } | 84 | } |
| 82 | 85 | ||
| 83 | void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { | 86 | void GetSystemEventReadableHandles(Kernel::HLERequestContext& ctx) { |
| 84 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 87 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 88 | |||
| 85 | IPC::ResponseBuilder rb{ctx, 2, 2}; | 89 | IPC::ResponseBuilder rb{ctx, 2, 2}; |
| 86 | rb.Push(RESULT_SUCCESS); | 90 | rb.Push(RESULT_SUCCESS); |
| 87 | rb.PushCopyObjects(event1, event2); | 91 | rb.PushCopyObjects(event1, event2); |
| @@ -89,12 +93,14 @@ private: | |||
| 89 | 93 | ||
| 90 | void Cancel(Kernel::HLERequestContext& ctx) { | 94 | void Cancel(Kernel::HLERequestContext& ctx) { |
| 91 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 95 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 96 | |||
| 92 | IPC::ResponseBuilder rb{ctx, 2}; | 97 | IPC::ResponseBuilder rb{ctx, 2}; |
| 93 | rb.Push(RESULT_SUCCESS); | 98 | rb.Push(RESULT_SUCCESS); |
| 94 | } | 99 | } |
| 95 | 100 | ||
| 96 | void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) { | 101 | void SetConnectionConfirmationOption(Kernel::HLERequestContext& ctx) { |
| 97 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 102 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 103 | |||
| 98 | IPC::ResponseBuilder rb{ctx, 2}; | 104 | IPC::ResponseBuilder rb{ctx, 2}; |
| 99 | rb.Push(RESULT_SUCCESS); | 105 | rb.Push(RESULT_SUCCESS); |
| 100 | } | 106 | } |
| @@ -122,32 +128,36 @@ private: | |||
| 122 | void GetClientId(Kernel::HLERequestContext& ctx) { | 128 | void GetClientId(Kernel::HLERequestContext& ctx) { |
| 123 | static constexpr u32 client_id = 1; | 129 | static constexpr u32 client_id = 1; |
| 124 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 130 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 131 | |||
| 125 | IPC::ResponseBuilder rb{ctx, 4}; | 132 | IPC::ResponseBuilder rb{ctx, 4}; |
| 126 | rb.Push(RESULT_SUCCESS); | 133 | rb.Push(RESULT_SUCCESS); |
| 127 | rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid | 134 | rb.Push<u64>(client_id); // Client ID needs to be non zero otherwise it's considered invalid |
| 128 | } | 135 | } |
| 129 | void CreateScanRequest(Kernel::HLERequestContext& ctx) { | 136 | void CreateScanRequest(Kernel::HLERequestContext& ctx) { |
| 137 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 138 | |||
| 130 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 139 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 131 | 140 | ||
| 132 | rb.Push(RESULT_SUCCESS); | 141 | rb.Push(RESULT_SUCCESS); |
| 133 | rb.PushIpcInterface<IScanRequest>(); | 142 | rb.PushIpcInterface<IScanRequest>(); |
| 134 | |||
| 135 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 136 | } | 143 | } |
| 137 | void CreateRequest(Kernel::HLERequestContext& ctx) { | 144 | void CreateRequest(Kernel::HLERequestContext& ctx) { |
| 145 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 146 | |||
| 138 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 147 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 139 | 148 | ||
| 140 | rb.Push(RESULT_SUCCESS); | 149 | rb.Push(RESULT_SUCCESS); |
| 141 | rb.PushIpcInterface<IRequest>(); | 150 | rb.PushIpcInterface<IRequest>(); |
| 142 | |||
| 143 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 144 | } | 151 | } |
| 145 | void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { | 152 | void RemoveNetworkProfile(Kernel::HLERequestContext& ctx) { |
| 146 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 153 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 154 | |||
| 147 | IPC::ResponseBuilder rb{ctx, 2}; | 155 | IPC::ResponseBuilder rb{ctx, 2}; |
| 148 | rb.Push(RESULT_SUCCESS); | 156 | rb.Push(RESULT_SUCCESS); |
| 149 | } | 157 | } |
| 150 | void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { | 158 | void CreateTemporaryNetworkProfile(Kernel::HLERequestContext& ctx) { |
| 159 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 160 | |||
| 151 | ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size"); | 161 | ASSERT_MSG(ctx.GetReadBufferSize() == 0x17c, "NetworkProfileData is not the correct size"); |
| 152 | u128 uuid{}; | 162 | u128 uuid{}; |
| 153 | auto buffer = ctx.ReadBuffer(); | 163 | auto buffer = ctx.ReadBuffer(); |
| @@ -158,23 +168,24 @@ private: | |||
| 158 | rb.Push(RESULT_SUCCESS); | 168 | rb.Push(RESULT_SUCCESS); |
| 159 | rb.PushIpcInterface<INetworkProfile>(); | 169 | rb.PushIpcInterface<INetworkProfile>(); |
| 160 | rb.PushRaw<u128>(uuid); | 170 | rb.PushRaw<u128>(uuid); |
| 161 | |||
| 162 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 163 | } | 171 | } |
| 164 | void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { | 172 | void IsWirelessCommunicationEnabled(Kernel::HLERequestContext& ctx) { |
| 165 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 173 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 174 | |||
| 166 | IPC::ResponseBuilder rb{ctx, 3}; | 175 | IPC::ResponseBuilder rb{ctx, 3}; |
| 167 | rb.Push(RESULT_SUCCESS); | 176 | rb.Push(RESULT_SUCCESS); |
| 168 | rb.Push<u8>(0); | 177 | rb.Push<u8>(0); |
| 169 | } | 178 | } |
| 170 | void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) { | 179 | void IsEthernetCommunicationEnabled(Kernel::HLERequestContext& ctx) { |
| 171 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 180 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 181 | |||
| 172 | IPC::ResponseBuilder rb{ctx, 3}; | 182 | IPC::ResponseBuilder rb{ctx, 3}; |
| 173 | rb.Push(RESULT_SUCCESS); | 183 | rb.Push(RESULT_SUCCESS); |
| 174 | rb.Push<u8>(0); | 184 | rb.Push<u8>(0); |
| 175 | } | 185 | } |
| 176 | void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { | 186 | void IsAnyInternetRequestAccepted(Kernel::HLERequestContext& ctx) { |
| 177 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); | 187 | LOG_WARNING(Service_NIFM, "(STUBBED) called"); |
| 188 | |||
| 178 | IPC::ResponseBuilder rb{ctx, 3}; | 189 | IPC::ResponseBuilder rb{ctx, 3}; |
| 179 | rb.Push(RESULT_SUCCESS); | 190 | rb.Push(RESULT_SUCCESS); |
| 180 | rb.Push<u8>(0); | 191 | rb.Push<u8>(0); |
| @@ -235,17 +246,19 @@ public: | |||
| 235 | } | 246 | } |
| 236 | 247 | ||
| 237 | void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { | 248 | void CreateGeneralServiceOld(Kernel::HLERequestContext& ctx) { |
| 249 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 250 | |||
| 238 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 251 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 239 | rb.Push(RESULT_SUCCESS); | 252 | rb.Push(RESULT_SUCCESS); |
| 240 | rb.PushIpcInterface<IGeneralService>(); | 253 | rb.PushIpcInterface<IGeneralService>(); |
| 241 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 242 | } | 254 | } |
| 243 | 255 | ||
| 244 | void CreateGeneralService(Kernel::HLERequestContext& ctx) { | 256 | void CreateGeneralService(Kernel::HLERequestContext& ctx) { |
| 257 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 258 | |||
| 245 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 259 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 246 | rb.Push(RESULT_SUCCESS); | 260 | rb.Push(RESULT_SUCCESS); |
| 247 | rb.PushIpcInterface<IGeneralService>(); | 261 | rb.PushIpcInterface<IGeneralService>(); |
| 248 | LOG_DEBUG(Service_NIFM, "called"); | ||
| 249 | } | 262 | } |
| 250 | }; | 263 | }; |
| 251 | 264 | ||
diff --git a/src/core/hle/service/nim/nim.cpp b/src/core/hle/service/nim/nim.cpp index 18091c9bb..1bbccd444 100644 --- a/src/core/hle/service/nim/nim.cpp +++ b/src/core/hle/service/nim/nim.cpp | |||
| @@ -148,47 +148,53 @@ private: | |||
| 148 | 148 | ||
| 149 | void StartTask(Kernel::HLERequestContext& ctx) { | 149 | void StartTask(Kernel::HLERequestContext& ctx) { |
| 150 | // No need to connect to the internet, just finish the task straight away. | 150 | // No need to connect to the internet, just finish the task straight away. |
| 151 | LOG_DEBUG(Service_NIM, "called"); | ||
| 152 | |||
| 151 | finished_event->Signal(); | 153 | finished_event->Signal(); |
| 152 | IPC::ResponseBuilder rb{ctx, 2}; | 154 | IPC::ResponseBuilder rb{ctx, 2}; |
| 153 | rb.Push(RESULT_SUCCESS); | 155 | rb.Push(RESULT_SUCCESS); |
| 154 | LOG_DEBUG(Service_NIM, "called"); | ||
| 155 | } | 156 | } |
| 156 | 157 | ||
| 157 | void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) { | 158 | void GetFinishNotificationEvent(Kernel::HLERequestContext& ctx) { |
| 159 | LOG_DEBUG(Service_NIM, "called"); | ||
| 160 | |||
| 158 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 161 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 159 | rb.Push(RESULT_SUCCESS); | 162 | rb.Push(RESULT_SUCCESS); |
| 160 | rb.PushCopyObjects(finished_event); | 163 | rb.PushCopyObjects(finished_event); |
| 161 | LOG_DEBUG(Service_NIM, "called"); | ||
| 162 | } | 164 | } |
| 163 | 165 | ||
| 164 | void GetResult(Kernel::HLERequestContext& ctx) { | 166 | void GetResult(Kernel::HLERequestContext& ctx) { |
| 167 | LOG_DEBUG(Service_NIM, "called"); | ||
| 168 | |||
| 165 | IPC::ResponseBuilder rb{ctx, 2}; | 169 | IPC::ResponseBuilder rb{ctx, 2}; |
| 166 | rb.Push(RESULT_SUCCESS); | 170 | rb.Push(RESULT_SUCCESS); |
| 167 | LOG_DEBUG(Service_NIM, "called"); | ||
| 168 | } | 171 | } |
| 169 | 172 | ||
| 170 | void Cancel(Kernel::HLERequestContext& ctx) { | 173 | void Cancel(Kernel::HLERequestContext& ctx) { |
| 174 | LOG_DEBUG(Service_NIM, "called"); | ||
| 175 | |||
| 171 | finished_event->Clear(); | 176 | finished_event->Clear(); |
| 172 | IPC::ResponseBuilder rb{ctx, 2}; | 177 | IPC::ResponseBuilder rb{ctx, 2}; |
| 173 | rb.Push(RESULT_SUCCESS); | 178 | rb.Push(RESULT_SUCCESS); |
| 174 | LOG_DEBUG(Service_NIM, "called"); | ||
| 175 | } | 179 | } |
| 176 | 180 | ||
| 177 | void IsProcessing(Kernel::HLERequestContext& ctx) { | 181 | void IsProcessing(Kernel::HLERequestContext& ctx) { |
| 182 | LOG_DEBUG(Service_NIM, "called"); | ||
| 183 | |||
| 178 | IPC::ResponseBuilder rb{ctx, 3}; | 184 | IPC::ResponseBuilder rb{ctx, 3}; |
| 179 | rb.Push(RESULT_SUCCESS); | 185 | rb.Push(RESULT_SUCCESS); |
| 180 | rb.PushRaw<u32>(0); // We instantly process the request | 186 | rb.PushRaw<u32>(0); // We instantly process the request |
| 181 | LOG_DEBUG(Service_NIM, "called"); | ||
| 182 | } | 187 | } |
| 183 | 188 | ||
| 184 | void GetServerTime(Kernel::HLERequestContext& ctx) { | 189 | void GetServerTime(Kernel::HLERequestContext& ctx) { |
| 190 | LOG_DEBUG(Service_NIM, "called"); | ||
| 191 | |||
| 185 | const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>( | 192 | const s64 server_time{std::chrono::duration_cast<std::chrono::seconds>( |
| 186 | std::chrono::system_clock::now().time_since_epoch()) | 193 | std::chrono::system_clock::now().time_since_epoch()) |
| 187 | .count()}; | 194 | .count()}; |
| 188 | IPC::ResponseBuilder rb{ctx, 4}; | 195 | IPC::ResponseBuilder rb{ctx, 4}; |
| 189 | rb.Push(RESULT_SUCCESS); | 196 | rb.Push(RESULT_SUCCESS); |
| 190 | rb.PushRaw<s64>(server_time); | 197 | rb.PushRaw<s64>(server_time); |
| 191 | LOG_DEBUG(Service_NIM, "called"); | ||
| 192 | } | 198 | } |
| 193 | }; | 199 | }; |
| 194 | 200 | ||
| @@ -208,23 +214,26 @@ public: | |||
| 208 | 214 | ||
| 209 | private: | 215 | private: |
| 210 | void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) { | 216 | void OpenEnsureNetworkClockAvailabilityService(Kernel::HLERequestContext& ctx) { |
| 217 | LOG_DEBUG(Service_NIM, "called"); | ||
| 218 | |||
| 211 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 212 | rb.Push(RESULT_SUCCESS); | 220 | rb.Push(RESULT_SUCCESS); |
| 213 | rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(); | 221 | rb.PushIpcInterface<IEnsureNetworkClockAvailabilityService>(); |
| 214 | LOG_DEBUG(Service_NIM, "called"); | ||
| 215 | } | 222 | } |
| 216 | 223 | ||
| 217 | // TODO(ogniK): Do we need these? | 224 | // TODO(ogniK): Do we need these? |
| 218 | void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { | 225 | void SuspendAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { |
| 226 | LOG_WARNING(Service_NIM, "(STUBBED) called"); | ||
| 227 | |||
| 219 | IPC::ResponseBuilder rb{ctx, 2}; | 228 | IPC::ResponseBuilder rb{ctx, 2}; |
| 220 | rb.Push(RESULT_SUCCESS); | 229 | rb.Push(RESULT_SUCCESS); |
| 221 | LOG_WARNING(Service_NIM, "(STUBBED) called"); | ||
| 222 | } | 230 | } |
| 223 | 231 | ||
| 224 | void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { | 232 | void ResumeAutonomicTimeCorrection(Kernel::HLERequestContext& ctx) { |
| 233 | LOG_WARNING(Service_NIM, "(STUBBED) called"); | ||
| 234 | |||
| 225 | IPC::ResponseBuilder rb{ctx, 2}; | 235 | IPC::ResponseBuilder rb{ctx, 2}; |
| 226 | rb.Push(RESULT_SUCCESS); | 236 | rb.Push(RESULT_SUCCESS); |
| 227 | LOG_WARNING(Service_NIM, "(STUBBED) called"); | ||
| 228 | } | 237 | } |
| 229 | }; | 238 | }; |
| 230 | 239 | ||
diff --git a/src/core/hle/service/ns/ns.cpp b/src/core/hle/service/ns/ns.cpp index 1d2978f24..2663f56b1 100644 --- a/src/core/hle/service/ns/ns.cpp +++ b/src/core/hle/service/ns/ns.cpp | |||
| @@ -433,11 +433,11 @@ public: | |||
| 433 | private: | 433 | private: |
| 434 | template <typename T> | 434 | template <typename T> |
| 435 | void PushInterface(Kernel::HLERequestContext& ctx) { | 435 | void PushInterface(Kernel::HLERequestContext& ctx) { |
| 436 | LOG_DEBUG(Service_NS, "called"); | ||
| 437 | |||
| 436 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 438 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 437 | rb.Push(RESULT_SUCCESS); | 439 | rb.Push(RESULT_SUCCESS); |
| 438 | rb.PushIpcInterface<T>(); | 440 | rb.PushIpcInterface<T>(); |
| 439 | |||
| 440 | LOG_DEBUG(Service_NS, "called"); | ||
| 441 | } | 441 | } |
| 442 | }; | 442 | }; |
| 443 | 443 | ||
| @@ -526,11 +526,11 @@ public: | |||
| 526 | 526 | ||
| 527 | private: | 527 | private: |
| 528 | void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) { | 528 | void OpenSystemUpdateControl(Kernel::HLERequestContext& ctx) { |
| 529 | LOG_DEBUG(Service_NS, "called"); | ||
| 530 | |||
| 529 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 531 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 530 | rb.Push(RESULT_SUCCESS); | 532 | rb.Push(RESULT_SUCCESS); |
| 531 | rb.PushIpcInterface<ISystemUpdateControl>(); | 533 | rb.PushIpcInterface<ISystemUpdateControl>(); |
| 532 | |||
| 533 | LOG_DEBUG(Service_NS, "called"); | ||
| 534 | } | 534 | } |
| 535 | }; | 535 | }; |
| 536 | 536 | ||
diff --git a/src/core/hle/service/ns/pl_u.cpp b/src/core/hle/service/ns/pl_u.cpp index 1066bf505..ad176f89d 100644 --- a/src/core/hle/service/ns/pl_u.cpp +++ b/src/core/hle/service/ns/pl_u.cpp | |||
| @@ -281,6 +281,7 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { | |||
| 281 | const u32 shared_font_type{rp.Pop<u32>()}; | 281 | const u32 shared_font_type{rp.Pop<u32>()}; |
| 282 | // Games don't call this so all fonts should be loaded | 282 | // Games don't call this so all fonts should be loaded |
| 283 | LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type); | 283 | LOG_DEBUG(Service_NS, "called, shared_font_type={}", shared_font_type); |
| 284 | |||
| 284 | IPC::ResponseBuilder rb{ctx, 2}; | 285 | IPC::ResponseBuilder rb{ctx, 2}; |
| 285 | rb.Push(RESULT_SUCCESS); | 286 | rb.Push(RESULT_SUCCESS); |
| 286 | } | 287 | } |
| @@ -288,8 +289,8 @@ void PL_U::RequestLoad(Kernel::HLERequestContext& ctx) { | |||
| 288 | void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { | 289 | void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { |
| 289 | IPC::RequestParser rp{ctx}; | 290 | IPC::RequestParser rp{ctx}; |
| 290 | const u32 font_id{rp.Pop<u32>()}; | 291 | const u32 font_id{rp.Pop<u32>()}; |
| 291 | |||
| 292 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); | 292 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); |
| 293 | |||
| 293 | IPC::ResponseBuilder rb{ctx, 3}; | 294 | IPC::ResponseBuilder rb{ctx, 3}; |
| 294 | rb.Push(RESULT_SUCCESS); | 295 | rb.Push(RESULT_SUCCESS); |
| 295 | rb.Push<u32>(static_cast<u32>(LoadState::Done)); | 296 | rb.Push<u32>(static_cast<u32>(LoadState::Done)); |
| @@ -298,8 +299,8 @@ void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { | |||
| 298 | void PL_U::GetSize(Kernel::HLERequestContext& ctx) { | 299 | void PL_U::GetSize(Kernel::HLERequestContext& ctx) { |
| 299 | IPC::RequestParser rp{ctx}; | 300 | IPC::RequestParser rp{ctx}; |
| 300 | const u32 font_id{rp.Pop<u32>()}; | 301 | const u32 font_id{rp.Pop<u32>()}; |
| 301 | |||
| 302 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); | 302 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); |
| 303 | |||
| 303 | IPC::ResponseBuilder rb{ctx, 3}; | 304 | IPC::ResponseBuilder rb{ctx, 3}; |
| 304 | rb.Push(RESULT_SUCCESS); | 305 | rb.Push(RESULT_SUCCESS); |
| 305 | rb.Push<u32>(impl->GetSharedFontRegion(font_id).size); | 306 | rb.Push<u32>(impl->GetSharedFontRegion(font_id).size); |
| @@ -308,8 +309,8 @@ void PL_U::GetSize(Kernel::HLERequestContext& ctx) { | |||
| 308 | void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { | 309 | void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { |
| 309 | IPC::RequestParser rp{ctx}; | 310 | IPC::RequestParser rp{ctx}; |
| 310 | const u32 font_id{rp.Pop<u32>()}; | 311 | const u32 font_id{rp.Pop<u32>()}; |
| 311 | |||
| 312 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); | 312 | LOG_DEBUG(Service_NS, "called, font_id={}", font_id); |
| 313 | |||
| 313 | IPC::ResponseBuilder rb{ctx, 3}; | 314 | IPC::ResponseBuilder rb{ctx, 3}; |
| 314 | rb.Push(RESULT_SUCCESS); | 315 | rb.Push(RESULT_SUCCESS); |
| 315 | rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset); | 316 | rb.Push<u32>(impl->GetSharedFontRegion(font_id).offset); |
| @@ -317,6 +318,7 @@ void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { | |||
| 317 | 318 | ||
| 318 | void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { | 319 | void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { |
| 319 | // Map backing memory for the font data | 320 | // Map backing memory for the font data |
| 321 | LOG_DEBUG(Service_NS, "called"); | ||
| 320 | Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, | 322 | Core::CurrentProcess()->VMManager().MapMemoryBlock(SHARED_FONT_MEM_VADDR, impl->shared_font, 0, |
| 321 | SHARED_FONT_MEM_SIZE, | 323 | SHARED_FONT_MEM_SIZE, |
| 322 | Kernel::MemoryState::Shared); | 324 | Kernel::MemoryState::Shared); |
| @@ -328,7 +330,6 @@ void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { | |||
| 328 | Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, | 330 | Kernel::MemoryPermission::Read, SHARED_FONT_MEM_VADDR, Kernel::MemoryRegion::BASE, |
| 329 | "PL_U:shared_font_mem"); | 331 | "PL_U:shared_font_mem"); |
| 330 | 332 | ||
| 331 | LOG_DEBUG(Service_NS, "called"); | ||
| 332 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 333 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 333 | rb.Push(RESULT_SUCCESS); | 334 | rb.Push(RESULT_SUCCESS); |
| 334 | rb.PushCopyObjects(impl->shared_font_mem); | 335 | rb.PushCopyObjects(impl->shared_font_mem); |
| @@ -338,6 +339,7 @@ void PL_U::GetSharedFontInOrderOfPriority(Kernel::HLERequestContext& ctx) { | |||
| 338 | IPC::RequestParser rp{ctx}; | 339 | IPC::RequestParser rp{ctx}; |
| 339 | const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for | 340 | const u64 language_code{rp.Pop<u64>()}; // TODO(ogniK): Find out what this is used for |
| 340 | LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code); | 341 | LOG_DEBUG(Service_NS, "called, language_code={:X}", language_code); |
| 342 | |||
| 341 | IPC::ResponseBuilder rb{ctx, 4}; | 343 | IPC::ResponseBuilder rb{ctx, 4}; |
| 342 | std::vector<u32> font_codes; | 344 | std::vector<u32> font_codes; |
| 343 | std::vector<u32> font_offsets; | 345 | std::vector<u32> font_offsets; |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp index c41ef7058..466db7ccd 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp | |||
| @@ -54,6 +54,7 @@ u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 54 | IoctlInitalizeEx params{}; | 54 | IoctlInitalizeEx params{}; |
| 55 | std::memcpy(¶ms, input.data(), input.size()); | 55 | std::memcpy(¶ms, input.data(), input.size()); |
| 56 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); | 56 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); |
| 57 | |||
| 57 | return 0; | 58 | return 0; |
| 58 | } | 59 | } |
| 59 | 60 | ||
| @@ -191,6 +192,7 @@ u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 191 | IoctlBindChannel params{}; | 192 | IoctlBindChannel params{}; |
| 192 | std::memcpy(¶ms, input.data(), input.size()); | 193 | std::memcpy(¶ms, input.data(), input.size()); |
| 193 | LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); | 194 | LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd); |
| 195 | |||
| 194 | channel = params.fd; | 196 | channel = params.fd; |
| 195 | return 0; | 197 | return 0; |
| 196 | } | 198 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp index 7a88ae029..d57a54ee8 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp | |||
| @@ -5,6 +5,8 @@ | |||
| 5 | #include <cstring> | 5 | #include <cstring> |
| 6 | #include "common/assert.h" | 6 | #include "common/assert.h" |
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/core_timing.h" | ||
| 9 | #include "core/core_timing_util.h" | ||
| 8 | #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" | 10 | #include "core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h" |
| 9 | 11 | ||
| 10 | namespace Service::Nvidia::Devices { | 12 | namespace Service::Nvidia::Devices { |
| @@ -33,6 +35,8 @@ u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vec | |||
| 33 | return ZBCQueryTable(input, output); | 35 | return ZBCQueryTable(input, output); |
| 34 | case IoctlCommand::IocFlushL2: | 36 | case IoctlCommand::IocFlushL2: |
| 35 | return FlushL2(input, output); | 37 | return FlushL2(input, output); |
| 38 | case IoctlCommand::IocGetGpuTime: | ||
| 39 | return GetGpuTime(input, output); | ||
| 36 | } | 40 | } |
| 37 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); | 41 | UNIMPLEMENTED_MSG("Unimplemented ioctl"); |
| 38 | return 0; | 42 | return 0; |
| @@ -99,6 +103,7 @@ u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& | |||
| 99 | 103 | ||
| 100 | u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { | 104 | u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { |
| 101 | LOG_DEBUG(Service_NVDRV, "called"); | 105 | LOG_DEBUG(Service_NVDRV, "called"); |
| 106 | |||
| 102 | IoctlActiveSlotMask params{}; | 107 | IoctlActiveSlotMask params{}; |
| 103 | if (input.size() > 0) { | 108 | if (input.size() > 0) { |
| 104 | std::memcpy(¶ms, input.data(), input.size()); | 109 | std::memcpy(¶ms, input.data(), input.size()); |
| @@ -111,6 +116,7 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector | |||
| 111 | 116 | ||
| 112 | u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { | 117 | u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { |
| 113 | LOG_DEBUG(Service_NVDRV, "called"); | 118 | LOG_DEBUG(Service_NVDRV, "called"); |
| 119 | |||
| 114 | IoctlZcullGetCtxSize params{}; | 120 | IoctlZcullGetCtxSize params{}; |
| 115 | if (input.size() > 0) { | 121 | if (input.size() > 0) { |
| 116 | std::memcpy(¶ms, input.data(), input.size()); | 122 | std::memcpy(¶ms, input.data(), input.size()); |
| @@ -122,6 +128,7 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u | |||
| 122 | 128 | ||
| 123 | u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { | 129 | u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { |
| 124 | LOG_DEBUG(Service_NVDRV, "called"); | 130 | LOG_DEBUG(Service_NVDRV, "called"); |
| 131 | |||
| 125 | IoctlNvgpuGpuZcullGetInfoArgs params{}; | 132 | IoctlNvgpuGpuZcullGetInfoArgs params{}; |
| 126 | 133 | ||
| 127 | if (input.size() > 0) { | 134 | if (input.size() > 0) { |
| @@ -144,6 +151,7 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& | |||
| 144 | 151 | ||
| 145 | u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { | 152 | u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { |
| 146 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 153 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 154 | |||
| 147 | IoctlZbcSetTable params{}; | 155 | IoctlZbcSetTable params{}; |
| 148 | std::memcpy(¶ms, input.data(), input.size()); | 156 | std::memcpy(¶ms, input.data(), input.size()); |
| 149 | // TODO(ogniK): What does this even actually do? | 157 | // TODO(ogniK): What does this even actually do? |
| @@ -153,6 +161,7 @@ u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& | |||
| 153 | 161 | ||
| 154 | u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { | 162 | u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { |
| 155 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 163 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 164 | |||
| 156 | IoctlZbcQueryTable params{}; | 165 | IoctlZbcQueryTable params{}; |
| 157 | std::memcpy(¶ms, input.data(), input.size()); | 166 | std::memcpy(¶ms, input.data(), input.size()); |
| 158 | // TODO : To implement properly | 167 | // TODO : To implement properly |
| @@ -162,6 +171,7 @@ u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8> | |||
| 162 | 171 | ||
| 163 | u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { | 172 | u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { |
| 164 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 173 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 174 | |||
| 165 | IoctlFlushL2 params{}; | 175 | IoctlFlushL2 params{}; |
| 166 | std::memcpy(¶ms, input.data(), input.size()); | 176 | std::memcpy(¶ms, input.data(), input.size()); |
| 167 | // TODO : To implement properly | 177 | // TODO : To implement properly |
| @@ -169,4 +179,14 @@ u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 169 | return 0; | 179 | return 0; |
| 170 | } | 180 | } |
| 171 | 181 | ||
| 182 | u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 183 | LOG_DEBUG(Service_NVDRV, "called"); | ||
| 184 | |||
| 185 | IoctlGetGpuTime params{}; | ||
| 186 | std::memcpy(¶ms, input.data(), input.size()); | ||
| 187 | params.gpu_time = CoreTiming::cyclesToNs(CoreTiming::GetTicks()); | ||
| 188 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 189 | return 0; | ||
| 190 | } | ||
| 191 | |||
| 172 | } // namespace Service::Nvidia::Devices | 192 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h index 3bbf028ad..240435eea 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h | |||
| @@ -156,6 +156,11 @@ private: | |||
| 156 | }; | 156 | }; |
| 157 | static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size"); | 157 | static_assert(sizeof(IoctlFlushL2) == 8, "IoctlFlushL2 is incorrect size"); |
| 158 | 158 | ||
| 159 | struct IoctlGetGpuTime { | ||
| 160 | u64_le gpu_time; | ||
| 161 | }; | ||
| 162 | static_assert(sizeof(IoctlGetGpuTime) == 8, "IoctlGetGpuTime is incorrect size"); | ||
| 163 | |||
| 159 | u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); | 164 | u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output); |
| 160 | u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); | 165 | u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output); |
| 161 | u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); | 166 | u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); |
| @@ -164,6 +169,7 @@ private: | |||
| 164 | u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); | 169 | u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); |
| 165 | u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); | 170 | u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); |
| 166 | u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); | 171 | u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); |
| 172 | u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); | ||
| 167 | }; | 173 | }; |
| 168 | 174 | ||
| 169 | } // namespace Service::Nvidia::Devices | 175 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index 874d5e1c3..3bfce0110 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -8,7 +8,6 @@ | |||
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" | 9 | #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" |
| 10 | #include "core/memory.h" | 10 | #include "core/memory.h" |
| 11 | #include "video_core/command_processor.h" | ||
| 12 | #include "video_core/gpu.h" | 11 | #include "video_core/gpu.h" |
| 13 | #include "video_core/memory_manager.h" | 12 | #include "video_core/memory_manager.h" |
| 14 | 13 | ||
| @@ -61,12 +60,14 @@ u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output | |||
| 61 | IoctlSetNvmapFD params{}; | 60 | IoctlSetNvmapFD params{}; |
| 62 | std::memcpy(¶ms, input.data(), input.size()); | 61 | std::memcpy(¶ms, input.data(), input.size()); |
| 63 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 62 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 63 | |||
| 64 | nvmap_fd = params.nvmap_fd; | 64 | nvmap_fd = params.nvmap_fd; |
| 65 | return 0; | 65 | return 0; |
| 66 | } | 66 | } |
| 67 | 67 | ||
| 68 | u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { | 68 | u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { |
| 69 | LOG_DEBUG(Service_NVDRV, "called"); | 69 | LOG_DEBUG(Service_NVDRV, "called"); |
| 70 | |||
| 70 | IoctlClientData params{}; | 71 | IoctlClientData params{}; |
| 71 | std::memcpy(¶ms, input.data(), input.size()); | 72 | std::memcpy(¶ms, input.data(), input.size()); |
| 72 | user_data = params.data; | 73 | user_data = params.data; |
| @@ -75,6 +76,7 @@ u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& out | |||
| 75 | 76 | ||
| 76 | u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { | 77 | u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { |
| 77 | LOG_DEBUG(Service_NVDRV, "called"); | 78 | LOG_DEBUG(Service_NVDRV, "called"); |
| 79 | |||
| 78 | IoctlClientData params{}; | 80 | IoctlClientData params{}; |
| 79 | std::memcpy(¶ms, input.data(), input.size()); | 81 | std::memcpy(¶ms, input.data(), input.size()); |
| 80 | params.data = user_data; | 82 | params.data = user_data; |
| @@ -86,6 +88,7 @@ u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 86 | std::memcpy(&zcull_params, input.data(), input.size()); | 88 | std::memcpy(&zcull_params, input.data(), input.size()); |
| 87 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, | 89 | LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, |
| 88 | zcull_params.mode); | 90 | zcull_params.mode); |
| 91 | |||
| 89 | std::memcpy(output.data(), &zcull_params, output.size()); | 92 | std::memcpy(output.data(), &zcull_params, output.size()); |
| 90 | return 0; | 93 | return 0; |
| 91 | } | 94 | } |
| @@ -95,6 +98,7 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& | |||
| 95 | std::memcpy(¶ms, input.data(), input.size()); | 98 | std::memcpy(¶ms, input.data(), input.size()); |
| 96 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, | 99 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, |
| 97 | params.size, params.mem); | 100 | params.size, params.mem); |
| 101 | |||
| 98 | std::memcpy(output.data(), ¶ms, output.size()); | 102 | std::memcpy(output.data(), ¶ms, output.size()); |
| 99 | return 0; | 103 | return 0; |
| 100 | } | 104 | } |
| @@ -102,6 +106,7 @@ u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& | |||
| 102 | u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { | 106 | u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { |
| 103 | std::memcpy(&channel_priority, input.data(), input.size()); | 107 | std::memcpy(&channel_priority, input.data(), input.size()); |
| 104 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); | 108 | LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); |
| 109 | |||
| 105 | return 0; | 110 | return 0; |
| 106 | } | 111 | } |
| 107 | 112 | ||
| @@ -113,6 +118,7 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 113 | "unk1={:X}, unk2={:X}, unk3={:X}", | 118 | "unk1={:X}, unk2={:X}, unk3={:X}", |
| 114 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, | 119 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, |
| 115 | params.unk3); | 120 | params.unk3); |
| 121 | |||
| 116 | params.fence_out.id = 0; | 122 | params.fence_out.id = 0; |
| 117 | params.fence_out.value = 0; | 123 | params.fence_out.value = 0; |
| 118 | std::memcpy(output.data(), ¶ms, output.size()); | 124 | std::memcpy(output.data(), ¶ms, output.size()); |
| @@ -124,11 +130,18 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector< | |||
| 124 | std::memcpy(¶ms, input.data(), input.size()); | 130 | std::memcpy(¶ms, input.data(), input.size()); |
| 125 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, | 131 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, |
| 126 | params.flags); | 132 | params.flags); |
| 133 | |||
| 127 | params.obj_id = 0x0; | 134 | params.obj_id = 0x0; |
| 128 | std::memcpy(output.data(), ¶ms, output.size()); | 135 | std::memcpy(output.data(), ¶ms, output.size()); |
| 129 | return 0; | 136 | return 0; |
| 130 | } | 137 | } |
| 131 | 138 | ||
| 139 | static void PushGPUEntries(Tegra::CommandList&& entries) { | ||
| 140 | auto& dma_pusher{Core::System::GetInstance().GPU().DmaPusher()}; | ||
| 141 | dma_pusher.Push(std::move(entries)); | ||
| 142 | dma_pusher.DispatchCalls(); | ||
| 143 | } | ||
| 144 | |||
| 132 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { | 145 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { |
| 133 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 146 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| 134 | UNIMPLEMENTED(); | 147 | UNIMPLEMENTED(); |
| @@ -142,11 +155,11 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 142 | params.num_entries * sizeof(Tegra::CommandListHeader), | 155 | params.num_entries * sizeof(Tegra::CommandListHeader), |
| 143 | "Incorrect input size"); | 156 | "Incorrect input size"); |
| 144 | 157 | ||
| 145 | std::vector<Tegra::CommandListHeader> entries(params.num_entries); | 158 | Tegra::CommandList entries(params.num_entries); |
| 146 | std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], | 159 | std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], |
| 147 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 160 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 148 | 161 | ||
| 149 | Core::System::GetInstance().GPU().ProcessCommandLists(entries); | 162 | PushGPUEntries(std::move(entries)); |
| 150 | 163 | ||
| 151 | params.fence_out.id = 0; | 164 | params.fence_out.id = 0; |
| 152 | params.fence_out.value = 0; | 165 | params.fence_out.value = 0; |
| @@ -163,11 +176,11 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) | |||
| 163 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", | 176 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", |
| 164 | params.address, params.num_entries, params.flags); | 177 | params.address, params.num_entries, params.flags); |
| 165 | 178 | ||
| 166 | std::vector<Tegra::CommandListHeader> entries(params.num_entries); | 179 | Tegra::CommandList entries(params.num_entries); |
| 167 | Memory::ReadBlock(params.address, entries.data(), | 180 | Memory::ReadBlock(params.address, entries.data(), |
| 168 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 181 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 169 | 182 | ||
| 170 | Core::System::GetInstance().GPU().ProcessCommandLists(entries); | 183 | PushGPUEntries(std::move(entries)); |
| 171 | 184 | ||
| 172 | params.fence_out.id = 0; | 185 | params.fence_out.id = 0; |
| 173 | params.fence_out.value = 0; | 186 | params.fence_out.value = 0; |
| @@ -179,6 +192,7 @@ u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& outpu | |||
| 179 | IoctlGetWaitbase params{}; | 192 | IoctlGetWaitbase params{}; |
| 180 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); | 193 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); |
| 181 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); | 194 | LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); |
| 195 | |||
| 182 | params.value = 0; // Seems to be hard coded at 0 | 196 | params.value = 0; // Seems to be hard coded at 0 |
| 183 | std::memcpy(output.data(), ¶ms, output.size()); | 197 | std::memcpy(output.data(), ¶ms, output.size()); |
| 184 | return 0; | 198 | return 0; |
| @@ -188,6 +202,7 @@ u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& | |||
| 188 | IoctlChannelSetTimeout params{}; | 202 | IoctlChannelSetTimeout params{}; |
| 189 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); | 203 | std::memcpy(¶ms, input.data(), sizeof(IoctlChannelSetTimeout)); |
| 190 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); | 204 | LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); |
| 205 | |||
| 191 | return 0; | 206 | return 0; |
| 192 | } | 207 | } |
| 193 | 208 | ||
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp index 46dbbc37c..f5e8ea7c3 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | |||
| @@ -30,6 +30,7 @@ u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 30 | IoctlSetNvmapFD params{}; | 30 | IoctlSetNvmapFD params{}; |
| 31 | std::memcpy(¶ms, input.data(), input.size()); | 31 | std::memcpy(¶ms, input.data(), input.size()); |
| 32 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 32 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 33 | |||
| 33 | nvmap_fd = params.nvmap_fd; | 34 | nvmap_fd = params.nvmap_fd; |
| 34 | return 0; | 35 | return 0; |
| 35 | } | 36 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp index c67f934f6..3e0951ab0 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp | |||
| @@ -30,6 +30,7 @@ u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& outp | |||
| 30 | IoctlSetNvmapFD params{}; | 30 | IoctlSetNvmapFD params{}; |
| 31 | std::memcpy(¶ms, input.data(), input.size()); | 31 | std::memcpy(¶ms, input.data(), input.size()); |
| 32 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 32 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 33 | |||
| 33 | nvmap_fd = params.nvmap_fd; | 34 | nvmap_fd = params.nvmap_fd; |
| 34 | return 0; | 35 | return 0; |
| 35 | } | 36 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp index 727b9fee4..d544f0f31 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | |||
| @@ -30,6 +30,7 @@ u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output | |||
| 30 | IoctlSetNvmapFD params{}; | 30 | IoctlSetNvmapFD params{}; |
| 31 | std::memcpy(¶ms, input.data(), input.size()); | 31 | std::memcpy(¶ms, input.data(), input.size()); |
| 32 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); | 32 | LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); |
| 33 | |||
| 33 | nvmap_fd = params.nvmap_fd; | 34 | nvmap_fd = params.nvmap_fd; |
| 34 | return 0; | 35 | return 0; |
| 35 | } | 36 | } |
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp index 43651d8a6..1ec796fc6 100644 --- a/src/core/hle/service/nvdrv/devices/nvmap.cpp +++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp | |||
| @@ -54,6 +54,7 @@ u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 54 | LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); | 54 | LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); |
| 55 | 55 | ||
| 56 | if (!params.size) { | 56 | if (!params.size) { |
| 57 | LOG_ERROR(Service_NVDRV, "Size is 0"); | ||
| 57 | return static_cast<u32>(NvErrCodes::InvalidValue); | 58 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 58 | } | 59 | } |
| 59 | // Create a new nvmap object and obtain a handle to it. | 60 | // Create a new nvmap object and obtain a handle to it. |
| @@ -78,10 +79,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 78 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); | 79 | LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); |
| 79 | 80 | ||
| 80 | if (!params.handle) { | 81 | if (!params.handle) { |
| 82 | LOG_ERROR(Service_NVDRV, "Handle is 0"); | ||
| 81 | return static_cast<u32>(NvErrCodes::InvalidValue); | 83 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 82 | } | 84 | } |
| 83 | 85 | ||
| 84 | if ((params.align - 1) & params.align) { | 86 | if ((params.align - 1) & params.align) { |
| 87 | LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); | ||
| 85 | return static_cast<u32>(NvErrCodes::InvalidValue); | 88 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 86 | } | 89 | } |
| 87 | 90 | ||
| @@ -92,10 +95,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 92 | 95 | ||
| 93 | auto object = GetObject(params.handle); | 96 | auto object = GetObject(params.handle); |
| 94 | if (!object) { | 97 | if (!object) { |
| 98 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | ||
| 95 | return static_cast<u32>(NvErrCodes::InvalidValue); | 99 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 96 | } | 100 | } |
| 97 | 101 | ||
| 98 | if (object->status == Object::Status::Allocated) { | 102 | if (object->status == Object::Status::Allocated) { |
| 103 | LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); | ||
| 99 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 104 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); |
| 100 | } | 105 | } |
| 101 | 106 | ||
| @@ -116,11 +121,13 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 116 | LOG_WARNING(Service_NVDRV, "called"); | 121 | LOG_WARNING(Service_NVDRV, "called"); |
| 117 | 122 | ||
| 118 | if (!params.handle) { | 123 | if (!params.handle) { |
| 124 | LOG_ERROR(Service_NVDRV, "Handle is zero"); | ||
| 119 | return static_cast<u32>(NvErrCodes::InvalidValue); | 125 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 120 | } | 126 | } |
| 121 | 127 | ||
| 122 | auto object = GetObject(params.handle); | 128 | auto object = GetObject(params.handle); |
| 123 | if (!object) { | 129 | if (!object) { |
| 130 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | ||
| 124 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 131 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); |
| 125 | } | 132 | } |
| 126 | 133 | ||
| @@ -139,11 +146,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 139 | auto itr = std::find_if(handles.begin(), handles.end(), | 146 | auto itr = std::find_if(handles.begin(), handles.end(), |
| 140 | [&](const auto& entry) { return entry.second->id == params.id; }); | 147 | [&](const auto& entry) { return entry.second->id == params.id; }); |
| 141 | if (itr == handles.end()) { | 148 | if (itr == handles.end()) { |
| 149 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | ||
| 142 | return static_cast<u32>(NvErrCodes::InvalidValue); | 150 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 143 | } | 151 | } |
| 144 | 152 | ||
| 145 | auto& object = itr->second; | 153 | auto& object = itr->second; |
| 146 | if (object->status != Object::Status::Allocated) { | 154 | if (object->status != Object::Status::Allocated) { |
| 155 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); | ||
| 147 | return static_cast<u32>(NvErrCodes::InvalidValue); | 156 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 148 | } | 157 | } |
| 149 | 158 | ||
| @@ -166,10 +175,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 166 | 175 | ||
| 167 | auto object = GetObject(params.handle); | 176 | auto object = GetObject(params.handle); |
| 168 | if (!object) { | 177 | if (!object) { |
| 178 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | ||
| 169 | return static_cast<u32>(NvErrCodes::InvalidValue); | 179 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 170 | } | 180 | } |
| 171 | 181 | ||
| 172 | if (object->status != Object::Status::Allocated) { | 182 | if (object->status != Object::Status::Allocated) { |
| 183 | LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); | ||
| 173 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); | 184 | return static_cast<u32>(NvErrCodes::OperationNotPermitted); |
| 174 | } | 185 | } |
| 175 | 186 | ||
| @@ -209,9 +220,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { | |||
| 209 | 220 | ||
| 210 | auto itr = handles.find(params.handle); | 221 | auto itr = handles.find(params.handle); |
| 211 | if (itr == handles.end()) { | 222 | if (itr == handles.end()) { |
| 223 | LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); | ||
| 212 | return static_cast<u32>(NvErrCodes::InvalidValue); | 224 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 213 | } | 225 | } |
| 214 | if (!itr->second->refcount) { | 226 | if (!itr->second->refcount) { |
| 227 | LOG_ERROR( | ||
| 228 | Service_NVDRV, | ||
| 229 | "There is no references to this object. The object is already freed. handle={:08X}", | ||
| 230 | params.handle); | ||
| 215 | return static_cast<u32>(NvErrCodes::InvalidValue); | 231 | return static_cast<u32>(NvErrCodes::InvalidValue); |
| 216 | } | 232 | } |
| 217 | 233 | ||
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp index ac3859353..ff76e0524 100644 --- a/src/core/hle/service/nvdrv/interface.cpp +++ b/src/core/hle/service/nvdrv/interface.cpp | |||
| @@ -55,6 +55,7 @@ void NVDRV::Close(Kernel::HLERequestContext& ctx) { | |||
| 55 | 55 | ||
| 56 | void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { | 56 | void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { |
| 57 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 57 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 58 | |||
| 58 | IPC::ResponseBuilder rb{ctx, 3}; | 59 | IPC::ResponseBuilder rb{ctx, 3}; |
| 59 | rb.Push(RESULT_SUCCESS); | 60 | rb.Push(RESULT_SUCCESS); |
| 60 | rb.Push<u32>(0); | 61 | rb.Push<u32>(0); |
| @@ -75,8 +76,8 @@ void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { | |||
| 75 | void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { | 76 | void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { |
| 76 | IPC::RequestParser rp{ctx}; | 77 | IPC::RequestParser rp{ctx}; |
| 77 | pid = rp.Pop<u64>(); | 78 | pid = rp.Pop<u64>(); |
| 78 | |||
| 79 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); | 79 | LOG_WARNING(Service_NVDRV, "(STUBBED) called, pid=0x{:X}", pid); |
| 80 | |||
| 80 | IPC::ResponseBuilder rb{ctx, 3}; | 81 | IPC::ResponseBuilder rb{ctx, 3}; |
| 81 | rb.Push(RESULT_SUCCESS); | 82 | rb.Push(RESULT_SUCCESS); |
| 82 | rb.Push<u32>(0); | 83 | rb.Push<u32>(0); |
| @@ -84,6 +85,23 @@ void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { | |||
| 84 | 85 | ||
| 85 | void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { | 86 | void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { |
| 86 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | 87 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); |
| 88 | |||
| 89 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 90 | rb.Push(RESULT_SUCCESS); | ||
| 91 | } | ||
| 92 | |||
| 93 | void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) { | ||
| 94 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | ||
| 95 | |||
| 96 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 97 | rb.Push(RESULT_SUCCESS); | ||
| 98 | } | ||
| 99 | |||
| 100 | void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { | ||
| 101 | // According to SwitchBrew, this has no inputs and no outputs, so effectively does nothing on | ||
| 102 | // retail hardware. | ||
| 103 | LOG_DEBUG(Service_NVDRV, "called"); | ||
| 104 | |||
| 87 | IPC::ResponseBuilder rb{ctx, 2}; | 105 | IPC::ResponseBuilder rb{ctx, 2}; |
| 88 | rb.Push(RESULT_SUCCESS); | 106 | rb.Push(RESULT_SUCCESS); |
| 89 | } | 107 | } |
| @@ -97,10 +115,10 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name) | |||
| 97 | {3, &NVDRV::Initialize, "Initialize"}, | 115 | {3, &NVDRV::Initialize, "Initialize"}, |
| 98 | {4, &NVDRV::QueryEvent, "QueryEvent"}, | 116 | {4, &NVDRV::QueryEvent, "QueryEvent"}, |
| 99 | {5, nullptr, "MapSharedMem"}, | 117 | {5, nullptr, "MapSharedMem"}, |
| 100 | {6, nullptr, "GetStatus"}, | 118 | {6, &NVDRV::GetStatus, "GetStatus"}, |
| 101 | {7, nullptr, "ForceSetClientPID"}, | 119 | {7, nullptr, "ForceSetClientPID"}, |
| 102 | {8, &NVDRV::SetClientPID, "SetClientPID"}, | 120 | {8, &NVDRV::SetClientPID, "SetClientPID"}, |
| 103 | {9, nullptr, "DumpGraphicsMemoryInfo"}, | 121 | {9, &NVDRV::DumpGraphicsMemoryInfo, "DumpGraphicsMemoryInfo"}, |
| 104 | {10, nullptr, "InitializeDevtools"}, | 122 | {10, nullptr, "InitializeDevtools"}, |
| 105 | {11, &NVDRV::Ioctl, "Ioctl2"}, | 123 | {11, &NVDRV::Ioctl, "Ioctl2"}, |
| 106 | {12, nullptr, "Ioctl3"}, | 124 | {12, nullptr, "Ioctl3"}, |
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h index d340893c2..5a1e4baa7 100644 --- a/src/core/hle/service/nvdrv/interface.h +++ b/src/core/hle/service/nvdrv/interface.h | |||
| @@ -24,6 +24,8 @@ private: | |||
| 24 | void QueryEvent(Kernel::HLERequestContext& ctx); | 24 | void QueryEvent(Kernel::HLERequestContext& ctx); |
| 25 | void SetClientPID(Kernel::HLERequestContext& ctx); | 25 | void SetClientPID(Kernel::HLERequestContext& ctx); |
| 26 | void FinishInitialize(Kernel::HLERequestContext& ctx); | 26 | void FinishInitialize(Kernel::HLERequestContext& ctx); |
| 27 | void GetStatus(Kernel::HLERequestContext& ctx); | ||
| 28 | void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); | ||
| 27 | 29 | ||
| 28 | std::shared_ptr<Module> nvdrv; | 30 | std::shared_ptr<Module> nvdrv; |
| 29 | 31 | ||
diff --git a/src/core/hle/service/nvflinger/buffer_queue.cpp b/src/core/hle/service/nvflinger/buffer_queue.cpp index 630ebbfc7..172a1a441 100644 --- a/src/core/hle/service/nvflinger/buffer_queue.cpp +++ b/src/core/hle/service/nvflinger/buffer_queue.cpp | |||
| @@ -20,13 +20,13 @@ BufferQueue::BufferQueue(u32 id, u64 layer_id) : id(id), layer_id(layer_id) { | |||
| 20 | BufferQueue::~BufferQueue() = default; | 20 | BufferQueue::~BufferQueue() = default; |
| 21 | 21 | ||
| 22 | void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { | 22 | void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { |
| 23 | LOG_WARNING(Service, "Adding graphics buffer {}", slot); | ||
| 24 | |||
| 23 | Buffer buffer{}; | 25 | Buffer buffer{}; |
| 24 | buffer.slot = slot; | 26 | buffer.slot = slot; |
| 25 | buffer.igbp_buffer = igbp_buffer; | 27 | buffer.igbp_buffer = igbp_buffer; |
| 26 | buffer.status = Buffer::Status::Free; | 28 | buffer.status = Buffer::Status::Free; |
| 27 | 29 | ||
| 28 | LOG_WARNING(Service, "Adding graphics buffer {}", slot); | ||
| 29 | |||
| 30 | queue.emplace_back(buffer); | 30 | queue.emplace_back(buffer); |
| 31 | buffer_wait_event->Signal(); | 31 | buffer_wait_event->Signal(); |
| 32 | } | 32 | } |
| @@ -92,6 +92,7 @@ void BufferQueue::ReleaseBuffer(u32 slot) { | |||
| 92 | 92 | ||
| 93 | u32 BufferQueue::Query(QueryType type) { | 93 | u32 BufferQueue::Query(QueryType type) { |
| 94 | LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type)); | 94 | LOG_WARNING(Service, "(STUBBED) called type={}", static_cast<u32>(type)); |
| 95 | |||
| 95 | switch (type) { | 96 | switch (type) { |
| 96 | case QueryType::NativeWindowFormat: | 97 | case QueryType::NativeWindowFormat: |
| 97 | // TODO(Subv): Use an enum for this | 98 | // TODO(Subv): Use an enum for this |
diff --git a/src/core/hle/service/pctl/module.cpp b/src/core/hle/service/pctl/module.cpp index 4fd185f69..6081f41e1 100644 --- a/src/core/hle/service/pctl/module.cpp +++ b/src/core/hle/service/pctl/module.cpp | |||
| @@ -114,29 +114,33 @@ public: | |||
| 114 | private: | 114 | private: |
| 115 | void Initialize(Kernel::HLERequestContext& ctx) { | 115 | void Initialize(Kernel::HLERequestContext& ctx) { |
| 116 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | 116 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); |
| 117 | |||
| 117 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; | 118 | IPC::ResponseBuilder rb{ctx, 2, 0, 0}; |
| 118 | rb.Push(RESULT_SUCCESS); | 119 | rb.Push(RESULT_SUCCESS); |
| 119 | } | 120 | } |
| 120 | 121 | ||
| 121 | void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) { | 122 | void CheckFreeCommunicationPermission(Kernel::HLERequestContext& ctx) { |
| 122 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); | 123 | LOG_WARNING(Service_PCTL, "(STUBBED) called"); |
| 124 | |||
| 123 | IPC::ResponseBuilder rb{ctx, 2}; | 125 | IPC::ResponseBuilder rb{ctx, 2}; |
| 124 | rb.Push(RESULT_SUCCESS); | 126 | rb.Push(RESULT_SUCCESS); |
| 125 | } | 127 | } |
| 126 | }; | 128 | }; |
| 127 | 129 | ||
| 128 | void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { | 130 | void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { |
| 131 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 132 | |||
| 129 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 133 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 130 | rb.Push(RESULT_SUCCESS); | 134 | rb.Push(RESULT_SUCCESS); |
| 131 | rb.PushIpcInterface<IParentalControlService>(); | 135 | rb.PushIpcInterface<IParentalControlService>(); |
| 132 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 133 | } | 136 | } |
| 134 | 137 | ||
| 135 | void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { | 138 | void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { |
| 139 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 140 | |||
| 136 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 141 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 137 | rb.Push(RESULT_SUCCESS); | 142 | rb.Push(RESULT_SUCCESS); |
| 138 | rb.PushIpcInterface<IParentalControlService>(); | 143 | rb.PushIpcInterface<IParentalControlService>(); |
| 139 | LOG_DEBUG(Service_PCTL, "called"); | ||
| 140 | } | 144 | } |
| 141 | 145 | ||
| 142 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | 146 | Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) |
diff --git a/src/core/hle/service/pm/pm.cpp b/src/core/hle/service/pm/pm.cpp index 6ec35ca60..53e7da9c3 100644 --- a/src/core/hle/service/pm/pm.cpp +++ b/src/core/hle/service/pm/pm.cpp | |||
| @@ -20,11 +20,11 @@ public: | |||
| 20 | 20 | ||
| 21 | private: | 21 | private: |
| 22 | void GetBootMode(Kernel::HLERequestContext& ctx) { | 22 | void GetBootMode(Kernel::HLERequestContext& ctx) { |
| 23 | LOG_DEBUG(Service_PM, "called"); | ||
| 24 | |||
| 23 | IPC::ResponseBuilder rb{ctx, 3}; | 25 | IPC::ResponseBuilder rb{ctx, 3}; |
| 24 | rb.Push(RESULT_SUCCESS); | 26 | rb.Push(RESULT_SUCCESS); |
| 25 | rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode | 27 | rb.Push<u32>(static_cast<u32>(SystemBootMode::Normal)); // Normal boot mode |
| 26 | |||
| 27 | LOG_DEBUG(Service_PM, "called"); | ||
| 28 | } | 28 | } |
| 29 | }; | 29 | }; |
| 30 | 30 | ||
diff --git a/src/core/hle/service/psc/psc.cpp b/src/core/hle/service/psc/psc.cpp index bbad870a2..0ba0a4076 100644 --- a/src/core/hle/service/psc/psc.cpp +++ b/src/core/hle/service/psc/psc.cpp | |||
| @@ -61,11 +61,11 @@ public: | |||
| 61 | 61 | ||
| 62 | private: | 62 | private: |
| 63 | void GetPmModule(Kernel::HLERequestContext& ctx) { | 63 | void GetPmModule(Kernel::HLERequestContext& ctx) { |
| 64 | LOG_DEBUG(Service_PSC, "called"); | ||
| 65 | |||
| 64 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 66 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 65 | rb.Push(RESULT_SUCCESS); | 67 | rb.Push(RESULT_SUCCESS); |
| 66 | rb.PushIpcInterface<IPmModule>(); | 68 | rb.PushIpcInterface<IPmModule>(); |
| 67 | |||
| 68 | LOG_DEBUG(Service_PSC, "called"); | ||
| 69 | } | 69 | } |
| 70 | }; | 70 | }; |
| 71 | 71 | ||
diff --git a/src/core/hle/service/set/set.cpp b/src/core/hle/service/set/set.cpp index 9e5af7839..40a9144f9 100644 --- a/src/core/hle/service/set/set.cpp +++ b/src/core/hle/service/set/set.cpp | |||
| @@ -49,38 +49,39 @@ static std::array<LanguageCode, size> MakeLanguageCodeSubset() { | |||
| 49 | static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) { | 49 | static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) { |
| 50 | IPC::ResponseBuilder rb{ctx, 3}; | 50 | IPC::ResponseBuilder rb{ctx, 3}; |
| 51 | rb.Push(RESULT_SUCCESS); | 51 | rb.Push(RESULT_SUCCESS); |
| 52 | if (available_language_codes.size() > max_size) | 52 | if (available_language_codes.size() > max_size) { |
| 53 | rb.Push(static_cast<u32>(max_size)); | 53 | rb.Push(static_cast<u32>(max_size)); |
| 54 | else | 54 | } else { |
| 55 | rb.Push(static_cast<u32>(available_language_codes.size())); | 55 | rb.Push(static_cast<u32>(available_language_codes.size())); |
| 56 | } | ||
| 56 | } | 57 | } |
| 57 | 58 | ||
| 58 | void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { | 59 | void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { |
| 59 | if (available_language_codes.size() > pre4_0_0_max_entries) | 60 | LOG_DEBUG(Service_SET, "called"); |
| 61 | |||
| 62 | if (available_language_codes.size() > pre4_0_0_max_entries) { | ||
| 60 | ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>()); | 63 | ctx.WriteBuffer(MakeLanguageCodeSubset<pre4_0_0_max_entries>()); |
| 61 | else | 64 | } else { |
| 62 | ctx.WriteBuffer(available_language_codes); | 65 | ctx.WriteBuffer(available_language_codes); |
| 63 | 66 | } | |
| 64 | PushResponseLanguageCode(ctx, pre4_0_0_max_entries); | 67 | PushResponseLanguageCode(ctx, pre4_0_0_max_entries); |
| 65 | |||
| 66 | LOG_DEBUG(Service_SET, "called"); | ||
| 67 | } | 68 | } |
| 68 | 69 | ||
| 69 | void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) { | 70 | void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) { |
| 70 | if (available_language_codes.size() > post4_0_0_max_entries) | 71 | LOG_DEBUG(Service_SET, "called"); |
| 72 | |||
| 73 | if (available_language_codes.size() > post4_0_0_max_entries) { | ||
| 71 | ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>()); | 74 | ctx.WriteBuffer(MakeLanguageCodeSubset<post4_0_0_max_entries>()); |
| 72 | else | 75 | } else { |
| 73 | ctx.WriteBuffer(available_language_codes); | 76 | ctx.WriteBuffer(available_language_codes); |
| 74 | 77 | } | |
| 75 | PushResponseLanguageCode(ctx, post4_0_0_max_entries); | 78 | PushResponseLanguageCode(ctx, post4_0_0_max_entries); |
| 76 | |||
| 77 | LOG_DEBUG(Service_SET, "called"); | ||
| 78 | } | 79 | } |
| 79 | 80 | ||
| 80 | void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { | 81 | void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { |
| 81 | PushResponseLanguageCode(ctx, pre4_0_0_max_entries); | ||
| 82 | |||
| 83 | LOG_DEBUG(Service_SET, "called"); | 82 | LOG_DEBUG(Service_SET, "called"); |
| 83 | |||
| 84 | PushResponseLanguageCode(ctx, pre4_0_0_max_entries); | ||
| 84 | } | 85 | } |
| 85 | 86 | ||
| 86 | void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { | 87 | void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { |
| @@ -90,11 +91,11 @@ void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { | |||
| 90 | } | 91 | } |
| 91 | 92 | ||
| 92 | void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) { | 93 | void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) { |
| 94 | LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index); | ||
| 95 | |||
| 93 | IPC::ResponseBuilder rb{ctx, 4}; | 96 | IPC::ResponseBuilder rb{ctx, 4}; |
| 94 | rb.Push(RESULT_SUCCESS); | 97 | rb.Push(RESULT_SUCCESS); |
| 95 | rb.Push(static_cast<u64>(available_language_codes[Settings::values.language_index])); | 98 | rb.Push(static_cast<u64>(available_language_codes[Settings::values.language_index])); |
| 96 | |||
| 97 | LOG_DEBUG(Service_SET, "called {}", Settings::values.language_index); | ||
| 98 | } | 99 | } |
| 99 | 100 | ||
| 100 | SET::SET() : ServiceFramework("set") { | 101 | SET::SET() : ServiceFramework("set") { |
diff --git a/src/core/hle/service/set/set_sys.cpp b/src/core/hle/service/set/set_sys.cpp index 41efca31c..c9b4da5b0 100644 --- a/src/core/hle/service/set/set_sys.cpp +++ b/src/core/hle/service/set/set_sys.cpp | |||
| @@ -10,22 +10,22 @@ | |||
| 10 | namespace Service::Set { | 10 | namespace Service::Set { |
| 11 | 11 | ||
| 12 | void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) { | 12 | void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) { |
| 13 | LOG_DEBUG(Service_SET, "called"); | ||
| 14 | |||
| 13 | IPC::ResponseBuilder rb{ctx, 3}; | 15 | IPC::ResponseBuilder rb{ctx, 3}; |
| 14 | 16 | ||
| 15 | rb.Push(RESULT_SUCCESS); | 17 | rb.Push(RESULT_SUCCESS); |
| 16 | rb.PushEnum(color_set); | 18 | rb.PushEnum(color_set); |
| 17 | |||
| 18 | LOG_DEBUG(Service_SET, "called"); | ||
| 19 | } | 19 | } |
| 20 | 20 | ||
| 21 | void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) { | 21 | void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) { |
| 22 | LOG_DEBUG(Service_SET, "called"); | ||
| 23 | |||
| 22 | IPC::RequestParser rp{ctx}; | 24 | IPC::RequestParser rp{ctx}; |
| 23 | color_set = rp.PopEnum<ColorSet>(); | 25 | color_set = rp.PopEnum<ColorSet>(); |
| 24 | 26 | ||
| 25 | IPC::ResponseBuilder rb{ctx, 2}; | 27 | IPC::ResponseBuilder rb{ctx, 2}; |
| 26 | rb.Push(RESULT_SUCCESS); | 28 | rb.Push(RESULT_SUCCESS); |
| 27 | |||
| 28 | LOG_DEBUG(Service_SET, "called"); | ||
| 29 | } | 29 | } |
| 30 | 30 | ||
| 31 | SET_SYS::SET_SYS() : ServiceFramework("set:sys") { | 31 | SET_SYS::SET_SYS() : ServiceFramework("set:sys") { |
diff --git a/src/core/hle/service/sm/controller.cpp b/src/core/hle/service/sm/controller.cpp index 98f6e4111..74da4d5e6 100644 --- a/src/core/hle/service/sm/controller.cpp +++ b/src/core/hle/service/sm/controller.cpp | |||
| @@ -14,25 +14,26 @@ namespace Service::SM { | |||
| 14 | 14 | ||
| 15 | void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { | 15 | void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { |
| 16 | ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); | 16 | ASSERT_MSG(ctx.Session()->IsSession(), "Session is already a domain"); |
| 17 | LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); | ||
| 17 | ctx.Session()->ConvertToDomain(); | 18 | ctx.Session()->ConvertToDomain(); |
| 18 | 19 | ||
| 19 | IPC::ResponseBuilder rb{ctx, 3}; | 20 | IPC::ResponseBuilder rb{ctx, 3}; |
| 20 | rb.Push(RESULT_SUCCESS); | 21 | rb.Push(RESULT_SUCCESS); |
| 21 | rb.Push<u32>(1); // Converted sessions start with 1 request handler | 22 | rb.Push<u32>(1); // Converted sessions start with 1 request handler |
| 22 | |||
| 23 | LOG_DEBUG(Service, "called, server_session={}", ctx.Session()->GetObjectId()); | ||
| 24 | } | 23 | } |
| 25 | 24 | ||
| 26 | void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { | 25 | void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { |
| 27 | // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong | 26 | // TODO(bunnei): This is just creating a new handle to the same Session. I assume this is wrong |
| 28 | // and that we probably want to actually make an entirely new Session, but we still need to | 27 | // and that we probably want to actually make an entirely new Session, but we still need to |
| 29 | // verify this on hardware. | 28 | // verify this on hardware. |
| 29 | LOG_DEBUG(Service, "called"); | ||
| 30 | |||
| 30 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | 31 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; |
| 31 | rb.Push(RESULT_SUCCESS); | 32 | rb.Push(RESULT_SUCCESS); |
| 32 | Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client}; | 33 | Kernel::SharedPtr<Kernel::ClientSession> session{ctx.Session()->parent->client}; |
| 33 | rb.PushMoveObjects(session); | 34 | rb.PushMoveObjects(session); |
| 34 | 35 | ||
| 35 | LOG_DEBUG(Service, "called, session={}", session->GetObjectId()); | 36 | LOG_DEBUG(Service, "session={}", session->GetObjectId()); |
| 36 | } | 37 | } |
| 37 | 38 | ||
| 38 | void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { | 39 | void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { |
| @@ -42,11 +43,11 @@ void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { | |||
| 42 | } | 43 | } |
| 43 | 44 | ||
| 44 | void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { | 45 | void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { |
| 46 | LOG_WARNING(Service, "(STUBBED) called"); | ||
| 47 | |||
| 45 | IPC::ResponseBuilder rb{ctx, 3}; | 48 | IPC::ResponseBuilder rb{ctx, 3}; |
| 46 | rb.Push(RESULT_SUCCESS); | 49 | rb.Push(RESULT_SUCCESS); |
| 47 | rb.Push<u16>(0x500); | 50 | rb.Push<u16>(0x500); |
| 48 | |||
| 49 | LOG_WARNING(Service, "(STUBBED) called"); | ||
| 50 | } | 51 | } |
| 51 | 52 | ||
| 52 | Controller::Controller() : ServiceFramework("IpcController") { | 53 | Controller::Controller() : ServiceFramework("IpcController") { |
diff --git a/src/core/hle/service/sm/sm.cpp b/src/core/hle/service/sm/sm.cpp index 464e79d01..0d0f63a78 100644 --- a/src/core/hle/service/sm/sm.cpp +++ b/src/core/hle/service/sm/sm.cpp | |||
| @@ -63,6 +63,17 @@ ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> ServiceManager::RegisterService | |||
| 63 | return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); | 63 | return MakeResult<Kernel::SharedPtr<Kernel::ServerPort>>(std::move(server_port)); |
| 64 | } | 64 | } |
| 65 | 65 | ||
| 66 | ResultCode ServiceManager::UnregisterService(const std::string& name) { | ||
| 67 | CASCADE_CODE(ValidateServiceName(name)); | ||
| 68 | |||
| 69 | const auto iter = registered_services.find(name); | ||
| 70 | if (iter == registered_services.end()) | ||
| 71 | return ERR_SERVICE_NOT_REGISTERED; | ||
| 72 | |||
| 73 | registered_services.erase(iter); | ||
| 74 | return RESULT_SUCCESS; | ||
| 75 | } | ||
| 76 | |||
| 66 | ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( | 77 | ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( |
| 67 | const std::string& name) { | 78 | const std::string& name) { |
| 68 | 79 | ||
| @@ -92,9 +103,10 @@ SM::~SM() = default; | |||
| 92 | * 0: ResultCode | 103 | * 0: ResultCode |
| 93 | */ | 104 | */ |
| 94 | void SM::Initialize(Kernel::HLERequestContext& ctx) { | 105 | void SM::Initialize(Kernel::HLERequestContext& ctx) { |
| 106 | LOG_DEBUG(Service_SM, "called"); | ||
| 107 | |||
| 95 | IPC::ResponseBuilder rb{ctx, 2}; | 108 | IPC::ResponseBuilder rb{ctx, 2}; |
| 96 | rb.Push(RESULT_SUCCESS); | 109 | rb.Push(RESULT_SUCCESS); |
| 97 | LOG_DEBUG(Service_SM, "called"); | ||
| 98 | } | 110 | } |
| 99 | 111 | ||
| 100 | void SM::GetService(Kernel::HLERequestContext& ctx) { | 112 | void SM::GetService(Kernel::HLERequestContext& ctx) { |
| @@ -127,13 +139,53 @@ void SM::GetService(Kernel::HLERequestContext& ctx) { | |||
| 127 | } | 139 | } |
| 128 | } | 140 | } |
| 129 | 141 | ||
| 142 | void SM::RegisterService(Kernel::HLERequestContext& ctx) { | ||
| 143 | IPC::RequestParser rp{ctx}; | ||
| 144 | |||
| 145 | const auto name_buf = rp.PopRaw<std::array<char, 8>>(); | ||
| 146 | const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | ||
| 147 | |||
| 148 | const std::string name(name_buf.begin(), end); | ||
| 149 | |||
| 150 | const auto unk_bool = static_cast<bool>(rp.PopRaw<u32>()); | ||
| 151 | const auto session_count = rp.PopRaw<u32>(); | ||
| 152 | |||
| 153 | LOG_DEBUG(Service_SM, "called with unk_bool={}", unk_bool); | ||
| 154 | |||
| 155 | auto handle = service_manager->RegisterService(name, session_count); | ||
| 156 | if (handle.Failed()) { | ||
| 157 | LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", | ||
| 158 | handle.Code().raw); | ||
| 159 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 160 | rb.Push(handle.Code()); | ||
| 161 | return; | ||
| 162 | } | ||
| 163 | |||
| 164 | IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; | ||
| 165 | rb.Push(handle.Code()); | ||
| 166 | rb.PushMoveObjects(std::move(handle).Unwrap()); | ||
| 167 | } | ||
| 168 | |||
| 169 | void SM::UnregisterService(Kernel::HLERequestContext& ctx) { | ||
| 170 | IPC::RequestParser rp{ctx}; | ||
| 171 | |||
| 172 | const auto name_buf = rp.PopRaw<std::array<char, 8>>(); | ||
| 173 | const auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | ||
| 174 | |||
| 175 | const std::string name(name_buf.begin(), end); | ||
| 176 | LOG_DEBUG(Service_SM, "called with name={}", name); | ||
| 177 | |||
| 178 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 179 | rb.Push(service_manager->UnregisterService(name)); | ||
| 180 | } | ||
| 181 | |||
| 130 | SM::SM(std::shared_ptr<ServiceManager> service_manager) | 182 | SM::SM(std::shared_ptr<ServiceManager> service_manager) |
| 131 | : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) { | 183 | : ServiceFramework("sm:", 4), service_manager(std::move(service_manager)) { |
| 132 | static const FunctionInfo functions[] = { | 184 | static const FunctionInfo functions[] = { |
| 133 | {0x00000000, &SM::Initialize, "Initialize"}, | 185 | {0x00000000, &SM::Initialize, "Initialize"}, |
| 134 | {0x00000001, &SM::GetService, "GetService"}, | 186 | {0x00000001, &SM::GetService, "GetService"}, |
| 135 | {0x00000002, nullptr, "RegisterService"}, | 187 | {0x00000002, &SM::RegisterService, "RegisterService"}, |
| 136 | {0x00000003, nullptr, "UnregisterService"}, | 188 | {0x00000003, &SM::UnregisterService, "UnregisterService"}, |
| 137 | }; | 189 | }; |
| 138 | RegisterHandlers(functions); | 190 | RegisterHandlers(functions); |
| 139 | } | 191 | } |
diff --git a/src/core/hle/service/sm/sm.h b/src/core/hle/service/sm/sm.h index 4f8145dda..bef25433e 100644 --- a/src/core/hle/service/sm/sm.h +++ b/src/core/hle/service/sm/sm.h | |||
| @@ -35,6 +35,8 @@ public: | |||
| 35 | private: | 35 | private: |
| 36 | void Initialize(Kernel::HLERequestContext& ctx); | 36 | void Initialize(Kernel::HLERequestContext& ctx); |
| 37 | void GetService(Kernel::HLERequestContext& ctx); | 37 | void GetService(Kernel::HLERequestContext& ctx); |
| 38 | void RegisterService(Kernel::HLERequestContext& ctx); | ||
| 39 | void UnregisterService(Kernel::HLERequestContext& ctx); | ||
| 38 | 40 | ||
| 39 | std::shared_ptr<ServiceManager> service_manager; | 41 | std::shared_ptr<ServiceManager> service_manager; |
| 40 | }; | 42 | }; |
| @@ -48,6 +50,7 @@ public: | |||
| 48 | 50 | ||
| 49 | ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, | 51 | ResultVal<Kernel::SharedPtr<Kernel::ServerPort>> RegisterService(std::string name, |
| 50 | unsigned int max_sessions); | 52 | unsigned int max_sessions); |
| 53 | ResultCode UnregisterService(const std::string& name); | ||
| 51 | ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); | 54 | ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> GetServicePort(const std::string& name); |
| 52 | ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); | 55 | ResultVal<Kernel::SharedPtr<Kernel::ClientSession>> ConnectToService(const std::string& name); |
| 53 | 56 | ||
diff --git a/src/core/hle/service/spl/module.cpp b/src/core/hle/service/spl/module.cpp index b2de2a818..8db0c2f13 100644 --- a/src/core/hle/service/spl/module.cpp +++ b/src/core/hle/service/spl/module.cpp | |||
| @@ -24,6 +24,8 @@ Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) | |||
| 24 | Module::Interface::~Interface() = default; | 24 | Module::Interface::~Interface() = default; |
| 25 | 25 | ||
| 26 | void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { | 26 | void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { |
| 27 | LOG_DEBUG(Service_SPL, "called"); | ||
| 28 | |||
| 27 | IPC::RequestParser rp{ctx}; | 29 | IPC::RequestParser rp{ctx}; |
| 28 | 30 | ||
| 29 | std::size_t size = ctx.GetWriteBufferSize(); | 31 | std::size_t size = ctx.GetWriteBufferSize(); |
| @@ -36,7 +38,6 @@ void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { | |||
| 36 | 38 | ||
| 37 | IPC::ResponseBuilder rb{ctx, 2}; | 39 | IPC::ResponseBuilder rb{ctx, 2}; |
| 38 | rb.Push(RESULT_SUCCESS); | 40 | rb.Push(RESULT_SUCCESS); |
| 39 | LOG_DEBUG(Service_SPL, "called"); | ||
| 40 | } | 41 | } |
| 41 | 42 | ||
| 42 | void InstallInterfaces(SM::ServiceManager& service_manager) { | 43 | void InstallInterfaces(SM::ServiceManager& service_manager) { |
diff --git a/src/core/hle/service/ssl/ssl.cpp b/src/core/hle/service/ssl/ssl.cpp index bc4f7a437..af40a1815 100644 --- a/src/core/hle/service/ssl/ssl.cpp +++ b/src/core/hle/service/ssl/ssl.cpp | |||
| @@ -69,6 +69,7 @@ public: | |||
| 69 | private: | 69 | private: |
| 70 | void SetOption(Kernel::HLERequestContext& ctx) { | 70 | void SetOption(Kernel::HLERequestContext& ctx) { |
| 71 | LOG_WARNING(Service_SSL, "(STUBBED) called"); | 71 | LOG_WARNING(Service_SSL, "(STUBBED) called"); |
| 72 | |||
| 72 | IPC::RequestParser rp{ctx}; | 73 | IPC::RequestParser rp{ctx}; |
| 73 | 74 | ||
| 74 | IPC::ResponseBuilder rb{ctx, 2}; | 75 | IPC::ResponseBuilder rb{ctx, 2}; |
| @@ -114,6 +115,7 @@ private: | |||
| 114 | 115 | ||
| 115 | void SetInterfaceVersion(Kernel::HLERequestContext& ctx) { | 116 | void SetInterfaceVersion(Kernel::HLERequestContext& ctx) { |
| 116 | LOG_DEBUG(Service_SSL, "called"); | 117 | LOG_DEBUG(Service_SSL, "called"); |
| 118 | |||
| 117 | IPC::RequestParser rp{ctx}; | 119 | IPC::RequestParser rp{ctx}; |
| 118 | ssl_version = rp.Pop<u32>(); | 120 | ssl_version = rp.Pop<u32>(); |
| 119 | 121 | ||
diff --git a/src/core/hle/service/time/time.cpp b/src/core/hle/service/time/time.cpp index e561a0c52..60b201d06 100644 --- a/src/core/hle/service/time/time.cpp +++ b/src/core/hle/service/time/time.cpp | |||
| @@ -72,6 +72,7 @@ private: | |||
| 72 | std::chrono::system_clock::now().time_since_epoch()) | 72 | std::chrono::system_clock::now().time_since_epoch()) |
| 73 | .count()}; | 73 | .count()}; |
| 74 | LOG_DEBUG(Service_Time, "called"); | 74 | LOG_DEBUG(Service_Time, "called"); |
| 75 | |||
| 75 | IPC::ResponseBuilder rb{ctx, 4}; | 76 | IPC::ResponseBuilder rb{ctx, 4}; |
| 76 | rb.Push(RESULT_SUCCESS); | 77 | rb.Push(RESULT_SUCCESS); |
| 77 | rb.Push<u64>(time_since_epoch); | 78 | rb.Push<u64>(time_since_epoch); |
| @@ -79,6 +80,7 @@ private: | |||
| 79 | 80 | ||
| 80 | void GetSystemClockContext(Kernel::HLERequestContext& ctx) { | 81 | void GetSystemClockContext(Kernel::HLERequestContext& ctx) { |
| 81 | LOG_WARNING(Service_Time, "(STUBBED) called"); | 82 | LOG_WARNING(Service_Time, "(STUBBED) called"); |
| 83 | |||
| 82 | SystemClockContext system_clock_ontext{}; | 84 | SystemClockContext system_clock_ontext{}; |
| 83 | IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2}; | 85 | IPC::ResponseBuilder rb{ctx, (sizeof(SystemClockContext) / 4) + 2}; |
| 84 | rb.Push(RESULT_SUCCESS); | 86 | rb.Push(RESULT_SUCCESS); |
| @@ -98,6 +100,7 @@ public: | |||
| 98 | private: | 100 | private: |
| 99 | void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { | 101 | void GetCurrentTimePoint(Kernel::HLERequestContext& ctx) { |
| 100 | LOG_DEBUG(Service_Time, "called"); | 102 | LOG_DEBUG(Service_Time, "called"); |
| 103 | |||
| 101 | SteadyClockTimePoint steady_clock_time_point{ | 104 | SteadyClockTimePoint steady_clock_time_point{ |
| 102 | CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000}; | 105 | CoreTiming::cyclesToMs(CoreTiming::GetTicks()) / 1000}; |
| 103 | IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; | 106 | IPC::ResponseBuilder rb{ctx, (sizeof(SteadyClockTimePoint) / 4) + 2}; |
| @@ -130,6 +133,7 @@ private: | |||
| 130 | 133 | ||
| 131 | void GetDeviceLocationName(Kernel::HLERequestContext& ctx) { | 134 | void GetDeviceLocationName(Kernel::HLERequestContext& ctx) { |
| 132 | LOG_DEBUG(Service_Time, "called"); | 135 | LOG_DEBUG(Service_Time, "called"); |
| 136 | |||
| 133 | IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2}; | 137 | IPC::ResponseBuilder rb{ctx, (sizeof(LocationName) / 4) + 2}; |
| 134 | rb.Push(RESULT_SUCCESS); | 138 | rb.Push(RESULT_SUCCESS); |
| 135 | rb.PushRaw(location_name); | 139 | rb.PushRaw(location_name); |
| @@ -137,6 +141,7 @@ private: | |||
| 137 | 141 | ||
| 138 | void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) { | 142 | void GetTotalLocationNameCount(Kernel::HLERequestContext& ctx) { |
| 139 | LOG_WARNING(Service_Time, "(STUBBED) called"); | 143 | LOG_WARNING(Service_Time, "(STUBBED) called"); |
| 144 | |||
| 140 | IPC::ResponseBuilder rb{ctx, 3}; | 145 | IPC::ResponseBuilder rb{ctx, 3}; |
| 141 | rb.Push(RESULT_SUCCESS); | 146 | rb.Push(RESULT_SUCCESS); |
| 142 | rb.Push<u32>(0); | 147 | rb.Push<u32>(0); |
| @@ -154,7 +159,6 @@ private: | |||
| 154 | void ToCalendarTime(Kernel::HLERequestContext& ctx) { | 159 | void ToCalendarTime(Kernel::HLERequestContext& ctx) { |
| 155 | IPC::RequestParser rp{ctx}; | 160 | IPC::RequestParser rp{ctx}; |
| 156 | const u64 posix_time = rp.Pop<u64>(); | 161 | const u64 posix_time = rp.Pop<u64>(); |
| 157 | |||
| 158 | LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); | 162 | LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); |
| 159 | 163 | ||
| 160 | TimeZoneRule time_zone_rule{}; | 164 | TimeZoneRule time_zone_rule{}; |
| @@ -175,7 +179,6 @@ private: | |||
| 175 | void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) { | 179 | void ToCalendarTimeWithMyRule(Kernel::HLERequestContext& ctx) { |
| 176 | IPC::RequestParser rp{ctx}; | 180 | IPC::RequestParser rp{ctx}; |
| 177 | const u64 posix_time = rp.Pop<u64>(); | 181 | const u64 posix_time = rp.Pop<u64>(); |
| 178 | |||
| 179 | LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); | 182 | LOG_WARNING(Service_Time, "(STUBBED) called, posix_time=0x{:016X}", posix_time); |
| 180 | 183 | ||
| 181 | CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; | 184 | CalendarTime calendar_time{2018, 1, 1, 0, 0, 0}; |
| @@ -192,6 +195,7 @@ private: | |||
| 192 | void ToPosixTime(Kernel::HLERequestContext& ctx) { | 195 | void ToPosixTime(Kernel::HLERequestContext& ctx) { |
| 193 | // TODO(ogniK): Figure out how to handle multiple times | 196 | // TODO(ogniK): Figure out how to handle multiple times |
| 194 | LOG_WARNING(Service_Time, "(STUBBED) called"); | 197 | LOG_WARNING(Service_Time, "(STUBBED) called"); |
| 198 | |||
| 195 | IPC::RequestParser rp{ctx}; | 199 | IPC::RequestParser rp{ctx}; |
| 196 | auto calendar_time = rp.PopRaw<CalendarTime>(); | 200 | auto calendar_time = rp.PopRaw<CalendarTime>(); |
| 197 | auto posix_time = CalendarToPosix(calendar_time, {}); | 201 | auto posix_time = CalendarToPosix(calendar_time, {}); |
| @@ -204,6 +208,7 @@ private: | |||
| 204 | 208 | ||
| 205 | void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) { | 209 | void ToPosixTimeWithMyRule(Kernel::HLERequestContext& ctx) { |
| 206 | LOG_WARNING(Service_Time, "(STUBBED) called"); | 210 | LOG_WARNING(Service_Time, "(STUBBED) called"); |
| 211 | |||
| 207 | IPC::RequestParser rp{ctx}; | 212 | IPC::RequestParser rp{ctx}; |
| 208 | auto calendar_time = rp.PopRaw<CalendarTime>(); | 213 | auto calendar_time = rp.PopRaw<CalendarTime>(); |
| 209 | auto posix_time = CalendarToPosix(calendar_time, {}); | 214 | auto posix_time = CalendarToPosix(calendar_time, {}); |
| @@ -216,38 +221,43 @@ private: | |||
| 216 | }; | 221 | }; |
| 217 | 222 | ||
| 218 | void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) { | 223 | void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) { |
| 224 | LOG_DEBUG(Service_Time, "called"); | ||
| 225 | |||
| 219 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 226 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 220 | rb.Push(RESULT_SUCCESS); | 227 | rb.Push(RESULT_SUCCESS); |
| 221 | rb.PushIpcInterface<ISystemClock>(); | 228 | rb.PushIpcInterface<ISystemClock>(); |
| 222 | LOG_DEBUG(Service_Time, "called"); | ||
| 223 | } | 229 | } |
| 224 | 230 | ||
| 225 | void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { | 231 | void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { |
| 232 | LOG_DEBUG(Service_Time, "called"); | ||
| 233 | |||
| 226 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 234 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 227 | rb.Push(RESULT_SUCCESS); | 235 | rb.Push(RESULT_SUCCESS); |
| 228 | rb.PushIpcInterface<ISystemClock>(); | 236 | rb.PushIpcInterface<ISystemClock>(); |
| 229 | LOG_DEBUG(Service_Time, "called"); | ||
| 230 | } | 237 | } |
| 231 | 238 | ||
| 232 | void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { | 239 | void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { |
| 240 | LOG_DEBUG(Service_Time, "called"); | ||
| 241 | |||
| 233 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 242 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 234 | rb.Push(RESULT_SUCCESS); | 243 | rb.Push(RESULT_SUCCESS); |
| 235 | rb.PushIpcInterface<ISteadyClock>(); | 244 | rb.PushIpcInterface<ISteadyClock>(); |
| 236 | LOG_DEBUG(Service_Time, "called"); | ||
| 237 | } | 245 | } |
| 238 | 246 | ||
| 239 | void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { | 247 | void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { |
| 248 | LOG_DEBUG(Service_Time, "called"); | ||
| 249 | |||
| 240 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 250 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 241 | rb.Push(RESULT_SUCCESS); | 251 | rb.Push(RESULT_SUCCESS); |
| 242 | rb.PushIpcInterface<ITimeZoneService>(); | 252 | rb.PushIpcInterface<ITimeZoneService>(); |
| 243 | LOG_DEBUG(Service_Time, "called"); | ||
| 244 | } | 253 | } |
| 245 | 254 | ||
| 246 | void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { | 255 | void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { |
| 256 | LOG_DEBUG(Service_Time, "called"); | ||
| 257 | |||
| 247 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 258 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 248 | rb.Push(RESULT_SUCCESS); | 259 | rb.Push(RESULT_SUCCESS); |
| 249 | rb.PushIpcInterface<ISystemClock>(); | 260 | rb.PushIpcInterface<ISystemClock>(); |
| 250 | LOG_DEBUG(Service_Time, "called"); | ||
| 251 | } | 261 | } |
| 252 | 262 | ||
| 253 | void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { | 263 | void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { |
| @@ -265,6 +275,7 @@ void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { | |||
| 265 | const std::time_t time(time_since_epoch); | 275 | const std::time_t time(time_since_epoch); |
| 266 | const std::tm* tm = std::localtime(&time); | 276 | const std::tm* tm = std::localtime(&time); |
| 267 | if (tm == nullptr) { | 277 | if (tm == nullptr) { |
| 278 | LOG_ERROR(Service_Time, "tm is a nullptr"); | ||
| 268 | IPC::ResponseBuilder rb{ctx, 2}; | 279 | IPC::ResponseBuilder rb{ctx, 2}; |
| 269 | rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code | 280 | rb.Push(ResultCode(-1)); // TODO(ogniK): Find appropriate error code |
| 270 | return; | 281 | return; |
diff --git a/src/core/hle/service/usb/usb.cpp b/src/core/hle/service/usb/usb.cpp index f0a831d45..f082a63bc 100644 --- a/src/core/hle/service/usb/usb.cpp +++ b/src/core/hle/service/usb/usb.cpp | |||
| @@ -159,11 +159,11 @@ public: | |||
| 159 | 159 | ||
| 160 | private: | 160 | private: |
| 161 | void GetPdSession(Kernel::HLERequestContext& ctx) { | 161 | void GetPdSession(Kernel::HLERequestContext& ctx) { |
| 162 | LOG_DEBUG(Service_USB, "called"); | ||
| 163 | |||
| 162 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; | 164 | IPC::ResponseBuilder rb{ctx, 2, 0, 1}; |
| 163 | rb.Push(RESULT_SUCCESS); | 165 | rb.Push(RESULT_SUCCESS); |
| 164 | rb.PushIpcInterface<IPdSession>(); | 166 | rb.PushIpcInterface<IPdSession>(); |
| 165 | |||
| 166 | LOG_DEBUG(Service_USB, "called"); | ||
| 167 | } | 167 | } |
| 168 | }; | 168 | }; |
| 169 | 169 | ||
diff --git a/src/core/hle/service/vi/vi.cpp b/src/core/hle/service/vi/vi.cpp index d25fdb1fe..5120abfff 100644 --- a/src/core/hle/service/vi/vi.cpp +++ b/src/core/hle/service/vi/vi.cpp | |||
| @@ -504,13 +504,17 @@ private: | |||
| 504 | u32 id = rp.Pop<u32>(); | 504 | u32 id = rp.Pop<u32>(); |
| 505 | auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); | 505 | auto transaction = static_cast<TransactionId>(rp.Pop<u32>()); |
| 506 | u32 flags = rp.Pop<u32>(); | 506 | u32 flags = rp.Pop<u32>(); |
| 507 | auto buffer_queue = nv_flinger->GetBufferQueue(id); | ||
| 508 | |||
| 509 | LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction)); | 507 | LOG_DEBUG(Service_VI, "called, transaction={:X}", static_cast<u32>(transaction)); |
| 510 | 508 | ||
| 509 | auto buffer_queue = nv_flinger->GetBufferQueue(id); | ||
| 510 | |||
| 511 | if (transaction == TransactionId::Connect) { | 511 | if (transaction == TransactionId::Connect) { |
| 512 | IGBPConnectRequestParcel request{ctx.ReadBuffer()}; | 512 | IGBPConnectRequestParcel request{ctx.ReadBuffer()}; |
| 513 | IGBPConnectResponseParcel response{1280, 720}; | 513 | IGBPConnectResponseParcel response{ |
| 514 | static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedWidth) * | ||
| 515 | Settings::values.resolution_factor), | ||
| 516 | static_cast<u32>(static_cast<u32>(DisplayResolution::UndockedHeight) * | ||
| 517 | Settings::values.resolution_factor)}; | ||
| 514 | ctx.WriteBuffer(response.Serialize()); | 518 | ctx.WriteBuffer(response.Serialize()); |
| 515 | } else if (transaction == TransactionId::SetPreallocatedBuffer) { | 519 | } else if (transaction == TransactionId::SetPreallocatedBuffer) { |
| 516 | IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; | 520 | IGBPSetPreallocatedBufferRequestParcel request{ctx.ReadBuffer()}; |
| @@ -589,9 +593,9 @@ private: | |||
| 589 | u32 id = rp.Pop<u32>(); | 593 | u32 id = rp.Pop<u32>(); |
| 590 | s32 addval = rp.PopRaw<s32>(); | 594 | s32 addval = rp.PopRaw<s32>(); |
| 591 | u32 type = rp.Pop<u32>(); | 595 | u32 type = rp.Pop<u32>(); |
| 592 | |||
| 593 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval, | 596 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, addval={:08X}, type={:08X}", id, addval, |
| 594 | type); | 597 | type); |
| 598 | |||
| 595 | IPC::ResponseBuilder rb{ctx, 2}; | 599 | IPC::ResponseBuilder rb{ctx, 2}; |
| 596 | rb.Push(RESULT_SUCCESS); | 600 | rb.Push(RESULT_SUCCESS); |
| 597 | } | 601 | } |
| @@ -600,12 +604,11 @@ private: | |||
| 600 | IPC::RequestParser rp{ctx}; | 604 | IPC::RequestParser rp{ctx}; |
| 601 | u32 id = rp.Pop<u32>(); | 605 | u32 id = rp.Pop<u32>(); |
| 602 | u32 unknown = rp.Pop<u32>(); | 606 | u32 unknown = rp.Pop<u32>(); |
| 607 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); | ||
| 603 | 608 | ||
| 604 | auto buffer_queue = nv_flinger->GetBufferQueue(id); | 609 | auto buffer_queue = nv_flinger->GetBufferQueue(id); |
| 605 | 610 | ||
| 606 | // TODO(Subv): Find out what this actually is. | 611 | // TODO(Subv): Find out what this actually is. |
| 607 | |||
| 608 | LOG_WARNING(Service_VI, "(STUBBED) called id={}, unknown={:08X}", id, unknown); | ||
| 609 | IPC::ResponseBuilder rb{ctx, 2, 1}; | 612 | IPC::ResponseBuilder rb{ctx, 2, 1}; |
| 610 | rb.Push(RESULT_SUCCESS); | 613 | rb.Push(RESULT_SUCCESS); |
| 611 | rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent()); | 614 | rb.PushCopyObjects(buffer_queue->GetBufferWaitEvent()); |
| @@ -669,6 +672,7 @@ public: | |||
| 669 | private: | 672 | private: |
| 670 | void SetLayerZ(Kernel::HLERequestContext& ctx) { | 673 | void SetLayerZ(Kernel::HLERequestContext& ctx) { |
| 671 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 674 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 675 | |||
| 672 | IPC::RequestParser rp{ctx}; | 676 | IPC::RequestParser rp{ctx}; |
| 673 | u64 layer_id = rp.Pop<u64>(); | 677 | u64 layer_id = rp.Pop<u64>(); |
| 674 | u64 z_value = rp.Pop<u64>(); | 678 | u64 z_value = rp.Pop<u64>(); |
| @@ -681,28 +685,33 @@ private: | |||
| 681 | IPC::RequestParser rp{ctx}; | 685 | IPC::RequestParser rp{ctx}; |
| 682 | u64 layer_id = rp.Pop<u64>(); | 686 | u64 layer_id = rp.Pop<u64>(); |
| 683 | bool visibility = rp.Pop<bool>(); | 687 | bool visibility = rp.Pop<bool>(); |
| 684 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 685 | rb.Push(RESULT_SUCCESS); | ||
| 686 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, | 688 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:08X}, visibility={}", layer_id, |
| 687 | visibility); | 689 | visibility); |
| 690 | |||
| 691 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 692 | rb.Push(RESULT_SUCCESS); | ||
| 688 | } | 693 | } |
| 689 | 694 | ||
| 690 | void GetDisplayMode(Kernel::HLERequestContext& ctx) { | 695 | void GetDisplayMode(Kernel::HLERequestContext& ctx) { |
| 696 | LOG_WARNING(Service_VI, "(STUBBED) called"); | ||
| 697 | |||
| 691 | IPC::ResponseBuilder rb{ctx, 6}; | 698 | IPC::ResponseBuilder rb{ctx, 6}; |
| 692 | rb.Push(RESULT_SUCCESS); | 699 | rb.Push(RESULT_SUCCESS); |
| 693 | 700 | ||
| 694 | if (Settings::values.use_docked_mode) { | 701 | if (Settings::values.use_docked_mode) { |
| 695 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth)); | 702 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedWidth) * |
| 696 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight)); | 703 | static_cast<u32>(Settings::values.resolution_factor)); |
| 704 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::DockedHeight) * | ||
| 705 | static_cast<u32>(Settings::values.resolution_factor)); | ||
| 697 | } else { | 706 | } else { |
| 698 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth)); | 707 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedWidth) * |
| 699 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight)); | 708 | static_cast<u32>(Settings::values.resolution_factor)); |
| 709 | rb.Push(static_cast<u32>(Service::VI::DisplayResolution::UndockedHeight) * | ||
| 710 | static_cast<u32>(Settings::values.resolution_factor)); | ||
| 700 | } | 711 | } |
| 701 | 712 | ||
| 702 | rb.PushRaw<float>(60.0f); | 713 | rb.PushRaw<float>(60.0f); // This wouldn't seem to be correct for 30 fps games. |
| 703 | rb.Push<u32>(0); | 714 | rb.Push<u32>(0); |
| 704 | |||
| 705 | LOG_DEBUG(Service_VI, "called"); | ||
| 706 | } | 715 | } |
| 707 | }; | 716 | }; |
| 708 | 717 | ||
| @@ -785,6 +794,7 @@ public: | |||
| 785 | private: | 794 | private: |
| 786 | void CloseDisplay(Kernel::HLERequestContext& ctx) { | 795 | void CloseDisplay(Kernel::HLERequestContext& ctx) { |
| 787 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 796 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 797 | |||
| 788 | IPC::RequestParser rp{ctx}; | 798 | IPC::RequestParser rp{ctx}; |
| 789 | u64 display = rp.Pop<u64>(); | 799 | u64 display = rp.Pop<u64>(); |
| 790 | 800 | ||
| @@ -794,6 +804,7 @@ private: | |||
| 794 | 804 | ||
| 795 | void CreateManagedLayer(Kernel::HLERequestContext& ctx) { | 805 | void CreateManagedLayer(Kernel::HLERequestContext& ctx) { |
| 796 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 806 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 807 | |||
| 797 | IPC::RequestParser rp{ctx}; | 808 | IPC::RequestParser rp{ctx}; |
| 798 | u32 unknown = rp.Pop<u32>(); | 809 | u32 unknown = rp.Pop<u32>(); |
| 799 | rp.Skip(1, false); | 810 | rp.Skip(1, false); |
| @@ -809,6 +820,7 @@ private: | |||
| 809 | 820 | ||
| 810 | void AddToLayerStack(Kernel::HLERequestContext& ctx) { | 821 | void AddToLayerStack(Kernel::HLERequestContext& ctx) { |
| 811 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 822 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 823 | |||
| 812 | IPC::RequestParser rp{ctx}; | 824 | IPC::RequestParser rp{ctx}; |
| 813 | u32 stack = rp.Pop<u32>(); | 825 | u32 stack = rp.Pop<u32>(); |
| 814 | u64 layer_id = rp.Pop<u64>(); | 826 | u64 layer_id = rp.Pop<u64>(); |
| @@ -821,10 +833,11 @@ private: | |||
| 821 | IPC::RequestParser rp{ctx}; | 833 | IPC::RequestParser rp{ctx}; |
| 822 | u64 layer_id = rp.Pop<u64>(); | 834 | u64 layer_id = rp.Pop<u64>(); |
| 823 | bool visibility = rp.Pop<bool>(); | 835 | bool visibility = rp.Pop<bool>(); |
| 824 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 825 | rb.Push(RESULT_SUCCESS); | ||
| 826 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, | 836 | LOG_WARNING(Service_VI, "(STUBBED) called, layer_id=0x{:X}, visibility={}", layer_id, |
| 827 | visibility); | 837 | visibility); |
| 838 | |||
| 839 | IPC::ResponseBuilder rb{ctx, 2}; | ||
| 840 | rb.Push(RESULT_SUCCESS); | ||
| 828 | } | 841 | } |
| 829 | 842 | ||
| 830 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; | 843 | std::shared_ptr<NVFlinger::NVFlinger> nv_flinger; |
| @@ -870,6 +883,7 @@ private: | |||
| 870 | 883 | ||
| 871 | void OpenDisplay(Kernel::HLERequestContext& ctx) { | 884 | void OpenDisplay(Kernel::HLERequestContext& ctx) { |
| 872 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 885 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 886 | |||
| 873 | IPC::RequestParser rp{ctx}; | 887 | IPC::RequestParser rp{ctx}; |
| 874 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); | 888 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); |
| 875 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | 889 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); |
| @@ -885,6 +899,7 @@ private: | |||
| 885 | 899 | ||
| 886 | void CloseDisplay(Kernel::HLERequestContext& ctx) { | 900 | void CloseDisplay(Kernel::HLERequestContext& ctx) { |
| 887 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 901 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 902 | |||
| 888 | IPC::RequestParser rp{ctx}; | 903 | IPC::RequestParser rp{ctx}; |
| 889 | u64 display_id = rp.Pop<u64>(); | 904 | u64 display_id = rp.Pop<u64>(); |
| 890 | 905 | ||
| @@ -894,6 +909,7 @@ private: | |||
| 894 | 909 | ||
| 895 | void GetDisplayResolution(Kernel::HLERequestContext& ctx) { | 910 | void GetDisplayResolution(Kernel::HLERequestContext& ctx) { |
| 896 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 911 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 912 | |||
| 897 | IPC::RequestParser rp{ctx}; | 913 | IPC::RequestParser rp{ctx}; |
| 898 | u64 display_id = rp.Pop<u64>(); | 914 | u64 display_id = rp.Pop<u64>(); |
| 899 | 915 | ||
| @@ -901,16 +917,21 @@ private: | |||
| 901 | rb.Push(RESULT_SUCCESS); | 917 | rb.Push(RESULT_SUCCESS); |
| 902 | 918 | ||
| 903 | if (Settings::values.use_docked_mode) { | 919 | if (Settings::values.use_docked_mode) { |
| 904 | rb.Push(static_cast<u64>(DisplayResolution::DockedWidth)); | 920 | rb.Push(static_cast<u64>(DisplayResolution::DockedWidth) * |
| 905 | rb.Push(static_cast<u64>(DisplayResolution::DockedHeight)); | 921 | static_cast<u32>(Settings::values.resolution_factor)); |
| 922 | rb.Push(static_cast<u64>(DisplayResolution::DockedHeight) * | ||
| 923 | static_cast<u32>(Settings::values.resolution_factor)); | ||
| 906 | } else { | 924 | } else { |
| 907 | rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth)); | 925 | rb.Push(static_cast<u64>(DisplayResolution::UndockedWidth) * |
| 908 | rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight)); | 926 | static_cast<u32>(Settings::values.resolution_factor)); |
| 927 | rb.Push(static_cast<u64>(DisplayResolution::UndockedHeight) * | ||
| 928 | static_cast<u32>(Settings::values.resolution_factor)); | ||
| 909 | } | 929 | } |
| 910 | } | 930 | } |
| 911 | 931 | ||
| 912 | void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { | 932 | void SetLayerScalingMode(Kernel::HLERequestContext& ctx) { |
| 913 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 933 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 934 | |||
| 914 | IPC::RequestParser rp{ctx}; | 935 | IPC::RequestParser rp{ctx}; |
| 915 | u32 scaling_mode = rp.Pop<u32>(); | 936 | u32 scaling_mode = rp.Pop<u32>(); |
| 916 | u64 unknown = rp.Pop<u64>(); | 937 | u64 unknown = rp.Pop<u64>(); |
| @@ -920,17 +941,21 @@ private: | |||
| 920 | } | 941 | } |
| 921 | 942 | ||
| 922 | void ListDisplays(Kernel::HLERequestContext& ctx) { | 943 | void ListDisplays(Kernel::HLERequestContext& ctx) { |
| 944 | LOG_WARNING(Service_VI, "(STUBBED) called"); | ||
| 945 | |||
| 923 | IPC::RequestParser rp{ctx}; | 946 | IPC::RequestParser rp{ctx}; |
| 924 | DisplayInfo display_info; | 947 | DisplayInfo display_info; |
| 948 | display_info.width *= static_cast<u64>(Settings::values.resolution_factor); | ||
| 949 | display_info.height *= static_cast<u64>(Settings::values.resolution_factor); | ||
| 925 | ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); | 950 | ctx.WriteBuffer(&display_info, sizeof(DisplayInfo)); |
| 926 | IPC::ResponseBuilder rb{ctx, 4}; | 951 | IPC::ResponseBuilder rb{ctx, 4}; |
| 927 | rb.Push(RESULT_SUCCESS); | 952 | rb.Push(RESULT_SUCCESS); |
| 928 | rb.Push<u64>(1); | 953 | rb.Push<u64>(1); |
| 929 | LOG_WARNING(Service_VI, "(STUBBED) called"); | ||
| 930 | } | 954 | } |
| 931 | 955 | ||
| 932 | void OpenLayer(Kernel::HLERequestContext& ctx) { | 956 | void OpenLayer(Kernel::HLERequestContext& ctx) { |
| 933 | LOG_DEBUG(Service_VI, "called"); | 957 | LOG_DEBUG(Service_VI, "called"); |
| 958 | |||
| 934 | IPC::RequestParser rp{ctx}; | 959 | IPC::RequestParser rp{ctx}; |
| 935 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); | 960 | auto name_buf = rp.PopRaw<std::array<u8, 0x40>>(); |
| 936 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); | 961 | auto end = std::find(name_buf.begin(), name_buf.end(), '\0'); |
| @@ -981,6 +1006,7 @@ private: | |||
| 981 | 1006 | ||
| 982 | void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) { | 1007 | void GetDisplayVsyncEvent(Kernel::HLERequestContext& ctx) { |
| 983 | LOG_WARNING(Service_VI, "(STUBBED) called"); | 1008 | LOG_WARNING(Service_VI, "(STUBBED) called"); |
| 1009 | |||
| 984 | IPC::RequestParser rp{ctx}; | 1010 | IPC::RequestParser rp{ctx}; |
| 985 | u64 display_id = rp.Pop<u64>(); | 1011 | u64 display_id = rp.Pop<u64>(); |
| 986 | 1012 | ||
diff --git a/src/core/settings.h b/src/core/settings.h index e63134f80..a0c5fd447 100644 --- a/src/core/settings.h +++ b/src/core/settings.h | |||
| @@ -403,6 +403,7 @@ struct Values { | |||
| 403 | bool use_gdbstub; | 403 | bool use_gdbstub; |
| 404 | u16 gdbstub_port; | 404 | u16 gdbstub_port; |
| 405 | std::string program_args; | 405 | std::string program_args; |
| 406 | bool dump_exefs; | ||
| 406 | bool dump_nso; | 407 | bool dump_nso; |
| 407 | 408 | ||
| 408 | // WebService | 409 | // WebService |
diff --git a/src/video_core/CMakeLists.txt b/src/video_core/CMakeLists.txt index a780215c1..0406fbcd9 100644 --- a/src/video_core/CMakeLists.txt +++ b/src/video_core/CMakeLists.txt | |||
| @@ -1,6 +1,6 @@ | |||
| 1 | add_library(video_core STATIC | 1 | add_library(video_core STATIC |
| 2 | command_processor.cpp | 2 | dma_pusher.cpp |
| 3 | command_processor.h | 3 | dma_pusher.h |
| 4 | debug_utils/debug_utils.cpp | 4 | debug_utils/debug_utils.cpp |
| 5 | debug_utils/debug_utils.h | 5 | debug_utils/debug_utils.h |
| 6 | engines/fermi_2d.cpp | 6 | engines/fermi_2d.cpp |
| @@ -21,6 +21,8 @@ add_library(video_core STATIC | |||
| 21 | macro_interpreter.h | 21 | macro_interpreter.h |
| 22 | memory_manager.cpp | 22 | memory_manager.cpp |
| 23 | memory_manager.h | 23 | memory_manager.h |
| 24 | morton.cpp | ||
| 25 | morton.h | ||
| 24 | rasterizer_cache.cpp | 26 | rasterizer_cache.cpp |
| 25 | rasterizer_cache.h | 27 | rasterizer_cache.h |
| 26 | rasterizer_interface.h | 28 | rasterizer_interface.h |
| @@ -62,7 +64,6 @@ add_library(video_core STATIC | |||
| 62 | textures/decoders.cpp | 64 | textures/decoders.cpp |
| 63 | textures/decoders.h | 65 | textures/decoders.h |
| 64 | textures/texture.h | 66 | textures/texture.h |
| 65 | utils.h | ||
| 66 | video_core.cpp | 67 | video_core.cpp |
| 67 | video_core.h | 68 | video_core.h |
| 68 | ) | 69 | ) |
diff --git a/src/video_core/command_processor.cpp b/src/video_core/command_processor.cpp index 28e8c13aa..8b9c548cc 100644 --- a/src/video_core/command_processor.cpp +++ b/src/video_core/command_processor.cpp | |||
| @@ -34,6 +34,9 @@ MICROPROFILE_DEFINE(ProcessCommandLists, "GPU", "Execute command buffer", MP_RGB | |||
| 34 | void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) { | 34 | void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) { |
| 35 | MICROPROFILE_SCOPE(ProcessCommandLists); | 35 | MICROPROFILE_SCOPE(ProcessCommandLists); |
| 36 | 36 | ||
| 37 | // On entering GPU code, assume all memory may be touched by the ARM core. | ||
| 38 | maxwell_3d->dirty_flags.OnMemoryWrite(); | ||
| 39 | |||
| 37 | auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) { | 40 | auto WriteReg = [this](u32 method, u32 subchannel, u32 value, u32 remaining_params) { |
| 38 | LOG_TRACE(HW_GPU, | 41 | LOG_TRACE(HW_GPU, |
| 39 | "Processing method {:08X} on subchannel {} value " | 42 | "Processing method {:08X} on subchannel {} value " |
diff --git a/src/video_core/command_processor.h b/src/video_core/command_processor.h deleted file mode 100644 index bd766e77a..000000000 --- a/src/video_core/command_processor.h +++ /dev/null | |||
| @@ -1,53 +0,0 @@ | |||
| 1 | // Copyright 2018 yuzu 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 <type_traits> | ||
| 8 | #include "common/bit_field.h" | ||
| 9 | #include "common/common_types.h" | ||
| 10 | #include "video_core/memory_manager.h" | ||
| 11 | |||
| 12 | namespace Tegra { | ||
| 13 | |||
| 14 | enum class SubmissionMode : u32 { | ||
| 15 | IncreasingOld = 0, | ||
| 16 | Increasing = 1, | ||
| 17 | NonIncreasingOld = 2, | ||
| 18 | NonIncreasing = 3, | ||
| 19 | Inline = 4, | ||
| 20 | IncreaseOnce = 5 | ||
| 21 | }; | ||
| 22 | |||
| 23 | struct CommandListHeader { | ||
| 24 | u32 entry0; // gpu_va_lo | ||
| 25 | union { | ||
| 26 | u32 entry1; // gpu_va_hi | (unk_0x02 << 0x08) | (size << 0x0A) | (unk_0x01 << 0x1F) | ||
| 27 | BitField<0, 8, u32> gpu_va_hi; | ||
| 28 | BitField<8, 2, u32> unk1; | ||
| 29 | BitField<10, 21, u32> sz; | ||
| 30 | BitField<31, 1, u32> unk2; | ||
| 31 | }; | ||
| 32 | |||
| 33 | GPUVAddr Address() const { | ||
| 34 | return (static_cast<GPUVAddr>(gpu_va_hi) << 32) | entry0; | ||
| 35 | } | ||
| 36 | }; | ||
| 37 | static_assert(sizeof(CommandListHeader) == 8, "CommandListHeader is incorrect size"); | ||
| 38 | |||
| 39 | union CommandHeader { | ||
| 40 | u32 hex; | ||
| 41 | |||
| 42 | BitField<0, 13, u32> method; | ||
| 43 | BitField<13, 3, u32> subchannel; | ||
| 44 | |||
| 45 | BitField<16, 13, u32> arg_count; | ||
| 46 | BitField<16, 13, u32> inline_data; | ||
| 47 | |||
| 48 | BitField<29, 3, SubmissionMode> mode; | ||
| 49 | }; | ||
| 50 | static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout"); | ||
| 51 | static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!"); | ||
| 52 | |||
| 53 | } // namespace Tegra | ||
diff --git a/src/video_core/dma_pusher.cpp b/src/video_core/dma_pusher.cpp new file mode 100644 index 000000000..63a958f11 --- /dev/null +++ b/src/video_core/dma_pusher.cpp | |||
| @@ -0,0 +1,123 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include "common/microprofile.h" | ||
| 6 | #include "core/core.h" | ||
| 7 | #include "core/memory.h" | ||
| 8 | #include "video_core/dma_pusher.h" | ||
| 9 | #include "video_core/engines/maxwell_3d.h" | ||
| 10 | #include "video_core/gpu.h" | ||
| 11 | |||
| 12 | namespace Tegra { | ||
| 13 | |||
| 14 | DmaPusher::DmaPusher(GPU& gpu) : gpu(gpu) {} | ||
| 15 | |||
| 16 | DmaPusher::~DmaPusher() = default; | ||
| 17 | |||
| 18 | MICROPROFILE_DEFINE(DispatchCalls, "GPU", "Execute command buffer", MP_RGB(128, 128, 192)); | ||
| 19 | |||
| 20 | void DmaPusher::DispatchCalls() { | ||
| 21 | MICROPROFILE_SCOPE(DispatchCalls); | ||
| 22 | |||
| 23 | // On entering GPU code, assume all memory may be touched by the ARM core. | ||
| 24 | gpu.Maxwell3D().dirty_flags.OnMemoryWrite(); | ||
| 25 | |||
| 26 | dma_pushbuffer_subindex = 0; | ||
| 27 | |||
| 28 | while (Core::System::GetInstance().IsPoweredOn()) { | ||
| 29 | if (!Step()) { | ||
| 30 | break; | ||
| 31 | } | ||
| 32 | } | ||
| 33 | } | ||
| 34 | |||
| 35 | bool DmaPusher::Step() { | ||
| 36 | if (dma_get != dma_put) { | ||
| 37 | // Push buffer non-empty, read a word | ||
| 38 | const CommandHeader command_header{ | ||
| 39 | Memory::Read32(*gpu.MemoryManager().GpuToCpuAddress(dma_get))}; | ||
| 40 | |||
| 41 | dma_get += sizeof(u32); | ||
| 42 | |||
| 43 | if (!non_main) { | ||
| 44 | dma_mget = dma_get; | ||
| 45 | } | ||
| 46 | |||
| 47 | // now, see if we're in the middle of a command | ||
| 48 | if (dma_state.length_pending) { | ||
| 49 | // Second word of long non-inc methods command - method count | ||
| 50 | dma_state.length_pending = 0; | ||
| 51 | dma_state.method_count = command_header.method_count_; | ||
| 52 | } else if (dma_state.method_count) { | ||
| 53 | // Data word of methods command | ||
| 54 | CallMethod(command_header.argument); | ||
| 55 | |||
| 56 | if (!dma_state.non_incrementing) { | ||
| 57 | dma_state.method++; | ||
| 58 | } | ||
| 59 | |||
| 60 | if (dma_increment_once) { | ||
| 61 | dma_state.non_incrementing = true; | ||
| 62 | } | ||
| 63 | |||
| 64 | dma_state.method_count--; | ||
| 65 | } else { | ||
| 66 | // No command active - this is the first word of a new one | ||
| 67 | switch (command_header.mode) { | ||
| 68 | case SubmissionMode::Increasing: | ||
| 69 | SetState(command_header); | ||
| 70 | dma_state.non_incrementing = false; | ||
| 71 | dma_increment_once = false; | ||
| 72 | break; | ||
| 73 | case SubmissionMode::NonIncreasing: | ||
| 74 | SetState(command_header); | ||
| 75 | dma_state.non_incrementing = true; | ||
| 76 | dma_increment_once = false; | ||
| 77 | break; | ||
| 78 | case SubmissionMode::Inline: | ||
| 79 | dma_state.method = command_header.method; | ||
| 80 | dma_state.subchannel = command_header.subchannel; | ||
| 81 | CallMethod(command_header.arg_count); | ||
| 82 | dma_state.non_incrementing = true; | ||
| 83 | dma_increment_once = false; | ||
| 84 | break; | ||
| 85 | case SubmissionMode::IncreaseOnce: | ||
| 86 | SetState(command_header); | ||
| 87 | dma_state.non_incrementing = false; | ||
| 88 | dma_increment_once = true; | ||
| 89 | break; | ||
| 90 | } | ||
| 91 | } | ||
| 92 | } else if (ib_enable && !dma_pushbuffer.empty()) { | ||
| 93 | // Current pushbuffer empty, but we have more IB entries to read | ||
| 94 | const CommandList& command_list{dma_pushbuffer.front()}; | ||
| 95 | const CommandListHeader& command_list_header{command_list[dma_pushbuffer_subindex++]}; | ||
| 96 | dma_get = command_list_header.addr; | ||
| 97 | dma_put = dma_get + command_list_header.size * sizeof(u32); | ||
| 98 | non_main = command_list_header.is_non_main; | ||
| 99 | |||
| 100 | if (dma_pushbuffer_subindex >= command_list.size()) { | ||
| 101 | // We've gone through the current list, remove it from the queue | ||
| 102 | dma_pushbuffer.pop(); | ||
| 103 | dma_pushbuffer_subindex = 0; | ||
| 104 | } | ||
| 105 | } else { | ||
| 106 | // Otherwise, pushbuffer empty and IB empty or nonexistent - nothing to do | ||
| 107 | return {}; | ||
| 108 | } | ||
| 109 | |||
| 110 | return true; | ||
| 111 | } | ||
| 112 | |||
| 113 | void DmaPusher::SetState(const CommandHeader& command_header) { | ||
| 114 | dma_state.method = command_header.method; | ||
| 115 | dma_state.subchannel = command_header.subchannel; | ||
| 116 | dma_state.method_count = command_header.method_count; | ||
| 117 | } | ||
| 118 | |||
| 119 | void DmaPusher::CallMethod(u32 argument) const { | ||
| 120 | gpu.CallMethod({dma_state.method, argument, dma_state.subchannel, dma_state.method_count}); | ||
| 121 | } | ||
| 122 | |||
| 123 | } // namespace Tegra | ||
diff --git a/src/video_core/dma_pusher.h b/src/video_core/dma_pusher.h new file mode 100644 index 000000000..16e0697c4 --- /dev/null +++ b/src/video_core/dma_pusher.h | |||
| @@ -0,0 +1,99 @@ | |||
| 1 | // Copyright 2018 yuzu 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 <vector> | ||
| 8 | #include <queue> | ||
| 9 | |||
| 10 | #include "common/bit_field.h" | ||
| 11 | #include "common/common_types.h" | ||
| 12 | #include "video_core/memory_manager.h" | ||
| 13 | |||
| 14 | namespace Tegra { | ||
| 15 | |||
| 16 | enum class SubmissionMode : u32 { | ||
| 17 | IncreasingOld = 0, | ||
| 18 | Increasing = 1, | ||
| 19 | NonIncreasingOld = 2, | ||
| 20 | NonIncreasing = 3, | ||
| 21 | Inline = 4, | ||
| 22 | IncreaseOnce = 5 | ||
| 23 | }; | ||
| 24 | |||
| 25 | struct CommandListHeader { | ||
| 26 | union { | ||
| 27 | u64 raw; | ||
| 28 | BitField<0, 40, GPUVAddr> addr; | ||
| 29 | BitField<41, 1, u64> is_non_main; | ||
| 30 | BitField<42, 21, u64> size; | ||
| 31 | }; | ||
| 32 | }; | ||
| 33 | static_assert(sizeof(CommandListHeader) == sizeof(u64), "CommandListHeader is incorrect size"); | ||
| 34 | |||
| 35 | union CommandHeader { | ||
| 36 | u32 argument; | ||
| 37 | BitField<0, 13, u32> method; | ||
| 38 | BitField<0, 24, u32> method_count_; | ||
| 39 | BitField<13, 3, u32> subchannel; | ||
| 40 | BitField<16, 13, u32> arg_count; | ||
| 41 | BitField<16, 13, u32> method_count; | ||
| 42 | BitField<29, 3, SubmissionMode> mode; | ||
| 43 | }; | ||
| 44 | static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout"); | ||
| 45 | static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!"); | ||
| 46 | |||
| 47 | class GPU; | ||
| 48 | |||
| 49 | using CommandList = std::vector<Tegra::CommandListHeader>; | ||
| 50 | |||
| 51 | /** | ||
| 52 | * The DmaPusher class implements DMA submission to FIFOs, providing an area of memory that the | ||
| 53 | * emulated app fills with commands and tells PFIFO to process. The pushbuffers are then assembled | ||
| 54 | * into a "command stream" consisting of 32-bit words that make up "commands". | ||
| 55 | * See https://envytools.readthedocs.io/en/latest/hw/fifo/dma-pusher.html#fifo-dma-pusher for | ||
| 56 | * details on this implementation. | ||
| 57 | */ | ||
| 58 | class DmaPusher { | ||
| 59 | public: | ||
| 60 | explicit DmaPusher(GPU& gpu); | ||
| 61 | ~DmaPusher(); | ||
| 62 | |||
| 63 | void Push(CommandList&& entries) { | ||
| 64 | dma_pushbuffer.push(std::move(entries)); | ||
| 65 | } | ||
| 66 | |||
| 67 | void DispatchCalls(); | ||
| 68 | |||
| 69 | private: | ||
| 70 | bool Step(); | ||
| 71 | |||
| 72 | void SetState(const CommandHeader& command_header); | ||
| 73 | |||
| 74 | void CallMethod(u32 argument) const; | ||
| 75 | |||
| 76 | GPU& gpu; | ||
| 77 | |||
| 78 | std::queue<CommandList> dma_pushbuffer; ///< Queue of command lists to be processed | ||
| 79 | std::size_t dma_pushbuffer_subindex{}; ///< Index within a command list within the pushbuffer | ||
| 80 | |||
| 81 | struct DmaState { | ||
| 82 | u32 method; ///< Current method | ||
| 83 | u32 subchannel; ///< Current subchannel | ||
| 84 | u32 method_count; ///< Current method count | ||
| 85 | u32 length_pending; ///< Large NI command length pending | ||
| 86 | bool non_incrementing; ///< Current command’s NI flag | ||
| 87 | }; | ||
| 88 | |||
| 89 | DmaState dma_state{}; | ||
| 90 | bool dma_increment_once{}; | ||
| 91 | |||
| 92 | GPUVAddr dma_put{}; ///< pushbuffer current end address | ||
| 93 | GPUVAddr dma_get{}; ///< pushbuffer current read address | ||
| 94 | GPUVAddr dma_mget{}; ///< main pushbuffer last read address | ||
| 95 | bool ib_enable{true}; ///< IB mode enabled | ||
| 96 | bool non_main{}; ///< non-main pushbuffer active | ||
| 97 | }; | ||
| 98 | |||
| 99 | } // namespace Tegra | ||
diff --git a/src/video_core/engines/fermi_2d.cpp b/src/video_core/engines/fermi_2d.cpp index 74e44c7fe..80f70e332 100644 --- a/src/video_core/engines/fermi_2d.cpp +++ b/src/video_core/engines/fermi_2d.cpp | |||
| @@ -2,8 +2,10 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "core/core.h" | ||
| 5 | #include "core/memory.h" | 6 | #include "core/memory.h" |
| 6 | #include "video_core/engines/fermi_2d.h" | 7 | #include "video_core/engines/fermi_2d.h" |
| 8 | #include "video_core/engines/maxwell_3d.h" | ||
| 7 | #include "video_core/rasterizer_interface.h" | 9 | #include "video_core/rasterizer_interface.h" |
| 8 | #include "video_core/textures/decoders.h" | 10 | #include "video_core/textures/decoders.h" |
| 9 | 11 | ||
| @@ -12,13 +14,13 @@ namespace Tegra::Engines { | |||
| 12 | Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) | 14 | Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) |
| 13 | : memory_manager(memory_manager), rasterizer{rasterizer} {} | 15 | : memory_manager(memory_manager), rasterizer{rasterizer} {} |
| 14 | 16 | ||
| 15 | void Fermi2D::WriteReg(u32 method, u32 value) { | 17 | void Fermi2D::CallMethod(const GPU::MethodCall& method_call) { |
| 16 | ASSERT_MSG(method < Regs::NUM_REGS, | 18 | ASSERT_MSG(method_call.method < Regs::NUM_REGS, |
| 17 | "Invalid Fermi2D register, increase the size of the Regs structure"); | 19 | "Invalid Fermi2D register, increase the size of the Regs structure"); |
| 18 | 20 | ||
| 19 | regs.reg_array[method] = value; | 21 | regs.reg_array[method_call.method] = method_call.argument; |
| 20 | 22 | ||
| 21 | switch (method) { | 23 | switch (method_call.method) { |
| 22 | case FERMI2D_REG_INDEX(trigger): { | 24 | case FERMI2D_REG_INDEX(trigger): { |
| 23 | HandleSurfaceCopy(); | 25 | HandleSurfaceCopy(); |
| 24 | break; | 26 | break; |
| @@ -47,6 +49,9 @@ void Fermi2D::HandleSurfaceCopy() { | |||
| 47 | u32 dst_bytes_per_pixel = RenderTargetBytesPerPixel(regs.dst.format); | 49 | u32 dst_bytes_per_pixel = RenderTargetBytesPerPixel(regs.dst.format); |
| 48 | 50 | ||
| 49 | if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst)) { | 51 | if (!rasterizer.AccelerateSurfaceCopy(regs.src, regs.dst)) { |
| 52 | // All copies here update the main memory, so mark all rasterizer states as invalid. | ||
| 53 | Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); | ||
| 54 | |||
| 50 | rasterizer.FlushRegion(source_cpu, src_bytes_per_pixel * regs.src.width * regs.src.height); | 55 | rasterizer.FlushRegion(source_cpu, src_bytes_per_pixel * regs.src.width * regs.src.height); |
| 51 | // We have to invalidate the destination region to evict any outdated surfaces from the | 56 | // We have to invalidate the destination region to evict any outdated surfaces from the |
| 52 | // cache. We do this before actually writing the new data because the destination address | 57 | // cache. We do this before actually writing the new data because the destination address |
| @@ -68,13 +73,13 @@ void Fermi2D::HandleSurfaceCopy() { | |||
| 68 | Texture::CopySwizzledData(regs.src.width, regs.src.height, regs.src.depth, | 73 | Texture::CopySwizzledData(regs.src.width, regs.src.height, regs.src.depth, |
| 69 | src_bytes_per_pixel, dst_bytes_per_pixel, src_buffer, | 74 | src_bytes_per_pixel, dst_bytes_per_pixel, src_buffer, |
| 70 | dst_buffer, true, regs.src.BlockHeight(), | 75 | dst_buffer, true, regs.src.BlockHeight(), |
| 71 | regs.src.BlockDepth()); | 76 | regs.src.BlockDepth(), 0); |
| 72 | } else { | 77 | } else { |
| 73 | // If the input is linear and the output is tiled, swizzle the input and copy it over. | 78 | // If the input is linear and the output is tiled, swizzle the input and copy it over. |
| 74 | Texture::CopySwizzledData(regs.src.width, regs.src.height, regs.src.depth, | 79 | Texture::CopySwizzledData(regs.src.width, regs.src.height, regs.src.depth, |
| 75 | src_bytes_per_pixel, dst_bytes_per_pixel, dst_buffer, | 80 | src_bytes_per_pixel, dst_bytes_per_pixel, dst_buffer, |
| 76 | src_buffer, false, regs.dst.BlockHeight(), | 81 | src_buffer, false, regs.dst.BlockHeight(), |
| 77 | regs.dst.BlockDepth()); | 82 | regs.dst.BlockDepth(), 0); |
| 78 | } | 83 | } |
| 79 | } | 84 | } |
| 80 | } | 85 | } |
diff --git a/src/video_core/engines/fermi_2d.h b/src/video_core/engines/fermi_2d.h index 2a6e8bbbb..50009bf75 100644 --- a/src/video_core/engines/fermi_2d.h +++ b/src/video_core/engines/fermi_2d.h | |||
| @@ -27,7 +27,7 @@ public: | |||
| 27 | ~Fermi2D() = default; | 27 | ~Fermi2D() = default; |
| 28 | 28 | ||
| 29 | /// Write the value to the register identified by method. | 29 | /// Write the value to the register identified by method. |
| 30 | void WriteReg(u32 method, u32 value); | 30 | void CallMethod(const GPU::MethodCall& method_call); |
| 31 | 31 | ||
| 32 | struct Regs { | 32 | struct Regs { |
| 33 | static constexpr std::size_t NUM_REGS = 0x258; | 33 | static constexpr std::size_t NUM_REGS = 0x258; |
diff --git a/src/video_core/engines/kepler_memory.cpp b/src/video_core/engines/kepler_memory.cpp index 585290d9f..4880191fc 100644 --- a/src/video_core/engines/kepler_memory.cpp +++ b/src/video_core/engines/kepler_memory.cpp | |||
| @@ -3,8 +3,10 @@ | |||
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "common/logging/log.h" | 5 | #include "common/logging/log.h" |
| 6 | #include "core/core.h" | ||
| 6 | #include "core/memory.h" | 7 | #include "core/memory.h" |
| 7 | #include "video_core/engines/kepler_memory.h" | 8 | #include "video_core/engines/kepler_memory.h" |
| 9 | #include "video_core/engines/maxwell_3d.h" | ||
| 8 | #include "video_core/rasterizer_interface.h" | 10 | #include "video_core/rasterizer_interface.h" |
| 9 | 11 | ||
| 10 | namespace Tegra::Engines { | 12 | namespace Tegra::Engines { |
| @@ -15,19 +17,19 @@ KeplerMemory::KeplerMemory(VideoCore::RasterizerInterface& rasterizer, | |||
| 15 | 17 | ||
| 16 | KeplerMemory::~KeplerMemory() = default; | 18 | KeplerMemory::~KeplerMemory() = default; |
| 17 | 19 | ||
| 18 | void KeplerMemory::WriteReg(u32 method, u32 value) { | 20 | void KeplerMemory::CallMethod(const GPU::MethodCall& method_call) { |
| 19 | ASSERT_MSG(method < Regs::NUM_REGS, | 21 | ASSERT_MSG(method_call.method < Regs::NUM_REGS, |
| 20 | "Invalid KeplerMemory register, increase the size of the Regs structure"); | 22 | "Invalid KeplerMemory register, increase the size of the Regs structure"); |
| 21 | 23 | ||
| 22 | regs.reg_array[method] = value; | 24 | regs.reg_array[method_call.method] = method_call.argument; |
| 23 | 25 | ||
| 24 | switch (method) { | 26 | switch (method_call.method) { |
| 25 | case KEPLERMEMORY_REG_INDEX(exec): { | 27 | case KEPLERMEMORY_REG_INDEX(exec): { |
| 26 | state.write_offset = 0; | 28 | state.write_offset = 0; |
| 27 | break; | 29 | break; |
| 28 | } | 30 | } |
| 29 | case KEPLERMEMORY_REG_INDEX(data): { | 31 | case KEPLERMEMORY_REG_INDEX(data): { |
| 30 | ProcessData(value); | 32 | ProcessData(method_call.argument); |
| 31 | break; | 33 | break; |
| 32 | } | 34 | } |
| 33 | } | 35 | } |
| @@ -47,6 +49,7 @@ void KeplerMemory::ProcessData(u32 data) { | |||
| 47 | rasterizer.InvalidateRegion(dest_address, sizeof(u32)); | 49 | rasterizer.InvalidateRegion(dest_address, sizeof(u32)); |
| 48 | 50 | ||
| 49 | Memory::Write32(dest_address, data); | 51 | Memory::Write32(dest_address, data); |
| 52 | Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); | ||
| 50 | 53 | ||
| 51 | state.write_offset++; | 54 | state.write_offset++; |
| 52 | } | 55 | } |
diff --git a/src/video_core/engines/kepler_memory.h b/src/video_core/engines/kepler_memory.h index bf4a13cff..fe9ebc5b9 100644 --- a/src/video_core/engines/kepler_memory.h +++ b/src/video_core/engines/kepler_memory.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/bit_field.h" | 9 | #include "common/bit_field.h" |
| 10 | #include "common/common_funcs.h" | 10 | #include "common/common_funcs.h" |
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "video_core/gpu.h" | ||
| 12 | #include "video_core/memory_manager.h" | 13 | #include "video_core/memory_manager.h" |
| 13 | 14 | ||
| 14 | namespace VideoCore { | 15 | namespace VideoCore { |
| @@ -26,7 +27,7 @@ public: | |||
| 26 | ~KeplerMemory(); | 27 | ~KeplerMemory(); |
| 27 | 28 | ||
| 28 | /// Write the value to the register identified by method. | 29 | /// Write the value to the register identified by method. |
| 29 | void WriteReg(u32 method, u32 value); | 30 | void CallMethod(const GPU::MethodCall& method_call); |
| 30 | 31 | ||
| 31 | struct Regs { | 32 | struct Regs { |
| 32 | static constexpr size_t NUM_REGS = 0x7F; | 33 | static constexpr size_t NUM_REGS = 0x7F; |
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp index 2bc534be3..b19b3a75a 100644 --- a/src/video_core/engines/maxwell_3d.cpp +++ b/src/video_core/engines/maxwell_3d.cpp | |||
| @@ -97,57 +97,74 @@ void Maxwell3D::CallMacroMethod(u32 method, std::vector<u32> parameters) { | |||
| 97 | macro_interpreter.Execute(search->second, std::move(parameters)); | 97 | macro_interpreter.Execute(search->second, std::move(parameters)); |
| 98 | } | 98 | } |
| 99 | 99 | ||
| 100 | void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { | 100 | void Maxwell3D::CallMethod(const GPU::MethodCall& method_call) { |
| 101 | auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); | 101 | auto debug_context = Core::System::GetInstance().GetGPUDebugContext(); |
| 102 | 102 | ||
| 103 | // It is an error to write to a register other than the current macro's ARG register before it | 103 | // It is an error to write to a register other than the current macro's ARG register before it |
| 104 | // has finished execution. | 104 | // has finished execution. |
| 105 | if (executing_macro != 0) { | 105 | if (executing_macro != 0) { |
| 106 | ASSERT(method == executing_macro + 1); | 106 | ASSERT(method_call.method == executing_macro + 1); |
| 107 | } | 107 | } |
| 108 | 108 | ||
| 109 | // Methods after 0xE00 are special, they're actually triggers for some microcode that was | 109 | // Methods after 0xE00 are special, they're actually triggers for some microcode that was |
| 110 | // uploaded to the GPU during initialization. | 110 | // uploaded to the GPU during initialization. |
| 111 | if (method >= MacroRegistersStart) { | 111 | if (method_call.method >= MacroRegistersStart) { |
| 112 | // We're trying to execute a macro | 112 | // We're trying to execute a macro |
| 113 | if (executing_macro == 0) { | 113 | if (executing_macro == 0) { |
| 114 | // A macro call must begin by writing the macro method's register, not its argument. | 114 | // A macro call must begin by writing the macro method's register, not its argument. |
| 115 | ASSERT_MSG((method % 2) == 0, | 115 | ASSERT_MSG((method_call.method % 2) == 0, |
| 116 | "Can't start macro execution by writing to the ARGS register"); | 116 | "Can't start macro execution by writing to the ARGS register"); |
| 117 | executing_macro = method; | 117 | executing_macro = method_call.method; |
| 118 | } | 118 | } |
| 119 | 119 | ||
| 120 | macro_params.push_back(value); | 120 | macro_params.push_back(method_call.argument); |
| 121 | 121 | ||
| 122 | // Call the macro when there are no more parameters in the command buffer | 122 | // Call the macro when there are no more parameters in the command buffer |
| 123 | if (remaining_params == 0) { | 123 | if (method_call.IsLastCall()) { |
| 124 | CallMacroMethod(executing_macro, std::move(macro_params)); | 124 | CallMacroMethod(executing_macro, std::move(macro_params)); |
| 125 | } | 125 | } |
| 126 | return; | 126 | return; |
| 127 | } | 127 | } |
| 128 | 128 | ||
| 129 | ASSERT_MSG(method < Regs::NUM_REGS, | 129 | ASSERT_MSG(method_call.method < Regs::NUM_REGS, |
| 130 | "Invalid Maxwell3D register, increase the size of the Regs structure"); | 130 | "Invalid Maxwell3D register, increase the size of the Regs structure"); |
| 131 | 131 | ||
| 132 | if (debug_context) { | 132 | if (debug_context) { |
| 133 | debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr); | 133 | debug_context->OnEvent(Tegra::DebugContext::Event::MaxwellCommandLoaded, nullptr); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | if (regs.reg_array[method] != value) { | 136 | if (regs.reg_array[method_call.method] != method_call.argument) { |
| 137 | regs.reg_array[method] = value; | 137 | regs.reg_array[method_call.method] = method_call.argument; |
| 138 | if (method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) && | 138 | // Vertex format |
| 139 | method < MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) { | 139 | if (method_call.method >= MAXWELL3D_REG_INDEX(vertex_attrib_format) && |
| 140 | method_call.method < | ||
| 141 | MAXWELL3D_REG_INDEX(vertex_attrib_format) + regs.vertex_attrib_format.size()) { | ||
| 140 | dirty_flags.vertex_attrib_format = true; | 142 | dirty_flags.vertex_attrib_format = true; |
| 141 | } | 143 | } |
| 144 | |||
| 145 | // Vertex buffer | ||
| 146 | if (method_call.method >= MAXWELL3D_REG_INDEX(vertex_array) && | ||
| 147 | method_call.method < MAXWELL3D_REG_INDEX(vertex_array) + 4 * 32) { | ||
| 148 | dirty_flags.vertex_array |= | ||
| 149 | 1u << ((method_call.method - MAXWELL3D_REG_INDEX(vertex_array)) >> 2); | ||
| 150 | } else if (method_call.method >= MAXWELL3D_REG_INDEX(vertex_array_limit) && | ||
| 151 | method_call.method < MAXWELL3D_REG_INDEX(vertex_array_limit) + 2 * 32) { | ||
| 152 | dirty_flags.vertex_array |= | ||
| 153 | 1u << ((method_call.method - MAXWELL3D_REG_INDEX(vertex_array_limit)) >> 1); | ||
| 154 | } else if (method_call.method >= MAXWELL3D_REG_INDEX(instanced_arrays) && | ||
| 155 | method_call.method < MAXWELL3D_REG_INDEX(instanced_arrays) + 32) { | ||
| 156 | dirty_flags.vertex_array |= | ||
| 157 | 1u << (method_call.method - MAXWELL3D_REG_INDEX(instanced_arrays)); | ||
| 158 | } | ||
| 142 | } | 159 | } |
| 143 | 160 | ||
| 144 | switch (method) { | 161 | switch (method_call.method) { |
| 145 | case MAXWELL3D_REG_INDEX(macros.data): { | 162 | case MAXWELL3D_REG_INDEX(macros.data): { |
| 146 | ProcessMacroUpload(value); | 163 | ProcessMacroUpload(method_call.argument); |
| 147 | break; | 164 | break; |
| 148 | } | 165 | } |
| 149 | case MAXWELL3D_REG_INDEX(macros.bind): { | 166 | case MAXWELL3D_REG_INDEX(macros.bind): { |
| 150 | ProcessMacroBind(value); | 167 | ProcessMacroBind(method_call.argument); |
| 151 | break; | 168 | break; |
| 152 | } | 169 | } |
| 153 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]): | 170 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]): |
| @@ -166,7 +183,7 @@ void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { | |||
| 166 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]): | 183 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]): |
| 167 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]): | 184 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]): |
| 168 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): { | 185 | case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): { |
| 169 | ProcessCBData(value); | 186 | ProcessCBData(method_call.argument); |
| 170 | break; | 187 | break; |
| 171 | } | 188 | } |
| 172 | case MAXWELL3D_REG_INDEX(cb_bind[0].raw_config): { | 189 | case MAXWELL3D_REG_INDEX(cb_bind[0].raw_config): { |
| @@ -270,6 +287,7 @@ void Maxwell3D::ProcessQueryGet() { | |||
| 270 | query_result.timestamp = CoreTiming::GetTicks(); | 287 | query_result.timestamp = CoreTiming::GetTicks(); |
| 271 | Memory::WriteBlock(*address, &query_result, sizeof(query_result)); | 288 | Memory::WriteBlock(*address, &query_result, sizeof(query_result)); |
| 272 | } | 289 | } |
| 290 | dirty_flags.OnMemoryWrite(); | ||
| 273 | break; | 291 | break; |
| 274 | } | 292 | } |
| 275 | default: | 293 | default: |
| @@ -346,6 +364,7 @@ void Maxwell3D::ProcessCBData(u32 value) { | |||
| 346 | memory_manager.GpuToCpuAddress(buffer_address + regs.const_buffer.cb_pos); | 364 | memory_manager.GpuToCpuAddress(buffer_address + regs.const_buffer.cb_pos); |
| 347 | 365 | ||
| 348 | Memory::Write32(*address, value); | 366 | Memory::Write32(*address, value); |
| 367 | dirty_flags.OnMemoryWrite(); | ||
| 349 | 368 | ||
| 350 | // Increment the current buffer position. | 369 | // Increment the current buffer position. |
| 351 | regs.const_buffer.cb_pos = regs.const_buffer.cb_pos + 4; | 370 | regs.const_buffer.cb_pos = regs.const_buffer.cb_pos + 4; |
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h index 9e480dc39..d3b3ed1f0 100644 --- a/src/video_core/engines/maxwell_3d.h +++ b/src/video_core/engines/maxwell_3d.h | |||
| @@ -389,6 +389,13 @@ public: | |||
| 389 | ReverseSubtract = 3, | 389 | ReverseSubtract = 3, |
| 390 | Min = 4, | 390 | Min = 4, |
| 391 | Max = 5, | 391 | Max = 5, |
| 392 | |||
| 393 | // These values are used by Nouveau and some games. | ||
| 394 | AddGL = 0x8006, | ||
| 395 | SubtractGL = 0x8007, | ||
| 396 | ReverseSubtractGL = 0x8008, | ||
| 397 | MinGL = 0x800a, | ||
| 398 | MaxGL = 0x800b | ||
| 392 | }; | 399 | }; |
| 393 | 400 | ||
| 394 | enum class Factor : u32 { | 401 | enum class Factor : u32 { |
| @@ -583,10 +590,18 @@ public: | |||
| 583 | 590 | ||
| 584 | float clear_color[4]; | 591 | float clear_color[4]; |
| 585 | float clear_depth; | 592 | float clear_depth; |
| 593 | |||
| 586 | INSERT_PADDING_WORDS(0x3); | 594 | INSERT_PADDING_WORDS(0x3); |
| 595 | |||
| 587 | s32 clear_stencil; | 596 | s32 clear_stencil; |
| 588 | 597 | ||
| 589 | INSERT_PADDING_WORDS(0x17); | 598 | INSERT_PADDING_WORDS(0x7); |
| 599 | |||
| 600 | u32 polygon_offset_point_enable; | ||
| 601 | u32 polygon_offset_line_enable; | ||
| 602 | u32 polygon_offset_fill_enable; | ||
| 603 | |||
| 604 | INSERT_PADDING_WORDS(0xD); | ||
| 590 | 605 | ||
| 591 | std::array<ScissorTest, NumViewports> scissor_test; | 606 | std::array<ScissorTest, NumViewports> scissor_test; |
| 592 | 607 | ||
| @@ -624,7 +639,16 @@ public: | |||
| 624 | } | 639 | } |
| 625 | } zeta; | 640 | } zeta; |
| 626 | 641 | ||
| 627 | INSERT_PADDING_WORDS(0x5B); | 642 | INSERT_PADDING_WORDS(0x41); |
| 643 | |||
| 644 | union { | ||
| 645 | BitField<0, 4, u32> stencil; | ||
| 646 | BitField<4, 4, u32> unknown; | ||
| 647 | BitField<8, 4, u32> scissor; | ||
| 648 | BitField<12, 4, u32> viewport; | ||
| 649 | } clear_flags; | ||
| 650 | |||
| 651 | INSERT_PADDING_WORDS(0x19); | ||
| 628 | 652 | ||
| 629 | std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format; | 653 | std::array<VertexAttribute, NumVertexAttributes> vertex_attrib_format; |
| 630 | 654 | ||
| @@ -712,6 +736,7 @@ public: | |||
| 712 | u32 frag_color_clamp; | 736 | u32 frag_color_clamp; |
| 713 | 737 | ||
| 714 | union { | 738 | union { |
| 739 | BitField<0, 1, u32> y_negate; | ||
| 715 | BitField<4, 1, u32> triangle_rast_flip; | 740 | BitField<4, 1, u32> triangle_rast_flip; |
| 716 | } screen_y_control; | 741 | } screen_y_control; |
| 717 | 742 | ||
| @@ -719,7 +744,20 @@ public: | |||
| 719 | 744 | ||
| 720 | u32 vb_element_base; | 745 | u32 vb_element_base; |
| 721 | 746 | ||
| 722 | INSERT_PADDING_WORDS(0x38); | 747 | INSERT_PADDING_WORDS(0x36); |
| 748 | |||
| 749 | union { | ||
| 750 | BitField<0, 1, u32> c0; | ||
| 751 | BitField<1, 1, u32> c1; | ||
| 752 | BitField<2, 1, u32> c2; | ||
| 753 | BitField<3, 1, u32> c3; | ||
| 754 | BitField<4, 1, u32> c4; | ||
| 755 | BitField<5, 1, u32> c5; | ||
| 756 | BitField<6, 1, u32> c6; | ||
| 757 | BitField<7, 1, u32> c7; | ||
| 758 | } clip_distance_enabled; | ||
| 759 | |||
| 760 | INSERT_PADDING_WORDS(0x1); | ||
| 723 | 761 | ||
| 724 | float point_size; | 762 | float point_size; |
| 725 | 763 | ||
| @@ -745,7 +783,11 @@ public: | |||
| 745 | } | 783 | } |
| 746 | } tsc; | 784 | } tsc; |
| 747 | 785 | ||
| 748 | INSERT_PADDING_WORDS(0x3); | 786 | INSERT_PADDING_WORDS(0x1); |
| 787 | |||
| 788 | float polygon_offset_factor; | ||
| 789 | |||
| 790 | INSERT_PADDING_WORDS(0x1); | ||
| 749 | 791 | ||
| 750 | struct { | 792 | struct { |
| 751 | u32 tic_address_high; | 793 | u32 tic_address_high; |
| @@ -770,7 +812,9 @@ public: | |||
| 770 | 812 | ||
| 771 | u32 framebuffer_srgb; | 813 | u32 framebuffer_srgb; |
| 772 | 814 | ||
| 773 | INSERT_PADDING_WORDS(0x12); | 815 | float polygon_offset_units; |
| 816 | |||
| 817 | INSERT_PADDING_WORDS(0x11); | ||
| 774 | 818 | ||
| 775 | union { | 819 | union { |
| 776 | BitField<2, 1, u32> coord_origin; | 820 | BitField<2, 1, u32> coord_origin; |
| @@ -847,7 +891,9 @@ public: | |||
| 847 | 891 | ||
| 848 | INSERT_PADDING_WORDS(0x7); | 892 | INSERT_PADDING_WORDS(0x7); |
| 849 | 893 | ||
| 850 | INSERT_PADDING_WORDS(0x20); | 894 | INSERT_PADDING_WORDS(0x1F); |
| 895 | |||
| 896 | float polygon_offset_clamp; | ||
| 851 | 897 | ||
| 852 | struct { | 898 | struct { |
| 853 | u32 is_instanced[NumVertexArrays]; | 899 | u32 is_instanced[NumVertexArrays]; |
| @@ -863,8 +909,21 @@ public: | |||
| 863 | 909 | ||
| 864 | Cull cull; | 910 | Cull cull; |
| 865 | 911 | ||
| 866 | INSERT_PADDING_WORDS(0x28); | 912 | u32 pixel_center_integer; |
| 913 | |||
| 914 | INSERT_PADDING_WORDS(0x1); | ||
| 915 | |||
| 916 | u32 viewport_transform_enabled; | ||
| 917 | |||
| 918 | INSERT_PADDING_WORDS(0x3); | ||
| 919 | |||
| 920 | union { | ||
| 921 | BitField<0, 1, u32> depth_range_0_1; | ||
| 922 | BitField<3, 1, u32> depth_clamp_near; | ||
| 923 | BitField<4, 1, u32> depth_clamp_far; | ||
| 924 | } view_volume_clip_control; | ||
| 867 | 925 | ||
| 926 | INSERT_PADDING_WORDS(0x21); | ||
| 868 | struct { | 927 | struct { |
| 869 | u32 enable; | 928 | u32 enable; |
| 870 | LogicOperation operation; | 929 | LogicOperation operation; |
| @@ -1028,6 +1087,11 @@ public: | |||
| 1028 | 1087 | ||
| 1029 | struct DirtyFlags { | 1088 | struct DirtyFlags { |
| 1030 | bool vertex_attrib_format = true; | 1089 | bool vertex_attrib_format = true; |
| 1090 | u32 vertex_array = 0xFFFFFFFF; | ||
| 1091 | |||
| 1092 | void OnMemoryWrite() { | ||
| 1093 | vertex_array = 0xFFFFFFFF; | ||
| 1094 | } | ||
| 1031 | }; | 1095 | }; |
| 1032 | 1096 | ||
| 1033 | DirtyFlags dirty_flags; | 1097 | DirtyFlags dirty_flags; |
| @@ -1036,7 +1100,7 @@ public: | |||
| 1036 | u32 GetRegisterValue(u32 method) const; | 1100 | u32 GetRegisterValue(u32 method) const; |
| 1037 | 1101 | ||
| 1038 | /// Write the value to the register identified by method. | 1102 | /// Write the value to the register identified by method. |
| 1039 | void WriteReg(u32 method, u32 value, u32 remaining_params); | 1103 | void CallMethod(const GPU::MethodCall& method_call); |
| 1040 | 1104 | ||
| 1041 | /// Returns a list of enabled textures for the specified shader stage. | 1105 | /// Returns a list of enabled textures for the specified shader stage. |
| 1042 | std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const; | 1106 | std::vector<Texture::FullTextureInfo> GetStageTextures(Regs::ShaderStage stage) const; |
| @@ -1120,6 +1184,9 @@ ASSERT_REG_POSITION(vertex_buffer, 0x35D); | |||
| 1120 | ASSERT_REG_POSITION(clear_color[0], 0x360); | 1184 | ASSERT_REG_POSITION(clear_color[0], 0x360); |
| 1121 | ASSERT_REG_POSITION(clear_depth, 0x364); | 1185 | ASSERT_REG_POSITION(clear_depth, 0x364); |
| 1122 | ASSERT_REG_POSITION(clear_stencil, 0x368); | 1186 | ASSERT_REG_POSITION(clear_stencil, 0x368); |
| 1187 | ASSERT_REG_POSITION(polygon_offset_point_enable, 0x370); | ||
| 1188 | ASSERT_REG_POSITION(polygon_offset_line_enable, 0x371); | ||
| 1189 | ASSERT_REG_POSITION(polygon_offset_fill_enable, 0x372); | ||
| 1123 | ASSERT_REG_POSITION(scissor_test, 0x380); | 1190 | ASSERT_REG_POSITION(scissor_test, 0x380); |
| 1124 | ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); | 1191 | ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); |
| 1125 | ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); | 1192 | ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); |
| @@ -1127,6 +1194,7 @@ ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7); | |||
| 1127 | ASSERT_REG_POSITION(color_mask_common, 0x3E4); | 1194 | ASSERT_REG_POSITION(color_mask_common, 0x3E4); |
| 1128 | ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); | 1195 | ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); |
| 1129 | ASSERT_REG_POSITION(zeta, 0x3F8); | 1196 | ASSERT_REG_POSITION(zeta, 0x3F8); |
| 1197 | ASSERT_REG_POSITION(clear_flags, 0x43E); | ||
| 1130 | ASSERT_REG_POSITION(vertex_attrib_format, 0x458); | 1198 | ASSERT_REG_POSITION(vertex_attrib_format, 0x458); |
| 1131 | ASSERT_REG_POSITION(rt_control, 0x487); | 1199 | ASSERT_REG_POSITION(rt_control, 0x487); |
| 1132 | ASSERT_REG_POSITION(zeta_width, 0x48a); | 1200 | ASSERT_REG_POSITION(zeta_width, 0x48a); |
| @@ -1153,10 +1221,12 @@ ASSERT_REG_POSITION(stencil_front_mask, 0x4E7); | |||
| 1153 | ASSERT_REG_POSITION(frag_color_clamp, 0x4EA); | 1221 | ASSERT_REG_POSITION(frag_color_clamp, 0x4EA); |
| 1154 | ASSERT_REG_POSITION(screen_y_control, 0x4EB); | 1222 | ASSERT_REG_POSITION(screen_y_control, 0x4EB); |
| 1155 | ASSERT_REG_POSITION(vb_element_base, 0x50D); | 1223 | ASSERT_REG_POSITION(vb_element_base, 0x50D); |
| 1224 | ASSERT_REG_POSITION(clip_distance_enabled, 0x544); | ||
| 1156 | ASSERT_REG_POSITION(point_size, 0x546); | 1225 | ASSERT_REG_POSITION(point_size, 0x546); |
| 1157 | ASSERT_REG_POSITION(zeta_enable, 0x54E); | 1226 | ASSERT_REG_POSITION(zeta_enable, 0x54E); |
| 1158 | ASSERT_REG_POSITION(multisample_control, 0x54F); | 1227 | ASSERT_REG_POSITION(multisample_control, 0x54F); |
| 1159 | ASSERT_REG_POSITION(tsc, 0x557); | 1228 | ASSERT_REG_POSITION(tsc, 0x557); |
| 1229 | ASSERT_REG_POSITION(polygon_offset_factor, 0x55b); | ||
| 1160 | ASSERT_REG_POSITION(tic, 0x55D); | 1230 | ASSERT_REG_POSITION(tic, 0x55D); |
| 1161 | ASSERT_REG_POSITION(stencil_two_side_enable, 0x565); | 1231 | ASSERT_REG_POSITION(stencil_two_side_enable, 0x565); |
| 1162 | ASSERT_REG_POSITION(stencil_back_op_fail, 0x566); | 1232 | ASSERT_REG_POSITION(stencil_back_op_fail, 0x566); |
| @@ -1164,13 +1234,18 @@ ASSERT_REG_POSITION(stencil_back_op_zfail, 0x567); | |||
| 1164 | ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568); | 1234 | ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568); |
| 1165 | ASSERT_REG_POSITION(stencil_back_func_func, 0x569); | 1235 | ASSERT_REG_POSITION(stencil_back_func_func, 0x569); |
| 1166 | ASSERT_REG_POSITION(framebuffer_srgb, 0x56E); | 1236 | ASSERT_REG_POSITION(framebuffer_srgb, 0x56E); |
| 1237 | ASSERT_REG_POSITION(polygon_offset_units, 0x56F); | ||
| 1167 | ASSERT_REG_POSITION(point_coord_replace, 0x581); | 1238 | ASSERT_REG_POSITION(point_coord_replace, 0x581); |
| 1168 | ASSERT_REG_POSITION(code_address, 0x582); | 1239 | ASSERT_REG_POSITION(code_address, 0x582); |
| 1169 | ASSERT_REG_POSITION(draw, 0x585); | 1240 | ASSERT_REG_POSITION(draw, 0x585); |
| 1170 | ASSERT_REG_POSITION(primitive_restart, 0x591); | 1241 | ASSERT_REG_POSITION(primitive_restart, 0x591); |
| 1171 | ASSERT_REG_POSITION(index_array, 0x5F2); | 1242 | ASSERT_REG_POSITION(index_array, 0x5F2); |
| 1243 | ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F); | ||
| 1172 | ASSERT_REG_POSITION(instanced_arrays, 0x620); | 1244 | ASSERT_REG_POSITION(instanced_arrays, 0x620); |
| 1173 | ASSERT_REG_POSITION(cull, 0x646); | 1245 | ASSERT_REG_POSITION(cull, 0x646); |
| 1246 | ASSERT_REG_POSITION(pixel_center_integer, 0x649); | ||
| 1247 | ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B); | ||
| 1248 | ASSERT_REG_POSITION(view_volume_clip_control, 0x64F); | ||
| 1174 | ASSERT_REG_POSITION(logic_op, 0x671); | 1249 | ASSERT_REG_POSITION(logic_op, 0x671); |
| 1175 | ASSERT_REG_POSITION(clear_buffers, 0x674); | 1250 | ASSERT_REG_POSITION(clear_buffers, 0x674); |
| 1176 | ASSERT_REG_POSITION(color_mask, 0x680); | 1251 | ASSERT_REG_POSITION(color_mask, 0x680); |
diff --git a/src/video_core/engines/maxwell_compute.cpp b/src/video_core/engines/maxwell_compute.cpp index 8b5f08351..656db6a61 100644 --- a/src/video_core/engines/maxwell_compute.cpp +++ b/src/video_core/engines/maxwell_compute.cpp | |||
| @@ -8,13 +8,13 @@ | |||
| 8 | 8 | ||
| 9 | namespace Tegra::Engines { | 9 | namespace Tegra::Engines { |
| 10 | 10 | ||
| 11 | void MaxwellCompute::WriteReg(u32 method, u32 value) { | 11 | void MaxwellCompute::CallMethod(const GPU::MethodCall& method_call) { |
| 12 | ASSERT_MSG(method < Regs::NUM_REGS, | 12 | ASSERT_MSG(method_call.method < Regs::NUM_REGS, |
| 13 | "Invalid MaxwellCompute register, increase the size of the Regs structure"); | 13 | "Invalid MaxwellCompute register, increase the size of the Regs structure"); |
| 14 | 14 | ||
| 15 | regs.reg_array[method] = value; | 15 | regs.reg_array[method_call.method] = method_call.argument; |
| 16 | 16 | ||
| 17 | switch (method) { | 17 | switch (method_call.method) { |
| 18 | case MAXWELL_COMPUTE_REG_INDEX(compute): { | 18 | case MAXWELL_COMPUTE_REG_INDEX(compute): { |
| 19 | LOG_CRITICAL(HW_GPU, "Compute shaders are not implemented"); | 19 | LOG_CRITICAL(HW_GPU, "Compute shaders are not implemented"); |
| 20 | UNREACHABLE(); | 20 | UNREACHABLE(); |
diff --git a/src/video_core/engines/maxwell_compute.h b/src/video_core/engines/maxwell_compute.h index 6ea934fb9..1d71f11bd 100644 --- a/src/video_core/engines/maxwell_compute.h +++ b/src/video_core/engines/maxwell_compute.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include "common/bit_field.h" | 9 | #include "common/bit_field.h" |
| 10 | #include "common/common_funcs.h" | 10 | #include "common/common_funcs.h" |
| 11 | #include "common/common_types.h" | 11 | #include "common/common_types.h" |
| 12 | #include "video_core/gpu.h" | ||
| 12 | 13 | ||
| 13 | namespace Tegra::Engines { | 14 | namespace Tegra::Engines { |
| 14 | 15 | ||
| @@ -42,7 +43,7 @@ public: | |||
| 42 | "MaxwellCompute Regs has wrong size"); | 43 | "MaxwellCompute Regs has wrong size"); |
| 43 | 44 | ||
| 44 | /// Write the value to the register identified by method. | 45 | /// Write the value to the register identified by method. |
| 45 | void WriteReg(u32 method, u32 value); | 46 | void CallMethod(const GPU::MethodCall& method_call); |
| 46 | }; | 47 | }; |
| 47 | 48 | ||
| 48 | #define ASSERT_REG_POSITION(field_name, position) \ | 49 | #define ASSERT_REG_POSITION(field_name, position) \ |
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp index b8a78cf82..06462f570 100644 --- a/src/video_core/engines/maxwell_dma.cpp +++ b/src/video_core/engines/maxwell_dma.cpp | |||
| @@ -2,7 +2,9 @@ | |||
| 2 | // Licensed under GPLv2 or any later version | 2 | // Licensed under GPLv2 or any later version |
| 3 | // Refer to the license.txt file included. | 3 | // Refer to the license.txt file included. |
| 4 | 4 | ||
| 5 | #include "core/core.h" | ||
| 5 | #include "core/memory.h" | 6 | #include "core/memory.h" |
| 7 | #include "video_core/engines/maxwell_3d.h" | ||
| 6 | #include "video_core/engines/maxwell_dma.h" | 8 | #include "video_core/engines/maxwell_dma.h" |
| 7 | #include "video_core/rasterizer_interface.h" | 9 | #include "video_core/rasterizer_interface.h" |
| 8 | #include "video_core/textures/decoders.h" | 10 | #include "video_core/textures/decoders.h" |
| @@ -12,16 +14,16 @@ namespace Tegra::Engines { | |||
| 12 | MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) | 14 | MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) |
| 13 | : memory_manager(memory_manager), rasterizer{rasterizer} {} | 15 | : memory_manager(memory_manager), rasterizer{rasterizer} {} |
| 14 | 16 | ||
| 15 | void MaxwellDMA::WriteReg(u32 method, u32 value) { | 17 | void MaxwellDMA::CallMethod(const GPU::MethodCall& method_call) { |
| 16 | ASSERT_MSG(method < Regs::NUM_REGS, | 18 | ASSERT_MSG(method_call.method < Regs::NUM_REGS, |
| 17 | "Invalid MaxwellDMA register, increase the size of the Regs structure"); | 19 | "Invalid MaxwellDMA register, increase the size of the Regs structure"); |
| 18 | 20 | ||
| 19 | regs.reg_array[method] = value; | 21 | regs.reg_array[method_call.method] = method_call.argument; |
| 20 | 22 | ||
| 21 | #define MAXWELLDMA_REG_INDEX(field_name) \ | 23 | #define MAXWELLDMA_REG_INDEX(field_name) \ |
| 22 | (offsetof(Tegra::Engines::MaxwellDMA::Regs, field_name) / sizeof(u32)) | 24 | (offsetof(Tegra::Engines::MaxwellDMA::Regs, field_name) / sizeof(u32)) |
| 23 | 25 | ||
| 24 | switch (method) { | 26 | switch (method_call.method) { |
| 25 | case MAXWELLDMA_REG_INDEX(exec): { | 27 | case MAXWELLDMA_REG_INDEX(exec): { |
| 26 | HandleCopy(); | 28 | HandleCopy(); |
| 27 | break; | 29 | break; |
| @@ -54,6 +56,9 @@ void MaxwellDMA::HandleCopy() { | |||
| 54 | return; | 56 | return; |
| 55 | } | 57 | } |
| 56 | 58 | ||
| 59 | // All copies here update the main memory, so mark all rasterizer states as invalid. | ||
| 60 | Core::System::GetInstance().GPU().Maxwell3D().dirty_flags.OnMemoryWrite(); | ||
| 61 | |||
| 57 | if (regs.exec.is_dst_linear && regs.exec.is_src_linear) { | 62 | if (regs.exec.is_dst_linear && regs.exec.is_src_linear) { |
| 58 | // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D | 63 | // When the enable_2d bit is disabled, the copy is performed as if we were copying a 1D |
| 59 | // buffer of length `x_count`, otherwise we copy a 2D image of dimensions (x_count, | 64 | // buffer of length `x_count`, otherwise we copy a 2D image of dimensions (x_count, |
diff --git a/src/video_core/engines/maxwell_dma.h b/src/video_core/engines/maxwell_dma.h index 5f3704f05..1f8cd65d2 100644 --- a/src/video_core/engines/maxwell_dma.h +++ b/src/video_core/engines/maxwell_dma.h | |||
| @@ -24,7 +24,7 @@ public: | |||
| 24 | ~MaxwellDMA() = default; | 24 | ~MaxwellDMA() = default; |
| 25 | 25 | ||
| 26 | /// Write the value to the register identified by method. | 26 | /// Write the value to the register identified by method. |
| 27 | void WriteReg(u32 method, u32 value); | 27 | void CallMethod(const GPU::MethodCall& method_call); |
| 28 | 28 | ||
| 29 | struct Regs { | 29 | struct Regs { |
| 30 | static constexpr std::size_t NUM_REGS = 0x1D6; | 30 | static constexpr std::size_t NUM_REGS = 0x1D6; |
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h index 83a6fd875..b9faaf8e0 100644 --- a/src/video_core/engines/shader_bytecode.h +++ b/src/video_core/engines/shader_bytecode.h | |||
| @@ -82,6 +82,8 @@ union Attribute { | |||
| 82 | Position = 7, | 82 | Position = 7, |
| 83 | Attribute_0 = 8, | 83 | Attribute_0 = 8, |
| 84 | Attribute_31 = 39, | 84 | Attribute_31 = 39, |
| 85 | ClipDistances0123 = 44, | ||
| 86 | ClipDistances4567 = 45, | ||
| 85 | PointCoord = 46, | 87 | PointCoord = 46, |
| 86 | // This attribute contains a tuple of (~, ~, InstanceId, VertexId) when inside a vertex | 88 | // This attribute contains a tuple of (~, ~, InstanceId, VertexId) when inside a vertex |
| 87 | // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval | 89 | // shader, and a tuple of (TessCoord.x, TessCoord.y, TessCoord.z, ~) when inside a Tess Eval |
| @@ -153,6 +155,7 @@ enum class PredCondition : u64 { | |||
| 153 | NotEqual = 5, | 155 | NotEqual = 5, |
| 154 | GreaterEqual = 6, | 156 | GreaterEqual = 6, |
| 155 | LessThanWithNan = 9, | 157 | LessThanWithNan = 9, |
| 158 | LessEqualWithNan = 11, | ||
| 156 | GreaterThanWithNan = 12, | 159 | GreaterThanWithNan = 12, |
| 157 | NotEqualWithNan = 13, | 160 | NotEqualWithNan = 13, |
| 158 | GreaterEqualWithNan = 14, | 161 | GreaterEqualWithNan = 14, |
| @@ -261,7 +264,7 @@ enum class FlowCondition : u64 { | |||
| 261 | Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for? | 264 | Fcsm_Tr = 0x1C, // TODO(bunnei): What is this used for? |
| 262 | }; | 265 | }; |
| 263 | 266 | ||
| 264 | enum class ControlCode : u64 { | 267 | enum class ConditionCode : u64 { |
| 265 | F = 0, | 268 | F = 0, |
| 266 | LT = 1, | 269 | LT = 1, |
| 267 | EQ = 2, | 270 | EQ = 2, |
| @@ -365,6 +368,11 @@ enum class HalfPrecision : u64 { | |||
| 365 | FMZ = 2, | 368 | FMZ = 2, |
| 366 | }; | 369 | }; |
| 367 | 370 | ||
| 371 | enum class R2pMode : u64 { | ||
| 372 | Pr = 0, | ||
| 373 | Cc = 1, | ||
| 374 | }; | ||
| 375 | |||
| 368 | enum class IpaInterpMode : u64 { | 376 | enum class IpaInterpMode : u64 { |
| 369 | Linear = 0, | 377 | Linear = 0, |
| 370 | Perspective = 1, | 378 | Perspective = 1, |
| @@ -569,7 +577,6 @@ union Instruction { | |||
| 569 | BitField<39, 2, u64> tab5cb8_2; | 577 | BitField<39, 2, u64> tab5cb8_2; |
| 570 | BitField<41, 3, u64> tab5c68_1; | 578 | BitField<41, 3, u64> tab5c68_1; |
| 571 | BitField<44, 2, u64> tab5c68_0; | 579 | BitField<44, 2, u64> tab5c68_0; |
| 572 | BitField<47, 1, u64> cc; | ||
| 573 | BitField<48, 1, u64> negate_b; | 580 | BitField<48, 1, u64> negate_b; |
| 574 | } fmul; | 581 | } fmul; |
| 575 | 582 | ||
| @@ -831,7 +838,7 @@ union Instruction { | |||
| 831 | union { | 838 | union { |
| 832 | BitField<0, 3, u64> pred0; | 839 | BitField<0, 3, u64> pred0; |
| 833 | BitField<3, 3, u64> pred3; | 840 | BitField<3, 3, u64> pred3; |
| 834 | BitField<8, 5, ControlCode> cc; // flag in cc | 841 | BitField<8, 5, ConditionCode> cc; // flag in cc |
| 835 | BitField<39, 3, u64> pred39; | 842 | BitField<39, 3, u64> pred39; |
| 836 | BitField<42, 1, u64> neg_pred39; | 843 | BitField<42, 1, u64> neg_pred39; |
| 837 | BitField<45, 4, PredOperation> op; // op with pred39 | 844 | BitField<45, 4, PredOperation> op; // op with pred39 |
| @@ -855,6 +862,12 @@ union Instruction { | |||
| 855 | } hsetp2; | 862 | } hsetp2; |
| 856 | 863 | ||
| 857 | union { | 864 | union { |
| 865 | BitField<40, 1, R2pMode> mode; | ||
| 866 | BitField<41, 2, u64> byte; | ||
| 867 | BitField<20, 7, u64> immediate_mask; | ||
| 868 | } r2p; | ||
| 869 | |||
| 870 | union { | ||
| 858 | BitField<39, 3, u64> pred39; | 871 | BitField<39, 3, u64> pred39; |
| 859 | BitField<42, 1, u64> neg_pred; | 872 | BitField<42, 1, u64> neg_pred; |
| 860 | BitField<43, 1, u64> neg_a; | 873 | BitField<43, 1, u64> neg_a; |
| @@ -1235,7 +1248,7 @@ union Instruction { | |||
| 1235 | BitField<60, 1, u64> is_b_gpr; | 1248 | BitField<60, 1, u64> is_b_gpr; |
| 1236 | BitField<59, 1, u64> is_c_gpr; | 1249 | BitField<59, 1, u64> is_c_gpr; |
| 1237 | BitField<20, 24, s64> smem_imm; | 1250 | BitField<20, 24, s64> smem_imm; |
| 1238 | BitField<0, 5, ControlCode> flow_control_code; | 1251 | BitField<0, 5, ConditionCode> flow_condition_code; |
| 1239 | 1252 | ||
| 1240 | Attribute attribute; | 1253 | Attribute attribute; |
| 1241 | Sampler sampler; | 1254 | Sampler sampler; |
| @@ -1256,6 +1269,7 @@ public: | |||
| 1256 | BFE_C, | 1269 | BFE_C, |
| 1257 | BFE_R, | 1270 | BFE_R, |
| 1258 | BFE_IMM, | 1271 | BFE_IMM, |
| 1272 | BFI_IMM_R, | ||
| 1259 | BRA, | 1273 | BRA, |
| 1260 | PBK, | 1274 | PBK, |
| 1261 | LD_A, | 1275 | LD_A, |
| @@ -1381,6 +1395,7 @@ public: | |||
| 1381 | PSETP, | 1395 | PSETP, |
| 1382 | PSET, | 1396 | PSET, |
| 1383 | CSETP, | 1397 | CSETP, |
| 1398 | R2P_IMM, | ||
| 1384 | XMAD_IMM, | 1399 | XMAD_IMM, |
| 1385 | XMAD_CR, | 1400 | XMAD_CR, |
| 1386 | XMAD_RC, | 1401 | XMAD_RC, |
| @@ -1396,6 +1411,7 @@ public: | |||
| 1396 | ArithmeticHalf, | 1411 | ArithmeticHalf, |
| 1397 | ArithmeticHalfImmediate, | 1412 | ArithmeticHalfImmediate, |
| 1398 | Bfe, | 1413 | Bfe, |
| 1414 | Bfi, | ||
| 1399 | Shift, | 1415 | Shift, |
| 1400 | Ffma, | 1416 | Ffma, |
| 1401 | Hfma2, | 1417 | Hfma2, |
| @@ -1410,6 +1426,7 @@ public: | |||
| 1410 | HalfSetPredicate, | 1426 | HalfSetPredicate, |
| 1411 | PredicateSetPredicate, | 1427 | PredicateSetPredicate, |
| 1412 | PredicateSetRegister, | 1428 | PredicateSetRegister, |
| 1429 | RegisterSetPredicate, | ||
| 1413 | Conversion, | 1430 | Conversion, |
| 1414 | Xmad, | 1431 | Xmad, |
| 1415 | Unknown, | 1432 | Unknown, |
| @@ -1613,6 +1630,7 @@ private: | |||
| 1613 | INST("0100110000000---", Id::BFE_C, Type::Bfe, "BFE_C"), | 1630 | INST("0100110000000---", Id::BFE_C, Type::Bfe, "BFE_C"), |
| 1614 | INST("0101110000000---", Id::BFE_R, Type::Bfe, "BFE_R"), | 1631 | INST("0101110000000---", Id::BFE_R, Type::Bfe, "BFE_R"), |
| 1615 | INST("0011100-00000---", Id::BFE_IMM, Type::Bfe, "BFE_IMM"), | 1632 | INST("0011100-00000---", Id::BFE_IMM, Type::Bfe, "BFE_IMM"), |
| 1633 | INST("0011011-11110---", Id::BFI_IMM_R, Type::Bfi, "BFI_IMM_R"), | ||
| 1616 | INST("0100110001000---", Id::LOP_C, Type::ArithmeticInteger, "LOP_C"), | 1634 | INST("0100110001000---", Id::LOP_C, Type::ArithmeticInteger, "LOP_C"), |
| 1617 | INST("0101110001000---", Id::LOP_R, Type::ArithmeticInteger, "LOP_R"), | 1635 | INST("0101110001000---", Id::LOP_R, Type::ArithmeticInteger, "LOP_R"), |
| 1618 | INST("0011100001000---", Id::LOP_IMM, Type::ArithmeticInteger, "LOP_IMM"), | 1636 | INST("0011100001000---", Id::LOP_IMM, Type::ArithmeticInteger, "LOP_IMM"), |
| @@ -1647,6 +1665,7 @@ private: | |||
| 1647 | INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"), | 1665 | INST("0101000010001---", Id::PSET, Type::PredicateSetRegister, "PSET"), |
| 1648 | INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), | 1666 | INST("0101000010010---", Id::PSETP, Type::PredicateSetPredicate, "PSETP"), |
| 1649 | INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"), | 1667 | INST("010100001010----", Id::CSETP, Type::PredicateSetPredicate, "CSETP"), |
| 1668 | INST("0011100-11110---", Id::R2P_IMM, Type::RegisterSetPredicate, "R2P_IMM"), | ||
| 1650 | INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), | 1669 | INST("0011011-00------", Id::XMAD_IMM, Type::Xmad, "XMAD_IMM"), |
| 1651 | INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), | 1670 | INST("0100111---------", Id::XMAD_CR, Type::Xmad, "XMAD_CR"), |
| 1652 | INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"), | 1671 | INST("010100010-------", Id::XMAD_RC, Type::Xmad, "XMAD_RC"), |
diff --git a/src/video_core/engines/shader_header.h b/src/video_core/engines/shader_header.h index a0e015c4b..99c34649f 100644 --- a/src/video_core/engines/shader_header.h +++ b/src/video_core/engines/shader_header.h | |||
| @@ -62,7 +62,16 @@ struct Header { | |||
| 62 | INSERT_PADDING_BYTES(1); // ImapSystemValuesB | 62 | INSERT_PADDING_BYTES(1); // ImapSystemValuesB |
| 63 | INSERT_PADDING_BYTES(16); // ImapGenericVector[32] | 63 | INSERT_PADDING_BYTES(16); // ImapGenericVector[32] |
| 64 | INSERT_PADDING_BYTES(2); // ImapColor | 64 | INSERT_PADDING_BYTES(2); // ImapColor |
| 65 | INSERT_PADDING_BYTES(2); // ImapSystemValuesC | 65 | union { |
| 66 | BitField<0, 8, u16> clip_distances; | ||
| 67 | BitField<8, 1, u16> point_sprite_s; | ||
| 68 | BitField<9, 1, u16> point_sprite_t; | ||
| 69 | BitField<10, 1, u16> fog_coordinate; | ||
| 70 | BitField<12, 1, u16> tessellation_eval_point_u; | ||
| 71 | BitField<13, 1, u16> tessellation_eval_point_v; | ||
| 72 | BitField<14, 1, u16> instance_id; | ||
| 73 | BitField<15, 1, u16> vertex_id; | ||
| 74 | }; | ||
| 66 | INSERT_PADDING_BYTES(5); // ImapFixedFncTexture[10] | 75 | INSERT_PADDING_BYTES(5); // ImapFixedFncTexture[10] |
| 67 | INSERT_PADDING_BYTES(1); // ImapReserved | 76 | INSERT_PADDING_BYTES(1); // ImapReserved |
| 68 | INSERT_PADDING_BYTES(3); // OmapSystemValuesA | 77 | INSERT_PADDING_BYTES(3); // OmapSystemValuesA |
diff --git a/src/video_core/gpu.cpp b/src/video_core/gpu.cpp index 51b3904f6..6c81dee64 100644 --- a/src/video_core/gpu.cpp +++ b/src/video_core/gpu.cpp | |||
| @@ -26,6 +26,7 @@ u32 FramebufferConfig::BytesPerPixel(PixelFormat format) { | |||
| 26 | 26 | ||
| 27 | GPU::GPU(VideoCore::RasterizerInterface& rasterizer) { | 27 | GPU::GPU(VideoCore::RasterizerInterface& rasterizer) { |
| 28 | memory_manager = std::make_unique<Tegra::MemoryManager>(); | 28 | memory_manager = std::make_unique<Tegra::MemoryManager>(); |
| 29 | dma_pusher = std::make_unique<Tegra::DmaPusher>(*this); | ||
| 29 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager); | 30 | maxwell_3d = std::make_unique<Engines::Maxwell3D>(rasterizer, *memory_manager); |
| 30 | fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager); | 31 | fermi_2d = std::make_unique<Engines::Fermi2D>(rasterizer, *memory_manager); |
| 31 | maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); | 32 | maxwell_compute = std::make_unique<Engines::MaxwellCompute>(); |
| @@ -51,6 +52,14 @@ const MemoryManager& GPU::MemoryManager() const { | |||
| 51 | return *memory_manager; | 52 | return *memory_manager; |
| 52 | } | 53 | } |
| 53 | 54 | ||
| 55 | DmaPusher& GPU::DmaPusher() { | ||
| 56 | return *dma_pusher; | ||
| 57 | } | ||
| 58 | |||
| 59 | const DmaPusher& GPU::DmaPusher() const { | ||
| 60 | return *dma_pusher; | ||
| 61 | } | ||
| 62 | |||
| 54 | u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { | 63 | u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { |
| 55 | ASSERT(format != RenderTargetFormat::NONE); | 64 | ASSERT(format != RenderTargetFormat::NONE); |
| 56 | 65 | ||
| @@ -113,4 +122,48 @@ u32 DepthFormatBytesPerPixel(DepthFormat format) { | |||
| 113 | } | 122 | } |
| 114 | } | 123 | } |
| 115 | 124 | ||
| 125 | enum class BufferMethods { | ||
| 126 | BindObject = 0, | ||
| 127 | CountBufferMethods = 0x40, | ||
| 128 | }; | ||
| 129 | |||
| 130 | void GPU::CallMethod(const MethodCall& method_call) { | ||
| 131 | LOG_TRACE(HW_GPU, | ||
| 132 | "Processing method {:08X} on subchannel {} value " | ||
| 133 | "{:08X} remaining params {}", | ||
| 134 | MethCall.method, MethCall.subchannel, value, remaining_params); | ||
| 135 | |||
| 136 | ASSERT(method_call.subchannel < bound_engines.size()); | ||
| 137 | |||
| 138 | if (method_call.method == static_cast<u32>(BufferMethods::BindObject)) { | ||
| 139 | // Bind the current subchannel to the desired engine id. | ||
| 140 | LOG_DEBUG(HW_GPU, "Binding subchannel {} to engine {}", method_call.subchannel, | ||
| 141 | method_call.argument); | ||
| 142 | bound_engines[method_call.subchannel] = static_cast<EngineID>(method_call.argument); | ||
| 143 | return; | ||
| 144 | } | ||
| 145 | |||
| 146 | const EngineID engine = bound_engines[method_call.subchannel]; | ||
| 147 | |||
| 148 | switch (engine) { | ||
| 149 | case EngineID::FERMI_TWOD_A: | ||
| 150 | fermi_2d->CallMethod(method_call); | ||
| 151 | break; | ||
| 152 | case EngineID::MAXWELL_B: | ||
| 153 | maxwell_3d->CallMethod(method_call); | ||
| 154 | break; | ||
| 155 | case EngineID::MAXWELL_COMPUTE_B: | ||
| 156 | maxwell_compute->CallMethod(method_call); | ||
| 157 | break; | ||
| 158 | case EngineID::MAXWELL_DMA_COPY_A: | ||
| 159 | maxwell_dma->CallMethod(method_call); | ||
| 160 | break; | ||
| 161 | case EngineID::KEPLER_INLINE_TO_MEMORY_B: | ||
| 162 | kepler_memory->CallMethod(method_call); | ||
| 163 | break; | ||
| 164 | default: | ||
| 165 | UNIMPLEMENTED_MSG("Unimplemented engine"); | ||
| 166 | } | ||
| 167 | } | ||
| 168 | |||
| 116 | } // namespace Tegra | 169 | } // namespace Tegra |
diff --git a/src/video_core/gpu.h b/src/video_core/gpu.h index 5cc1e19ca..af5ccd1e9 100644 --- a/src/video_core/gpu.h +++ b/src/video_core/gpu.h | |||
| @@ -9,6 +9,7 @@ | |||
| 9 | #include <vector> | 9 | #include <vector> |
| 10 | #include "common/common_types.h" | 10 | #include "common/common_types.h" |
| 11 | #include "core/hle/service/nvflinger/buffer_queue.h" | 11 | #include "core/hle/service/nvflinger/buffer_queue.h" |
| 12 | #include "video_core/dma_pusher.h" | ||
| 12 | #include "video_core/memory_manager.h" | 13 | #include "video_core/memory_manager.h" |
| 13 | 14 | ||
| 14 | namespace VideoCore { | 15 | namespace VideoCore { |
| @@ -119,8 +120,23 @@ public: | |||
| 119 | explicit GPU(VideoCore::RasterizerInterface& rasterizer); | 120 | explicit GPU(VideoCore::RasterizerInterface& rasterizer); |
| 120 | ~GPU(); | 121 | ~GPU(); |
| 121 | 122 | ||
| 122 | /// Processes a command list stored at the specified address in GPU memory. | 123 | struct MethodCall { |
| 123 | void ProcessCommandLists(const std::vector<CommandListHeader>& commands); | 124 | u32 method{}; |
| 125 | u32 argument{}; | ||
| 126 | u32 subchannel{}; | ||
| 127 | u32 method_count{}; | ||
| 128 | |||
| 129 | bool IsLastCall() const { | ||
| 130 | return method_count <= 1; | ||
| 131 | } | ||
| 132 | |||
| 133 | MethodCall(u32 method, u32 argument, u32 subchannel = 0, u32 method_count = 0) | ||
| 134 | : method(method), argument(argument), subchannel(subchannel), | ||
| 135 | method_count(method_count) {} | ||
| 136 | }; | ||
| 137 | |||
| 138 | /// Calls a GPU method. | ||
| 139 | void CallMethod(const MethodCall& method_call); | ||
| 124 | 140 | ||
| 125 | /// Returns a reference to the Maxwell3D GPU engine. | 141 | /// Returns a reference to the Maxwell3D GPU engine. |
| 126 | Engines::Maxwell3D& Maxwell3D(); | 142 | Engines::Maxwell3D& Maxwell3D(); |
| @@ -134,7 +150,14 @@ public: | |||
| 134 | /// Returns a const reference to the GPU memory manager. | 150 | /// Returns a const reference to the GPU memory manager. |
| 135 | const Tegra::MemoryManager& MemoryManager() const; | 151 | const Tegra::MemoryManager& MemoryManager() const; |
| 136 | 152 | ||
| 153 | /// Returns a reference to the GPU DMA pusher. | ||
| 154 | Tegra::DmaPusher& DmaPusher(); | ||
| 155 | |||
| 156 | /// Returns a const reference to the GPU DMA pusher. | ||
| 157 | const Tegra::DmaPusher& DmaPusher() const; | ||
| 158 | |||
| 137 | private: | 159 | private: |
| 160 | std::unique_ptr<Tegra::DmaPusher> dma_pusher; | ||
| 138 | std::unique_ptr<Tegra::MemoryManager> memory_manager; | 161 | std::unique_ptr<Tegra::MemoryManager> memory_manager; |
| 139 | 162 | ||
| 140 | /// Mapping of command subchannels to their bound engine ids. | 163 | /// Mapping of command subchannels to their bound engine ids. |
diff --git a/src/video_core/macro_interpreter.cpp b/src/video_core/macro_interpreter.cpp index 335a8d407..9c55e9f1e 100644 --- a/src/video_core/macro_interpreter.cpp +++ b/src/video_core/macro_interpreter.cpp | |||
| @@ -35,6 +35,7 @@ void MacroInterpreter::Reset() { | |||
| 35 | // The next parameter index starts at 1, because $r1 already has the value of the first | 35 | // The next parameter index starts at 1, because $r1 already has the value of the first |
| 36 | // parameter. | 36 | // parameter. |
| 37 | next_parameter_index = 1; | 37 | next_parameter_index = 1; |
| 38 | carry_flag = false; | ||
| 38 | } | 39 | } |
| 39 | 40 | ||
| 40 | bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) { | 41 | bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) { |
| @@ -135,14 +136,28 @@ MacroInterpreter::Opcode MacroInterpreter::GetOpcode(u32 offset) const { | |||
| 135 | return {macro_memory[offset + pc / sizeof(u32)]}; | 136 | return {macro_memory[offset + pc / sizeof(u32)]}; |
| 136 | } | 137 | } |
| 137 | 138 | ||
| 138 | u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const { | 139 | u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) { |
| 139 | switch (operation) { | 140 | switch (operation) { |
| 140 | case ALUOperation::Add: | 141 | case ALUOperation::Add: { |
| 141 | return src_a + src_b; | 142 | const u64 result{static_cast<u64>(src_a) + src_b}; |
| 142 | // TODO(Subv): Implement AddWithCarry | 143 | carry_flag = result > 0xffffffff; |
| 143 | case ALUOperation::Subtract: | 144 | return static_cast<u32>(result); |
| 144 | return src_a - src_b; | 145 | } |
| 145 | // TODO(Subv): Implement SubtractWithBorrow | 146 | case ALUOperation::AddWithCarry: { |
| 147 | const u64 result{static_cast<u64>(src_a) + src_b + (carry_flag ? 1ULL : 0ULL)}; | ||
| 148 | carry_flag = result > 0xffffffff; | ||
| 149 | return static_cast<u32>(result); | ||
| 150 | } | ||
| 151 | case ALUOperation::Subtract: { | ||
| 152 | const u64 result{static_cast<u64>(src_a) - src_b}; | ||
| 153 | carry_flag = result < 0x100000000; | ||
| 154 | return static_cast<u32>(result); | ||
| 155 | } | ||
| 156 | case ALUOperation::SubtractWithBorrow: { | ||
| 157 | const u64 result{static_cast<u64>(src_a) - src_b - (carry_flag ? 0ULL : 1ULL)}; | ||
| 158 | carry_flag = result < 0x100000000; | ||
| 159 | return static_cast<u32>(result); | ||
| 160 | } | ||
| 146 | case ALUOperation::Xor: | 161 | case ALUOperation::Xor: |
| 147 | return src_a ^ src_b; | 162 | return src_a ^ src_b; |
| 148 | case ALUOperation::Or: | 163 | case ALUOperation::Or: |
| @@ -235,7 +250,7 @@ void MacroInterpreter::SetMethodAddress(u32 address) { | |||
| 235 | } | 250 | } |
| 236 | 251 | ||
| 237 | void MacroInterpreter::Send(u32 value) { | 252 | void MacroInterpreter::Send(u32 value) { |
| 238 | maxwell3d.WriteReg(method_address.address, value, 0); | 253 | maxwell3d.CallMethod({method_address.address, value}); |
| 239 | // Increment the method address by the method increment. | 254 | // Increment the method address by the method increment. |
| 240 | method_address.address.Assign(method_address.address.Value() + | 255 | method_address.address.Assign(method_address.address.Value() + |
| 241 | method_address.increment.Value()); | 256 | method_address.increment.Value()); |
diff --git a/src/video_core/macro_interpreter.h b/src/video_core/macro_interpreter.h index 62d1ce289..cde360288 100644 --- a/src/video_core/macro_interpreter.h +++ b/src/video_core/macro_interpreter.h | |||
| @@ -117,7 +117,7 @@ private: | |||
| 117 | bool Step(u32 offset, bool is_delay_slot); | 117 | bool Step(u32 offset, bool is_delay_slot); |
| 118 | 118 | ||
| 119 | /// Calculates the result of an ALU operation. src_a OP src_b; | 119 | /// Calculates the result of an ALU operation. src_a OP src_b; |
| 120 | u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const; | 120 | u32 GetALUResult(ALUOperation operation, u32 src_a, u32 src_b); |
| 121 | 121 | ||
| 122 | /// Performs the result operation on the input result and stores it in the specified register | 122 | /// Performs the result operation on the input result and stores it in the specified register |
| 123 | /// (if necessary). | 123 | /// (if necessary). |
| @@ -165,5 +165,7 @@ private: | |||
| 165 | std::vector<u32> parameters; | 165 | std::vector<u32> parameters; |
| 166 | /// Index of the next parameter that will be fetched by the 'parm' instruction. | 166 | /// Index of the next parameter that will be fetched by the 'parm' instruction. |
| 167 | u32 next_parameter_index = 0; | 167 | u32 next_parameter_index = 0; |
| 168 | |||
| 169 | bool carry_flag{}; | ||
| 168 | }; | 170 | }; |
| 169 | } // namespace Tegra | 171 | } // namespace Tegra |
diff --git a/src/video_core/memory_manager.cpp b/src/video_core/memory_manager.cpp index 77a20bb84..47247f097 100644 --- a/src/video_core/memory_manager.cpp +++ b/src/video_core/memory_manager.cpp | |||
| @@ -9,6 +9,13 @@ | |||
| 9 | 9 | ||
| 10 | namespace Tegra { | 10 | namespace Tegra { |
| 11 | 11 | ||
| 12 | MemoryManager::MemoryManager() { | ||
| 13 | // Mark the first page as reserved, so that 0 is not a valid GPUVAddr. Otherwise, games might | ||
| 14 | // try to use 0 as a valid address, which is also used to mean nullptr. This fixes a bug with | ||
| 15 | // Undertale using 0 for a render target. | ||
| 16 | PageSlot(0) = static_cast<u64>(PageStatus::Reserved); | ||
| 17 | } | ||
| 18 | |||
| 12 | GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) { | 19 | GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) { |
| 13 | const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, align, PageStatus::Unmapped)}; | 20 | const std::optional<GPUVAddr> gpu_addr{FindFreeBlock(0, size, align, PageStatus::Unmapped)}; |
| 14 | 21 | ||
diff --git a/src/video_core/memory_manager.h b/src/video_core/memory_manager.h index 4eb338aa2..fb03497ca 100644 --- a/src/video_core/memory_manager.h +++ b/src/video_core/memory_manager.h | |||
| @@ -18,7 +18,7 @@ using GPUVAddr = u64; | |||
| 18 | 18 | ||
| 19 | class MemoryManager final { | 19 | class MemoryManager final { |
| 20 | public: | 20 | public: |
| 21 | MemoryManager() = default; | 21 | MemoryManager(); |
| 22 | 22 | ||
| 23 | GPUVAddr AllocateSpace(u64 size, u64 align); | 23 | GPUVAddr AllocateSpace(u64 size, u64 align); |
| 24 | GPUVAddr AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align); | 24 | GPUVAddr AllocateSpace(GPUVAddr gpu_addr, u64 size, u64 align); |
| @@ -37,6 +37,7 @@ private: | |||
| 37 | enum class PageStatus : u64 { | 37 | enum class PageStatus : u64 { |
| 38 | Unmapped = 0xFFFFFFFFFFFFFFFFULL, | 38 | Unmapped = 0xFFFFFFFFFFFFFFFFULL, |
| 39 | Allocated = 0xFFFFFFFFFFFFFFFEULL, | 39 | Allocated = 0xFFFFFFFFFFFFFFFEULL, |
| 40 | Reserved = 0xFFFFFFFFFFFFFFFDULL, | ||
| 40 | }; | 41 | }; |
| 41 | 42 | ||
| 42 | std::optional<GPUVAddr> FindFreeBlock(GPUVAddr region_start, u64 size, u64 align, | 43 | std::optional<GPUVAddr> FindFreeBlock(GPUVAddr region_start, u64 size, u64 align, |
diff --git a/src/video_core/morton.cpp b/src/video_core/morton.cpp new file mode 100644 index 000000000..a310491a8 --- /dev/null +++ b/src/video_core/morton.cpp | |||
| @@ -0,0 +1,355 @@ | |||
| 1 | // Copyright 2018 yuzu Emulator Project | ||
| 2 | // Licensed under GPLv2 or any later version | ||
| 3 | // Refer to the license.txt file included. | ||
| 4 | |||
| 5 | #include <array> | ||
| 6 | #include <cstring> | ||
| 7 | #include "common/assert.h" | ||
| 8 | #include "common/common_types.h" | ||
| 9 | #include "core/memory.h" | ||
| 10 | #include "video_core/morton.h" | ||
| 11 | #include "video_core/surface.h" | ||
| 12 | #include "video_core/textures/decoders.h" | ||
| 13 | |||
| 14 | namespace VideoCore { | ||
| 15 | |||
| 16 | using Surface::GetBytesPerPixel; | ||
| 17 | using Surface::PixelFormat; | ||
| 18 | |||
| 19 | using MortonCopyFn = void (*)(u32, u32, u32, u32, u32, u32, u8*, std::size_t, VAddr); | ||
| 20 | using ConversionArray = std::array<MortonCopyFn, Surface::MaxPixelFormat>; | ||
| 21 | |||
| 22 | template <bool morton_to_linear, PixelFormat format> | ||
| 23 | static void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, | ||
| 24 | u32 tile_width_spacing, u8* buffer, std::size_t buffer_size, VAddr addr) { | ||
| 25 | constexpr u32 bytes_per_pixel = GetBytesPerPixel(format); | ||
| 26 | |||
| 27 | // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual | ||
| 28 | // pixel values. | ||
| 29 | const u32 tile_size_x{GetDefaultBlockWidth(format)}; | ||
| 30 | const u32 tile_size_y{GetDefaultBlockHeight(format)}; | ||
| 31 | |||
| 32 | if constexpr (morton_to_linear) { | ||
| 33 | Tegra::Texture::UnswizzleTexture(buffer, addr, tile_size_x, tile_size_y, bytes_per_pixel, | ||
| 34 | stride, height, depth, block_height, block_depth, | ||
| 35 | tile_width_spacing); | ||
| 36 | } else { | ||
| 37 | Tegra::Texture::CopySwizzledData( | ||
| 38 | (stride + tile_size_x - 1) / tile_size_x, (height + tile_size_y - 1) / tile_size_y, | ||
| 39 | depth, bytes_per_pixel, bytes_per_pixel, Memory::GetPointer(addr), buffer, false, | ||
| 40 | block_height, block_depth, tile_width_spacing); | ||
| 41 | } | ||
| 42 | } | ||
| 43 | |||
| 44 | static constexpr ConversionArray morton_to_linear_fns = { | ||
| 45 | // clang-format off | ||
| 46 | MortonCopy<true, PixelFormat::ABGR8U>, | ||
| 47 | MortonCopy<true, PixelFormat::ABGR8S>, | ||
| 48 | MortonCopy<true, PixelFormat::ABGR8UI>, | ||
| 49 | MortonCopy<true, PixelFormat::B5G6R5U>, | ||
| 50 | MortonCopy<true, PixelFormat::A2B10G10R10U>, | ||
| 51 | MortonCopy<true, PixelFormat::A1B5G5R5U>, | ||
| 52 | MortonCopy<true, PixelFormat::R8U>, | ||
| 53 | MortonCopy<true, PixelFormat::R8UI>, | ||
| 54 | MortonCopy<true, PixelFormat::RGBA16F>, | ||
| 55 | MortonCopy<true, PixelFormat::RGBA16U>, | ||
| 56 | MortonCopy<true, PixelFormat::RGBA16UI>, | ||
| 57 | MortonCopy<true, PixelFormat::R11FG11FB10F>, | ||
| 58 | MortonCopy<true, PixelFormat::RGBA32UI>, | ||
| 59 | MortonCopy<true, PixelFormat::DXT1>, | ||
| 60 | MortonCopy<true, PixelFormat::DXT23>, | ||
| 61 | MortonCopy<true, PixelFormat::DXT45>, | ||
| 62 | MortonCopy<true, PixelFormat::DXN1>, | ||
| 63 | MortonCopy<true, PixelFormat::DXN2UNORM>, | ||
| 64 | MortonCopy<true, PixelFormat::DXN2SNORM>, | ||
| 65 | MortonCopy<true, PixelFormat::BC7U>, | ||
| 66 | MortonCopy<true, PixelFormat::BC6H_UF16>, | ||
| 67 | MortonCopy<true, PixelFormat::BC6H_SF16>, | ||
| 68 | MortonCopy<true, PixelFormat::ASTC_2D_4X4>, | ||
| 69 | MortonCopy<true, PixelFormat::G8R8U>, | ||
| 70 | MortonCopy<true, PixelFormat::G8R8S>, | ||
| 71 | MortonCopy<true, PixelFormat::BGRA8>, | ||
| 72 | MortonCopy<true, PixelFormat::RGBA32F>, | ||
| 73 | MortonCopy<true, PixelFormat::RG32F>, | ||
| 74 | MortonCopy<true, PixelFormat::R32F>, | ||
| 75 | MortonCopy<true, PixelFormat::R16F>, | ||
| 76 | MortonCopy<true, PixelFormat::R16U>, | ||
| 77 | MortonCopy<true, PixelFormat::R16S>, | ||
| 78 | MortonCopy<true, PixelFormat::R16UI>, | ||
| 79 | MortonCopy<true, PixelFormat::R16I>, | ||
| 80 | MortonCopy<true, PixelFormat::RG16>, | ||
| 81 | MortonCopy<true, PixelFormat::RG16F>, | ||
| 82 | MortonCopy<true, PixelFormat::RG16UI>, | ||
| 83 | MortonCopy<true, PixelFormat::RG16I>, | ||
| 84 | MortonCopy<true, PixelFormat::RG16S>, | ||
| 85 | MortonCopy<true, PixelFormat::RGB32F>, | ||
| 86 | MortonCopy<true, PixelFormat::RGBA8_SRGB>, | ||
| 87 | MortonCopy<true, PixelFormat::RG8U>, | ||
| 88 | MortonCopy<true, PixelFormat::RG8S>, | ||
| 89 | MortonCopy<true, PixelFormat::RG32UI>, | ||
| 90 | MortonCopy<true, PixelFormat::R32UI>, | ||
| 91 | MortonCopy<true, PixelFormat::ASTC_2D_8X8>, | ||
| 92 | MortonCopy<true, PixelFormat::ASTC_2D_8X5>, | ||
| 93 | MortonCopy<true, PixelFormat::ASTC_2D_5X4>, | ||
| 94 | MortonCopy<true, PixelFormat::BGRA8_SRGB>, | ||
| 95 | MortonCopy<true, PixelFormat::DXT1_SRGB>, | ||
| 96 | MortonCopy<true, PixelFormat::DXT23_SRGB>, | ||
| 97 | MortonCopy<true, PixelFormat::DXT45_SRGB>, | ||
| 98 | MortonCopy<true, PixelFormat::BC7U_SRGB>, | ||
| 99 | MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>, | ||
| 100 | MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>, | ||
| 101 | MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>, | ||
| 102 | MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>, | ||
| 103 | MortonCopy<true, PixelFormat::ASTC_2D_5X5>, | ||
| 104 | MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>, | ||
| 105 | MortonCopy<true, PixelFormat::ASTC_2D_10X8>, | ||
| 106 | MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>, | ||
| 107 | MortonCopy<true, PixelFormat::Z32F>, | ||
| 108 | MortonCopy<true, PixelFormat::Z16>, | ||
| 109 | MortonCopy<true, PixelFormat::Z24S8>, | ||
| 110 | MortonCopy<true, PixelFormat::S8Z24>, | ||
| 111 | MortonCopy<true, PixelFormat::Z32FS8>, | ||
| 112 | // clang-format on | ||
| 113 | }; | ||
| 114 | |||
| 115 | static constexpr ConversionArray linear_to_morton_fns = { | ||
| 116 | // clang-format off | ||
| 117 | MortonCopy<false, PixelFormat::ABGR8U>, | ||
| 118 | MortonCopy<false, PixelFormat::ABGR8S>, | ||
| 119 | MortonCopy<false, PixelFormat::ABGR8UI>, | ||
| 120 | MortonCopy<false, PixelFormat::B5G6R5U>, | ||
| 121 | MortonCopy<false, PixelFormat::A2B10G10R10U>, | ||
| 122 | MortonCopy<false, PixelFormat::A1B5G5R5U>, | ||
| 123 | MortonCopy<false, PixelFormat::R8U>, | ||
| 124 | MortonCopy<false, PixelFormat::R8UI>, | ||
| 125 | MortonCopy<false, PixelFormat::RGBA16F>, | ||
| 126 | MortonCopy<false, PixelFormat::RGBA16U>, | ||
| 127 | MortonCopy<false, PixelFormat::RGBA16UI>, | ||
| 128 | MortonCopy<false, PixelFormat::R11FG11FB10F>, | ||
| 129 | MortonCopy<false, PixelFormat::RGBA32UI>, | ||
| 130 | MortonCopy<false, PixelFormat::DXT1>, | ||
| 131 | MortonCopy<false, PixelFormat::DXT23>, | ||
| 132 | MortonCopy<false, PixelFormat::DXT45>, | ||
| 133 | MortonCopy<false, PixelFormat::DXN1>, | ||
| 134 | MortonCopy<false, PixelFormat::DXN2UNORM>, | ||
| 135 | MortonCopy<false, PixelFormat::DXN2SNORM>, | ||
| 136 | MortonCopy<false, PixelFormat::BC7U>, | ||
| 137 | MortonCopy<false, PixelFormat::BC6H_UF16>, | ||
| 138 | MortonCopy<false, PixelFormat::BC6H_SF16>, | ||
| 139 | // TODO(Subv): Swizzling ASTC formats are not supported | ||
| 140 | nullptr, | ||
| 141 | MortonCopy<false, PixelFormat::G8R8U>, | ||
| 142 | MortonCopy<false, PixelFormat::G8R8S>, | ||
| 143 | MortonCopy<false, PixelFormat::BGRA8>, | ||
| 144 | MortonCopy<false, PixelFormat::RGBA32F>, | ||
| 145 | MortonCopy<false, PixelFormat::RG32F>, | ||
| 146 | MortonCopy<false, PixelFormat::R32F>, | ||
| 147 | MortonCopy<false, PixelFormat::R16F>, | ||
| 148 | MortonCopy<false, PixelFormat::R16U>, | ||
| 149 | MortonCopy<false, PixelFormat::R16S>, | ||
| 150 | MortonCopy<false, PixelFormat::R16UI>, | ||
| 151 | MortonCopy<false, PixelFormat::R16I>, | ||
| 152 | MortonCopy<false, PixelFormat::RG16>, | ||
| 153 | MortonCopy<false, PixelFormat::RG16F>, | ||
| 154 | MortonCopy<false, PixelFormat::RG16UI>, | ||
| 155 | MortonCopy<false, PixelFormat::RG16I>, | ||
| 156 | MortonCopy<false, PixelFormat::RG16S>, | ||
| 157 | MortonCopy<false, PixelFormat::RGB32F>, | ||
| 158 | MortonCopy<false, PixelFormat::RGBA8_SRGB>, | ||
| 159 | MortonCopy<false, PixelFormat::RG8U>, | ||
| 160 | MortonCopy<false, PixelFormat::RG8S>, | ||
| 161 | MortonCopy<false, PixelFormat::RG32UI>, | ||
| 162 | MortonCopy<false, PixelFormat::R32UI>, | ||
| 163 | nullptr, | ||
| 164 | nullptr, | ||
| 165 | nullptr, | ||
| 166 | MortonCopy<false, PixelFormat::BGRA8_SRGB>, | ||
| 167 | MortonCopy<false, PixelFormat::DXT1_SRGB>, | ||
| 168 | MortonCopy<false, PixelFormat::DXT23_SRGB>, | ||
| 169 | MortonCopy<false, PixelFormat::DXT45_SRGB>, | ||
| 170 | MortonCopy<false, PixelFormat::BC7U_SRGB>, | ||
| 171 | nullptr, | ||
| 172 | nullptr, | ||
| 173 | nullptr, | ||
| 174 | nullptr, | ||
| 175 | nullptr, | ||
| 176 | nullptr, | ||
| 177 | nullptr, | ||
| 178 | nullptr, | ||
| 179 | MortonCopy<false, PixelFormat::Z32F>, | ||
| 180 | MortonCopy<false, PixelFormat::Z16>, | ||
| 181 | MortonCopy<false, PixelFormat::Z24S8>, | ||
| 182 | MortonCopy<false, PixelFormat::S8Z24>, | ||
| 183 | MortonCopy<false, PixelFormat::Z32FS8>, | ||
| 184 | // clang-format on | ||
| 185 | }; | ||
| 186 | |||
| 187 | static MortonCopyFn GetSwizzleFunction(MortonSwizzleMode mode, Surface::PixelFormat format) { | ||
| 188 | switch (mode) { | ||
| 189 | case MortonSwizzleMode::MortonToLinear: | ||
| 190 | return morton_to_linear_fns[static_cast<std::size_t>(format)]; | ||
| 191 | case MortonSwizzleMode::LinearToMorton: | ||
| 192 | return linear_to_morton_fns[static_cast<std::size_t>(format)]; | ||
| 193 | } | ||
| 194 | UNREACHABLE(); | ||
| 195 | } | ||
| 196 | |||
| 197 | /// 8x8 Z-Order coordinate from 2D coordinates | ||
| 198 | static u32 MortonInterleave(u32 x, u32 y) { | ||
| 199 | static const u32 xlut[] = {0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15}; | ||
| 200 | static const u32 ylut[] = {0x00, 0x02, 0x08, 0x0a, 0x20, 0x22, 0x28, 0x2a}; | ||
| 201 | return xlut[x % 8] + ylut[y % 8]; | ||
| 202 | } | ||
| 203 | |||
| 204 | /// Calculates the offset of the position of the pixel in Morton order | ||
| 205 | static u32 GetMortonOffset(u32 x, u32 y, u32 bytes_per_pixel) { | ||
| 206 | // Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each | ||
| 207 | // of which is composed of four 2x2 subtiles each of which is composed of four texels. | ||
| 208 | // Each structure is embedded into the next-bigger one in a diagonal pattern, e.g. | ||
| 209 | // texels are laid out in a 2x2 subtile like this: | ||
| 210 | // 2 3 | ||
| 211 | // 0 1 | ||
| 212 | // | ||
| 213 | // The full 8x8 tile has the texels arranged like this: | ||
| 214 | // | ||
| 215 | // 42 43 46 47 58 59 62 63 | ||
| 216 | // 40 41 44 45 56 57 60 61 | ||
| 217 | // 34 35 38 39 50 51 54 55 | ||
| 218 | // 32 33 36 37 48 49 52 53 | ||
| 219 | // 10 11 14 15 26 27 30 31 | ||
| 220 | // 08 09 12 13 24 25 28 29 | ||
| 221 | // 02 03 06 07 18 19 22 23 | ||
| 222 | // 00 01 04 05 16 17 20 21 | ||
| 223 | // | ||
| 224 | // This pattern is what's called Z-order curve, or Morton order. | ||
| 225 | |||
| 226 | const unsigned int block_height = 8; | ||
| 227 | const unsigned int coarse_x = x & ~7; | ||
| 228 | |||
| 229 | u32 i = MortonInterleave(x, y); | ||
| 230 | |||
| 231 | const unsigned int offset = coarse_x * block_height; | ||
| 232 | |||
| 233 | return (i + offset) * bytes_per_pixel; | ||
| 234 | } | ||
| 235 | |||
| 236 | static u32 MortonInterleave128(u32 x, u32 y) { | ||
| 237 | // 128x128 Z-Order coordinate from 2D coordinates | ||
| 238 | static constexpr u32 xlut[] = { | ||
| 239 | 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, | ||
| 240 | 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, | ||
| 241 | 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, | ||
| 242 | 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, | ||
| 243 | 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, | ||
| 244 | 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, | ||
| 245 | 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, | ||
| 246 | 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, | ||
| 247 | 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, | ||
| 248 | 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, | ||
| 249 | 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, | ||
| 250 | 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, | ||
| 251 | 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, | ||
| 252 | 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, | ||
| 253 | 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, | ||
| 254 | 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, | ||
| 255 | 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, | ||
| 256 | 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, | ||
| 257 | 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, | ||
| 258 | 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, | ||
| 259 | 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, | ||
| 260 | 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, | ||
| 261 | 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, | ||
| 262 | 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, | ||
| 263 | 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, | ||
| 264 | 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, | ||
| 265 | 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, | ||
| 266 | 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, | ||
| 267 | 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, | ||
| 268 | 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, | ||
| 269 | 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, | ||
| 270 | 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, | ||
| 271 | 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, | ||
| 272 | 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, | ||
| 273 | 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, | ||
| 274 | }; | ||
| 275 | static constexpr u32 ylut[] = { | ||
| 276 | 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, | ||
| 277 | 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, | ||
| 278 | 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, | ||
| 279 | 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, | ||
| 280 | 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, | ||
| 281 | 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, | ||
| 282 | 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, | ||
| 283 | 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, | ||
| 284 | 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, | ||
| 285 | 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, | ||
| 286 | 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, | ||
| 287 | 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, | ||
| 288 | 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, | ||
| 289 | 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, | ||
| 290 | 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, | ||
| 291 | 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, | ||
| 292 | 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, | ||
| 293 | 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, | ||
| 294 | 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, | ||
| 295 | 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, | ||
| 296 | 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, | ||
| 297 | 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, | ||
| 298 | 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, | ||
| 299 | 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, | ||
| 300 | 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, | ||
| 301 | 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, | ||
| 302 | 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, | ||
| 303 | 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, | ||
| 304 | 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, | ||
| 305 | 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, | ||
| 306 | 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, | ||
| 307 | 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, | ||
| 308 | 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, | ||
| 309 | 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, | ||
| 310 | 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, | ||
| 311 | }; | ||
| 312 | return xlut[x % 128] + ylut[y % 128]; | ||
| 313 | } | ||
| 314 | |||
| 315 | static u32 GetMortonOffset128(u32 x, u32 y, u32 bytes_per_pixel) { | ||
| 316 | // Calculates the offset of the position of the pixel in Morton order | ||
| 317 | // Framebuffer images are split into 128x128 tiles. | ||
| 318 | |||
| 319 | constexpr u32 block_height = 128; | ||
| 320 | const u32 coarse_x = x & ~127; | ||
| 321 | |||
| 322 | const u32 i = MortonInterleave128(x, y); | ||
| 323 | |||
| 324 | const u32 offset = coarse_x * block_height; | ||
| 325 | |||
| 326 | return (i + offset) * bytes_per_pixel; | ||
| 327 | } | ||
| 328 | |||
| 329 | void MortonSwizzle(MortonSwizzleMode mode, Surface::PixelFormat format, u32 stride, | ||
| 330 | u32 block_height, u32 height, u32 block_depth, u32 depth, u32 tile_width_spacing, | ||
| 331 | u8* buffer, std::size_t buffer_size, VAddr addr) { | ||
| 332 | |||
| 333 | GetSwizzleFunction(mode, format)(stride, block_height, height, block_depth, depth, | ||
| 334 | tile_width_spacing, buffer, buffer_size, addr); | ||
| 335 | } | ||
| 336 | |||
| 337 | void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel, u32 linear_bytes_per_pixel, | ||
| 338 | u8* morton_data, u8* linear_data, bool morton_to_linear) { | ||
| 339 | u8* data_ptrs[2]; | ||
| 340 | for (u32 y = 0; y < height; ++y) { | ||
| 341 | for (u32 x = 0; x < width; ++x) { | ||
| 342 | const u32 coarse_y = y & ~127; | ||
| 343 | const u32 morton_offset = | ||
| 344 | GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel; | ||
| 345 | const u32 linear_pixel_index = (x + y * width) * linear_bytes_per_pixel; | ||
| 346 | |||
| 347 | data_ptrs[morton_to_linear ? 1 : 0] = morton_data + morton_offset; | ||
| 348 | data_ptrs[morton_to_linear ? 0 : 1] = &linear_data[linear_pixel_index]; | ||
| 349 | |||
| 350 | std::memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel); | ||
| 351 | } | ||
| 352 | } | ||
| 353 | } | ||
| 354 | |||
| 355 | } // namespace VideoCore | ||
diff --git a/src/video_core/morton.h b/src/video_core/morton.h new file mode 100644 index 000000000..065f59ce3 --- /dev/null +++ b/src/video_core/morton.h | |||
| @@ -0,0 +1,21 @@ | |||
| 1 | // Copyright 2018 yuzu 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 "common/common_types.h" | ||
| 8 | #include "video_core/surface.h" | ||
| 9 | |||
| 10 | namespace VideoCore { | ||
| 11 | |||
| 12 | enum class MortonSwizzleMode { MortonToLinear, LinearToMorton }; | ||
| 13 | |||
| 14 | void MortonSwizzle(MortonSwizzleMode mode, VideoCore::Surface::PixelFormat format, u32 stride, | ||
| 15 | u32 block_height, u32 height, u32 block_depth, u32 depth, u32 tile_width_spacing, | ||
| 16 | u8* buffer, std::size_t buffer_size, VAddr addr); | ||
| 17 | |||
| 18 | void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel, u32 linear_bytes_per_pixel, | ||
| 19 | u8* morton_data, u8* linear_data, bool morton_to_linear); | ||
| 20 | |||
| 21 | } // namespace VideoCore | ||
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.cpp b/src/video_core/renderer_opengl/gl_buffer_cache.cpp index 075192c3f..46a6c0308 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_buffer_cache.cpp | |||
| @@ -76,7 +76,7 @@ std::tuple<u8*, GLintptr> OGLBufferCache::ReserveMemory(std::size_t size, std::s | |||
| 76 | return std::make_tuple(uploaded_ptr, uploaded_offset); | 76 | return std::make_tuple(uploaded_ptr, uploaded_offset); |
| 77 | } | 77 | } |
| 78 | 78 | ||
| 79 | void OGLBufferCache::Map(std::size_t max_size) { | 79 | bool OGLBufferCache::Map(std::size_t max_size) { |
| 80 | bool invalidate; | 80 | bool invalidate; |
| 81 | std::tie(buffer_ptr, buffer_offset_base, invalidate) = | 81 | std::tie(buffer_ptr, buffer_offset_base, invalidate) = |
| 82 | stream_buffer.Map(static_cast<GLsizeiptr>(max_size), 4); | 82 | stream_buffer.Map(static_cast<GLsizeiptr>(max_size), 4); |
| @@ -85,6 +85,7 @@ void OGLBufferCache::Map(std::size_t max_size) { | |||
| 85 | if (invalidate) { | 85 | if (invalidate) { |
| 86 | InvalidateAll(); | 86 | InvalidateAll(); |
| 87 | } | 87 | } |
| 88 | return invalidate; | ||
| 88 | } | 89 | } |
| 89 | 90 | ||
| 90 | void OGLBufferCache::Unmap() { | 91 | void OGLBufferCache::Unmap() { |
diff --git a/src/video_core/renderer_opengl/gl_buffer_cache.h b/src/video_core/renderer_opengl/gl_buffer_cache.h index 91fca3f6c..c11acfb79 100644 --- a/src/video_core/renderer_opengl/gl_buffer_cache.h +++ b/src/video_core/renderer_opengl/gl_buffer_cache.h | |||
| @@ -50,7 +50,7 @@ public: | |||
| 50 | /// Reserves memory to be used by host's CPU. Returns mapped address and offset. | 50 | /// Reserves memory to be used by host's CPU. Returns mapped address and offset. |
| 51 | std::tuple<u8*, GLintptr> ReserveMemory(std::size_t size, std::size_t alignment = 4); | 51 | std::tuple<u8*, GLintptr> ReserveMemory(std::size_t size, std::size_t alignment = 4); |
| 52 | 52 | ||
| 53 | void Map(std::size_t max_size); | 53 | bool Map(std::size_t max_size); |
| 54 | void Unmap(); | 54 | void Unmap(); |
| 55 | 55 | ||
| 56 | GLuint GetHandle() const; | 56 | GLuint GetHandle() const; |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp index ae6aaee4c..a44bbfae8 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp | |||
| @@ -98,14 +98,9 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo | |||
| 98 | has_ARB_direct_state_access = true; | 98 | has_ARB_direct_state_access = true; |
| 99 | } else if (extension == "GL_ARB_multi_bind") { | 99 | } else if (extension == "GL_ARB_multi_bind") { |
| 100 | has_ARB_multi_bind = true; | 100 | has_ARB_multi_bind = true; |
| 101 | } else if (extension == "GL_ARB_separate_shader_objects") { | ||
| 102 | has_ARB_separate_shader_objects = true; | ||
| 103 | } else if (extension == "GL_ARB_vertex_attrib_binding") { | ||
| 104 | has_ARB_vertex_attrib_binding = true; | ||
| 105 | } | 101 | } |
| 106 | } | 102 | } |
| 107 | 103 | ||
| 108 | ASSERT_MSG(has_ARB_separate_shader_objects, "has_ARB_separate_shader_objects is unsupported"); | ||
| 109 | OpenGLState::ApplyDefaultState(); | 104 | OpenGLState::ApplyDefaultState(); |
| 110 | 105 | ||
| 111 | // Create render framebuffer | 106 | // Create render framebuffer |
| @@ -118,10 +113,24 @@ RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& window, ScreenInfo | |||
| 118 | glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); | 113 | glGetIntegerv(GL_UNIFORM_BUFFER_OFFSET_ALIGNMENT, &uniform_buffer_alignment); |
| 119 | 114 | ||
| 120 | LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); | 115 | LOG_CRITICAL(Render_OpenGL, "Sync fixed function OpenGL state here!"); |
| 116 | CheckExtensions(); | ||
| 121 | } | 117 | } |
| 122 | 118 | ||
| 123 | RasterizerOpenGL::~RasterizerOpenGL() {} | 119 | RasterizerOpenGL::~RasterizerOpenGL() {} |
| 124 | 120 | ||
| 121 | void RasterizerOpenGL::CheckExtensions() { | ||
| 122 | if (!GLAD_GL_ARB_texture_filter_anisotropic && !GLAD_GL_EXT_texture_filter_anisotropic) { | ||
| 123 | LOG_WARNING( | ||
| 124 | Render_OpenGL, | ||
| 125 | "Anisotropic filter is not supported! This can cause graphical issues in some games."); | ||
| 126 | } | ||
| 127 | if (!GLAD_GL_ARB_buffer_storage) { | ||
| 128 | LOG_WARNING( | ||
| 129 | Render_OpenGL, | ||
| 130 | "Buffer storage control is not supported! This can cause performance degradation."); | ||
| 131 | } | ||
| 132 | } | ||
| 133 | |||
| 125 | void RasterizerOpenGL::SetupVertexFormat() { | 134 | void RasterizerOpenGL::SetupVertexFormat() { |
| 126 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | 135 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); |
| 127 | const auto& regs = gpu.regs; | 136 | const auto& regs = gpu.regs; |
| @@ -181,15 +190,25 @@ void RasterizerOpenGL::SetupVertexFormat() { | |||
| 181 | } | 190 | } |
| 182 | state.draw.vertex_array = VAO.handle; | 191 | state.draw.vertex_array = VAO.handle; |
| 183 | state.ApplyVertexBufferState(); | 192 | state.ApplyVertexBufferState(); |
| 193 | |||
| 194 | // Rebinding the VAO invalidates the vertex buffer bindings. | ||
| 195 | gpu.dirty_flags.vertex_array = 0xFFFFFFFF; | ||
| 184 | } | 196 | } |
| 185 | 197 | ||
| 186 | void RasterizerOpenGL::SetupVertexBuffer() { | 198 | void RasterizerOpenGL::SetupVertexBuffer() { |
| 187 | MICROPROFILE_SCOPE(OpenGL_VB); | 199 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); |
| 188 | const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | ||
| 189 | const auto& regs = gpu.regs; | 200 | const auto& regs = gpu.regs; |
| 190 | 201 | ||
| 202 | if (!gpu.dirty_flags.vertex_array) | ||
| 203 | return; | ||
| 204 | |||
| 205 | MICROPROFILE_SCOPE(OpenGL_VB); | ||
| 206 | |||
| 191 | // Upload all guest vertex arrays sequentially to our buffer | 207 | // Upload all guest vertex arrays sequentially to our buffer |
| 192 | for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { | 208 | for (u32 index = 0; index < Maxwell::NumVertexArrays; ++index) { |
| 209 | if (~gpu.dirty_flags.vertex_array & (1u << index)) | ||
| 210 | continue; | ||
| 211 | |||
| 193 | const auto& vertex_array = regs.vertex_array[index]; | 212 | const auto& vertex_array = regs.vertex_array[index]; |
| 194 | if (!vertex_array.IsEnabled()) | 213 | if (!vertex_array.IsEnabled()) |
| 195 | continue; | 214 | continue; |
| @@ -216,6 +235,8 @@ void RasterizerOpenGL::SetupVertexBuffer() { | |||
| 216 | 235 | ||
| 217 | // Implicit set by glBindVertexBuffer. Stupid glstate handling... | 236 | // Implicit set by glBindVertexBuffer. Stupid glstate handling... |
| 218 | state.draw.vertex_buffer = buffer_cache.GetHandle(); | 237 | state.draw.vertex_buffer = buffer_cache.GetHandle(); |
| 238 | |||
| 239 | gpu.dirty_flags.vertex_array = 0; | ||
| 219 | } | 240 | } |
| 220 | 241 | ||
| 221 | DrawParameters RasterizerOpenGL::SetupDraw() { | 242 | DrawParameters RasterizerOpenGL::SetupDraw() { |
| @@ -542,6 +563,30 @@ void RasterizerOpenGL::Clear() { | |||
| 542 | ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); | 563 | ASSERT_MSG(regs.zeta_enable != 0, "Tried to clear stencil but buffer is not enabled!"); |
| 543 | use_stencil = true; | 564 | use_stencil = true; |
| 544 | clear_state.stencil.test_enabled = true; | 565 | clear_state.stencil.test_enabled = true; |
| 566 | if (regs.clear_flags.stencil) { | ||
| 567 | // Stencil affects the clear so fill it with the used masks | ||
| 568 | clear_state.stencil.front.test_func = GL_ALWAYS; | ||
| 569 | clear_state.stencil.front.test_mask = regs.stencil_front_func_mask; | ||
| 570 | clear_state.stencil.front.action_stencil_fail = GL_KEEP; | ||
| 571 | clear_state.stencil.front.action_depth_fail = GL_KEEP; | ||
| 572 | clear_state.stencil.front.action_depth_pass = GL_KEEP; | ||
| 573 | clear_state.stencil.front.write_mask = regs.stencil_front_mask; | ||
| 574 | if (regs.stencil_two_side_enable) { | ||
| 575 | clear_state.stencil.back.test_func = GL_ALWAYS; | ||
| 576 | clear_state.stencil.back.test_mask = regs.stencil_back_func_mask; | ||
| 577 | clear_state.stencil.back.action_stencil_fail = GL_KEEP; | ||
| 578 | clear_state.stencil.back.action_depth_fail = GL_KEEP; | ||
| 579 | clear_state.stencil.back.action_depth_pass = GL_KEEP; | ||
| 580 | clear_state.stencil.back.write_mask = regs.stencil_back_mask; | ||
| 581 | } else { | ||
| 582 | clear_state.stencil.back.test_func = GL_ALWAYS; | ||
| 583 | clear_state.stencil.back.test_mask = 0xFFFFFFFF; | ||
| 584 | clear_state.stencil.back.write_mask = 0xFFFFFFFF; | ||
| 585 | clear_state.stencil.back.action_stencil_fail = GL_KEEP; | ||
| 586 | clear_state.stencil.back.action_depth_fail = GL_KEEP; | ||
| 587 | clear_state.stencil.back.action_depth_pass = GL_KEEP; | ||
| 588 | } | ||
| 589 | } | ||
| 545 | } | 590 | } |
| 546 | 591 | ||
| 547 | if (!use_color && !use_depth && !use_stencil) { | 592 | if (!use_color && !use_depth && !use_stencil) { |
| @@ -553,6 +598,14 @@ void RasterizerOpenGL::Clear() { | |||
| 553 | 598 | ||
| 554 | ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false, | 599 | ConfigureFramebuffers(clear_state, use_color, use_depth || use_stencil, false, |
| 555 | regs.clear_buffers.RT.Value()); | 600 | regs.clear_buffers.RT.Value()); |
| 601 | if (regs.clear_flags.scissor) { | ||
| 602 | SyncScissorTest(clear_state); | ||
| 603 | } | ||
| 604 | |||
| 605 | if (regs.clear_flags.viewport) { | ||
| 606 | clear_state.EmulateViewportWithScissor(); | ||
| 607 | } | ||
| 608 | |||
| 556 | clear_state.Apply(); | 609 | clear_state.Apply(); |
| 557 | 610 | ||
| 558 | if (use_color) { | 611 | if (use_color) { |
| @@ -573,7 +626,7 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 573 | return; | 626 | return; |
| 574 | 627 | ||
| 575 | MICROPROFILE_SCOPE(OpenGL_Drawing); | 628 | MICROPROFILE_SCOPE(OpenGL_Drawing); |
| 576 | const auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); | 629 | auto& gpu = Core::System::GetInstance().GPU().Maxwell3D(); |
| 577 | const auto& regs = gpu.regs; | 630 | const auto& regs = gpu.regs; |
| 578 | 631 | ||
| 579 | ScopeAcquireGLContext acquire_context{emu_window}; | 632 | ScopeAcquireGLContext acquire_context{emu_window}; |
| @@ -588,12 +641,13 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 588 | SyncLogicOpState(); | 641 | SyncLogicOpState(); |
| 589 | SyncCullMode(); | 642 | SyncCullMode(); |
| 590 | SyncPrimitiveRestart(); | 643 | SyncPrimitiveRestart(); |
| 591 | SyncScissorTest(); | 644 | SyncScissorTest(state); |
| 645 | SyncClipEnabled(); | ||
| 592 | // Alpha Testing is synced on shaders. | 646 | // Alpha Testing is synced on shaders. |
| 593 | SyncTransformFeedback(); | 647 | SyncTransformFeedback(); |
| 594 | SyncPointState(); | 648 | SyncPointState(); |
| 595 | CheckAlphaTests(); | 649 | CheckAlphaTests(); |
| 596 | 650 | SyncPolygonOffset(); | |
| 597 | // TODO(bunnei): Sync framebuffer_scale uniform here | 651 | // TODO(bunnei): Sync framebuffer_scale uniform here |
| 598 | // TODO(bunnei): Sync scissorbox uniform(s) here | 652 | // TODO(bunnei): Sync scissorbox uniform(s) here |
| 599 | 653 | ||
| @@ -626,7 +680,11 @@ void RasterizerOpenGL::DrawArrays() { | |||
| 626 | // Add space for at least 18 constant buffers | 680 | // Add space for at least 18 constant buffers |
| 627 | buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment); | 681 | buffer_size += Maxwell::MaxConstBuffers * (MaxConstbufferSize + uniform_buffer_alignment); |
| 628 | 682 | ||
| 629 | buffer_cache.Map(buffer_size); | 683 | bool invalidate = buffer_cache.Map(buffer_size); |
| 684 | if (invalidate) { | ||
| 685 | // As all cached buffers are invalidated, we need to recheck their state. | ||
| 686 | gpu.dirty_flags.vertex_array = 0xFFFFFFFF; | ||
| 687 | } | ||
| 630 | 688 | ||
| 631 | SetupVertexFormat(); | 689 | SetupVertexFormat(); |
| 632 | SetupVertexBuffer(); | 690 | SetupVertexBuffer(); |
| @@ -815,7 +873,7 @@ void RasterizerOpenGL::SamplerInfo::SyncWithConfig(const Tegra::Texture::TSCEntr | |||
| 815 | } | 873 | } |
| 816 | const u32 bias = config.mip_lod_bias.Value(); | 874 | const u32 bias = config.mip_lod_bias.Value(); |
| 817 | // Sign extend the 13-bit value. | 875 | // Sign extend the 13-bit value. |
| 818 | const u32 mask = 1U << (13 - 1); | 876 | constexpr u32 mask = 1U << (13 - 1); |
| 819 | const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f; | 877 | const float bias_lod = static_cast<s32>((bias ^ mask) - mask) / 256.f; |
| 820 | if (lod_bias != bias_lod) { | 878 | if (lod_bias != bias_lod) { |
| 821 | lod_bias = bias_lod; | 879 | lod_bias = bias_lod; |
| @@ -942,20 +1000,35 @@ u32 RasterizerOpenGL::SetupTextures(Maxwell::ShaderStage stage, Shader& shader, | |||
| 942 | 1000 | ||
| 943 | void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { | 1001 | void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { |
| 944 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1002 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 945 | for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { | 1003 | const bool geometry_shaders_enabled = |
| 946 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; | 1004 | regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry)); |
| 1005 | const std::size_t viewport_count = | ||
| 1006 | geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1; | ||
| 1007 | for (std::size_t i = 0; i < viewport_count; i++) { | ||
| 947 | auto& viewport = current_state.viewports[i]; | 1008 | auto& viewport = current_state.viewports[i]; |
| 1009 | const auto& src = regs.viewports[i]; | ||
| 1010 | const MathUtil::Rectangle<s32> viewport_rect{regs.viewport_transform[i].GetRect()}; | ||
| 948 | viewport.x = viewport_rect.left; | 1011 | viewport.x = viewport_rect.left; |
| 949 | viewport.y = viewport_rect.bottom; | 1012 | viewport.y = viewport_rect.bottom; |
| 950 | viewport.width = static_cast<GLfloat>(viewport_rect.GetWidth()); | 1013 | viewport.width = viewport_rect.GetWidth(); |
| 951 | viewport.height = static_cast<GLfloat>(viewport_rect.GetHeight()); | 1014 | viewport.height = viewport_rect.GetHeight(); |
| 952 | viewport.depth_range_far = regs.viewports[i].depth_range_far; | 1015 | viewport.depth_range_far = regs.viewports[i].depth_range_far; |
| 953 | viewport.depth_range_near = regs.viewports[i].depth_range_near; | 1016 | viewport.depth_range_near = regs.viewports[i].depth_range_near; |
| 954 | } | 1017 | } |
| 1018 | state.depth_clamp.far_plane = regs.view_volume_clip_control.depth_clamp_far != 0; | ||
| 1019 | state.depth_clamp.near_plane = regs.view_volume_clip_control.depth_clamp_near != 0; | ||
| 955 | } | 1020 | } |
| 956 | 1021 | ||
| 957 | void RasterizerOpenGL::SyncClipEnabled() { | 1022 | void RasterizerOpenGL::SyncClipEnabled() { |
| 958 | UNREACHABLE(); | 1023 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 1024 | state.clip_distance[0] = regs.clip_distance_enabled.c0 != 0; | ||
| 1025 | state.clip_distance[1] = regs.clip_distance_enabled.c1 != 0; | ||
| 1026 | state.clip_distance[2] = regs.clip_distance_enabled.c2 != 0; | ||
| 1027 | state.clip_distance[3] = regs.clip_distance_enabled.c3 != 0; | ||
| 1028 | state.clip_distance[4] = regs.clip_distance_enabled.c4 != 0; | ||
| 1029 | state.clip_distance[5] = regs.clip_distance_enabled.c5 != 0; | ||
| 1030 | state.clip_distance[6] = regs.clip_distance_enabled.c6 != 0; | ||
| 1031 | state.clip_distance[7] = regs.clip_distance_enabled.c7 != 0; | ||
| 959 | } | 1032 | } |
| 960 | 1033 | ||
| 961 | void RasterizerOpenGL::SyncClipCoef() { | 1034 | void RasterizerOpenGL::SyncClipCoef() { |
| @@ -1120,11 +1193,15 @@ void RasterizerOpenGL::SyncLogicOpState() { | |||
| 1120 | state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); | 1193 | state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); |
| 1121 | } | 1194 | } |
| 1122 | 1195 | ||
| 1123 | void RasterizerOpenGL::SyncScissorTest() { | 1196 | void RasterizerOpenGL::SyncScissorTest(OpenGLState& current_state) { |
| 1124 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1197 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 1125 | for (std::size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumViewports; i++) { | 1198 | const bool geometry_shaders_enabled = |
| 1199 | regs.IsShaderConfigEnabled(static_cast<size_t>(Maxwell::ShaderProgram::Geometry)); | ||
| 1200 | const std::size_t viewport_count = | ||
| 1201 | geometry_shaders_enabled ? Tegra::Engines::Maxwell3D::Regs::NumViewports : 1; | ||
| 1202 | for (std::size_t i = 0; i < viewport_count; i++) { | ||
| 1126 | const auto& src = regs.scissor_test[i]; | 1203 | const auto& src = regs.scissor_test[i]; |
| 1127 | auto& dst = state.viewports[i].scissor; | 1204 | auto& dst = current_state.viewports[i].scissor; |
| 1128 | dst.enabled = (src.enable != 0); | 1205 | dst.enabled = (src.enable != 0); |
| 1129 | if (dst.enabled == 0) { | 1206 | if (dst.enabled == 0) { |
| 1130 | return; | 1207 | return; |
| @@ -1152,6 +1229,16 @@ void RasterizerOpenGL::SyncPointState() { | |||
| 1152 | state.point.size = regs.point_size; | 1229 | state.point.size = regs.point_size; |
| 1153 | } | 1230 | } |
| 1154 | 1231 | ||
| 1232 | void RasterizerOpenGL::SyncPolygonOffset() { | ||
| 1233 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | ||
| 1234 | state.polygon_offset.fill_enable = regs.polygon_offset_fill_enable != 0; | ||
| 1235 | state.polygon_offset.line_enable = regs.polygon_offset_line_enable != 0; | ||
| 1236 | state.polygon_offset.point_enable = regs.polygon_offset_point_enable != 0; | ||
| 1237 | state.polygon_offset.units = regs.polygon_offset_units; | ||
| 1238 | state.polygon_offset.factor = regs.polygon_offset_factor; | ||
| 1239 | state.polygon_offset.clamp = regs.polygon_offset_clamp; | ||
| 1240 | } | ||
| 1241 | |||
| 1155 | void RasterizerOpenGL::CheckAlphaTests() { | 1242 | void RasterizerOpenGL::CheckAlphaTests() { |
| 1156 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; | 1243 | const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; |
| 1157 | 1244 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h index 6e78ab4cd..7ec9746b1 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer.h +++ b/src/video_core/renderer_opengl/gl_rasterizer.h | |||
| @@ -91,19 +91,20 @@ private: | |||
| 91 | void SyncWithConfig(const Tegra::Texture::TSCEntry& info); | 91 | void SyncWithConfig(const Tegra::Texture::TSCEntry& info); |
| 92 | 92 | ||
| 93 | private: | 93 | private: |
| 94 | Tegra::Texture::TextureFilter mag_filter; | 94 | Tegra::Texture::TextureFilter mag_filter = Tegra::Texture::TextureFilter::Nearest; |
| 95 | Tegra::Texture::TextureFilter min_filter; | 95 | Tegra::Texture::TextureFilter min_filter = Tegra::Texture::TextureFilter::Nearest; |
| 96 | Tegra::Texture::TextureMipmapFilter mip_filter; | 96 | Tegra::Texture::TextureMipmapFilter mip_filter = Tegra::Texture::TextureMipmapFilter::None; |
| 97 | Tegra::Texture::WrapMode wrap_u; | 97 | Tegra::Texture::WrapMode wrap_u = Tegra::Texture::WrapMode::ClampToEdge; |
| 98 | Tegra::Texture::WrapMode wrap_v; | 98 | Tegra::Texture::WrapMode wrap_v = Tegra::Texture::WrapMode::ClampToEdge; |
| 99 | Tegra::Texture::WrapMode wrap_p; | 99 | Tegra::Texture::WrapMode wrap_p = Tegra::Texture::WrapMode::ClampToEdge; |
| 100 | bool uses_depth_compare; | 100 | bool uses_depth_compare = false; |
| 101 | Tegra::Texture::DepthCompareFunc depth_compare_func; | 101 | Tegra::Texture::DepthCompareFunc depth_compare_func = |
| 102 | GLvec4 border_color; | 102 | Tegra::Texture::DepthCompareFunc::Always; |
| 103 | float min_lod; | 103 | GLvec4 border_color = {}; |
| 104 | float max_lod; | 104 | float min_lod = 0.0f; |
| 105 | float lod_bias; | 105 | float max_lod = 16.0f; |
| 106 | float max_anisotropic; | 106 | float lod_bias = 0.0f; |
| 107 | float max_anisotropic = 1.0f; | ||
| 107 | }; | 108 | }; |
| 108 | 109 | ||
| 109 | /** | 110 | /** |
| @@ -171,7 +172,7 @@ private: | |||
| 171 | void SyncMultiSampleState(); | 172 | void SyncMultiSampleState(); |
| 172 | 173 | ||
| 173 | /// Syncs the scissor test state to match the guest state | 174 | /// Syncs the scissor test state to match the guest state |
| 174 | void SyncScissorTest(); | 175 | void SyncScissorTest(OpenGLState& current_state); |
| 175 | 176 | ||
| 176 | /// Syncs the transform feedback state to match the guest state | 177 | /// Syncs the transform feedback state to match the guest state |
| 177 | void SyncTransformFeedback(); | 178 | void SyncTransformFeedback(); |
| @@ -182,13 +183,18 @@ private: | |||
| 182 | /// Syncs Color Mask | 183 | /// Syncs Color Mask |
| 183 | void SyncColorMask(); | 184 | void SyncColorMask(); |
| 184 | 185 | ||
| 186 | /// Syncs the polygon offsets | ||
| 187 | void SyncPolygonOffset(); | ||
| 188 | |||
| 185 | /// Check asserts for alpha testing. | 189 | /// Check asserts for alpha testing. |
| 186 | void CheckAlphaTests(); | 190 | void CheckAlphaTests(); |
| 187 | 191 | ||
| 192 | /// Check for extension that are not strictly required | ||
| 193 | /// but are needed for correct emulation | ||
| 194 | void CheckExtensions(); | ||
| 195 | |||
| 188 | bool has_ARB_direct_state_access = false; | 196 | bool has_ARB_direct_state_access = false; |
| 189 | bool has_ARB_multi_bind = false; | 197 | bool has_ARB_multi_bind = false; |
| 190 | bool has_ARB_separate_shader_objects = false; | ||
| 191 | bool has_ARB_vertex_attrib_binding = false; | ||
| 192 | 198 | ||
| 193 | OpenGLState state; | 199 | OpenGLState state; |
| 194 | 200 | ||
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp index 9ca82c06c..dde2f468d 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.cpp | |||
| @@ -15,6 +15,7 @@ | |||
| 15 | #include "core/memory.h" | 15 | #include "core/memory.h" |
| 16 | #include "core/settings.h" | 16 | #include "core/settings.h" |
| 17 | #include "video_core/engines/maxwell_3d.h" | 17 | #include "video_core/engines/maxwell_3d.h" |
| 18 | #include "video_core/morton.h" | ||
| 18 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 19 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 19 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" | 20 | #include "video_core/renderer_opengl/gl_rasterizer_cache.h" |
| 20 | #include "video_core/renderer_opengl/gl_state.h" | 21 | #include "video_core/renderer_opengl/gl_state.h" |
| @@ -22,10 +23,11 @@ | |||
| 22 | #include "video_core/surface.h" | 23 | #include "video_core/surface.h" |
| 23 | #include "video_core/textures/astc.h" | 24 | #include "video_core/textures/astc.h" |
| 24 | #include "video_core/textures/decoders.h" | 25 | #include "video_core/textures/decoders.h" |
| 25 | #include "video_core/utils.h" | ||
| 26 | 26 | ||
| 27 | namespace OpenGL { | 27 | namespace OpenGL { |
| 28 | 28 | ||
| 29 | using VideoCore::MortonSwizzle; | ||
| 30 | using VideoCore::MortonSwizzleMode; | ||
| 29 | using VideoCore::Surface::ComponentTypeFromDepthFormat; | 31 | using VideoCore::Surface::ComponentTypeFromDepthFormat; |
| 30 | using VideoCore::Surface::ComponentTypeFromRenderTarget; | 32 | using VideoCore::Surface::ComponentTypeFromRenderTarget; |
| 31 | using VideoCore::Surface::ComponentTypeFromTexture; | 33 | using VideoCore::Surface::ComponentTypeFromTexture; |
| @@ -95,6 +97,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only, | |||
| 95 | params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0, | 97 | params.block_width = params.is_tiled ? config.tic.BlockWidth() : 0, |
| 96 | params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, | 98 | params.block_height = params.is_tiled ? config.tic.BlockHeight() : 0, |
| 97 | params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0, | 99 | params.block_depth = params.is_tiled ? config.tic.BlockDepth() : 0, |
| 100 | params.tile_width_spacing = params.is_tiled ? (1 << config.tic.tile_width_spacing.Value()) : 1; | ||
| 98 | params.srgb_conversion = config.tic.IsSrgbConversionEnabled(); | 101 | params.srgb_conversion = config.tic.IsSrgbConversionEnabled(); |
| 99 | params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(), | 102 | params.pixel_format = PixelFormatFromTextureFormat(config.tic.format, config.tic.r_type.Value(), |
| 100 | params.srgb_conversion); | 103 | params.srgb_conversion); |
| @@ -160,6 +163,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only, | |||
| 160 | params.block_width = 1 << config.memory_layout.block_width; | 163 | params.block_width = 1 << config.memory_layout.block_width; |
| 161 | params.block_height = 1 << config.memory_layout.block_height; | 164 | params.block_height = 1 << config.memory_layout.block_height; |
| 162 | params.block_depth = 1 << config.memory_layout.block_depth; | 165 | params.block_depth = 1 << config.memory_layout.block_depth; |
| 166 | params.tile_width_spacing = 1; | ||
| 163 | params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); | 167 | params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); |
| 164 | params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || | 168 | params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || |
| 165 | config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; | 169 | config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; |
| @@ -195,6 +199,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only, | |||
| 195 | params.block_width = 1 << std::min(block_width, 5U); | 199 | params.block_width = 1 << std::min(block_width, 5U); |
| 196 | params.block_height = 1 << std::min(block_height, 5U); | 200 | params.block_height = 1 << std::min(block_height, 5U); |
| 197 | params.block_depth = 1 << std::min(block_depth, 5U); | 201 | params.block_depth = 1 << std::min(block_depth, 5U); |
| 202 | params.tile_width_spacing = 1; | ||
| 198 | params.pixel_format = PixelFormatFromDepthFormat(format); | 203 | params.pixel_format = PixelFormatFromDepthFormat(format); |
| 199 | params.component_type = ComponentTypeFromDepthFormat(format); | 204 | params.component_type = ComponentTypeFromDepthFormat(format); |
| 200 | params.type = GetFormatType(params.pixel_format); | 205 | params.type = GetFormatType(params.pixel_format); |
| @@ -221,6 +226,7 @@ std::size_t SurfaceParams::InnerMemorySize(bool force_gl, bool layer_only, | |||
| 221 | params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0, | 226 | params.block_width = params.is_tiled ? std::min(config.BlockWidth(), 32U) : 0, |
| 222 | params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0, | 227 | params.block_height = params.is_tiled ? std::min(config.BlockHeight(), 32U) : 0, |
| 223 | params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0, | 228 | params.block_depth = params.is_tiled ? std::min(config.BlockDepth(), 32U) : 0, |
| 229 | params.tile_width_spacing = 1; | ||
| 224 | params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); | 230 | params.pixel_format = PixelFormatFromRenderTargetFormat(config.format); |
| 225 | params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || | 231 | params.srgb_conversion = config.format == Tegra::RenderTargetFormat::BGRA8_SRGB || |
| 226 | config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; | 232 | config.format == Tegra::RenderTargetFormat::RGBA8_SRGB; |
| @@ -265,11 +271,11 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex | |||
| 265 | {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | 271 | {GL_COMPRESSED_RG_RGTC2, GL_RG, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, |
| 266 | true}, // DXN2UNORM | 272 | true}, // DXN2UNORM |
| 267 | {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM | 273 | {GL_COMPRESSED_SIGNED_RG_RGTC2, GL_RG, GL_INT, ComponentType::SNorm, true}, // DXN2SNORM |
| 268 | {GL_COMPRESSED_RGBA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | 274 | {GL_COMPRESSED_RGBA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, |
| 269 | true}, // BC7U | 275 | true}, // BC7U |
| 270 | {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, | 276 | {GL_COMPRESSED_RGB_BPTC_UNSIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float, |
| 271 | ComponentType::Float, true}, // BC6H_UF16 | 277 | true}, // BC6H_UF16 |
| 272 | {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT_ARB, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float, | 278 | {GL_COMPRESSED_RGB_BPTC_SIGNED_FLOAT, GL_RGB, GL_UNSIGNED_INT_8_8_8_8, ComponentType::Float, |
| 273 | true}, // BC6H_SF16 | 279 | true}, // BC6H_SF16 |
| 274 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4 | 280 | {GL_RGBA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4 |
| 275 | {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U | 281 | {GL_RG8, GL_RG, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // G8R8U |
| @@ -306,8 +312,8 @@ static constexpr std::array<FormatTuple, VideoCore::Surface::MaxPixelFormat> tex | |||
| 306 | true}, // DXT23_SRGB | 312 | true}, // DXT23_SRGB |
| 307 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, | 313 | {GL_COMPRESSED_SRGB_ALPHA_S3TC_DXT5_EXT, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, |
| 308 | true}, // DXT45_SRGB | 314 | true}, // DXT45_SRGB |
| 309 | {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM_ARB, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, | 315 | {GL_COMPRESSED_SRGB_ALPHA_BPTC_UNORM, GL_RGBA, GL_UNSIGNED_INT_8_8_8_8, ComponentType::UNorm, |
| 310 | ComponentType::UNorm, true}, // BC7U_SRGB | 316 | true}, // BC7U_SRGB |
| 311 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB | 317 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_4X4_SRGB |
| 312 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB | 318 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X8_SRGB |
| 313 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB | 319 | {GL_SRGB8_ALPHA8, GL_RGBA, GL_UNSIGNED_BYTE, ComponentType::UNorm, false}, // ASTC_2D_8X5_SRGB |
| @@ -346,7 +352,7 @@ static GLenum SurfaceTargetToGL(SurfaceTarget target) { | |||
| 346 | case SurfaceTarget::TextureCubemap: | 352 | case SurfaceTarget::TextureCubemap: |
| 347 | return GL_TEXTURE_CUBE_MAP; | 353 | return GL_TEXTURE_CUBE_MAP; |
| 348 | case SurfaceTarget::TextureCubeArray: | 354 | case SurfaceTarget::TextureCubeArray: |
| 349 | return GL_TEXTURE_CUBE_MAP_ARRAY_ARB; | 355 | return GL_TEXTURE_CUBE_MAP_ARRAY; |
| 350 | } | 356 | } |
| 351 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target)); | 357 | LOG_CRITICAL(Render_OpenGL, "Unimplemented texture target={}", static_cast<u32>(target)); |
| 352 | UNREACHABLE(); | 358 | UNREACHABLE(); |
| @@ -370,174 +376,7 @@ MathUtil::Rectangle<u32> SurfaceParams::GetRect(u32 mip_level) const { | |||
| 370 | return {0, actual_height, MipWidth(mip_level), 0}; | 376 | return {0, actual_height, MipWidth(mip_level), 0}; |
| 371 | } | 377 | } |
| 372 | 378 | ||
| 373 | template <bool morton_to_gl, PixelFormat format> | 379 | void SwizzleFunc(const MortonSwizzleMode& mode, const SurfaceParams& params, |
| 374 | void MortonCopy(u32 stride, u32 block_height, u32 height, u32 block_depth, u32 depth, u8* gl_buffer, | ||
| 375 | std::size_t gl_buffer_size, VAddr addr) { | ||
| 376 | constexpr u32 bytes_per_pixel = GetBytesPerPixel(format); | ||
| 377 | |||
| 378 | // With the BCn formats (DXT and DXN), each 4x4 tile is swizzled instead of just individual | ||
| 379 | // pixel values. | ||
| 380 | const u32 tile_size_x{GetDefaultBlockWidth(format)}; | ||
| 381 | const u32 tile_size_y{GetDefaultBlockHeight(format)}; | ||
| 382 | |||
| 383 | if (morton_to_gl) { | ||
| 384 | Tegra::Texture::UnswizzleTexture(gl_buffer, addr, tile_size_x, tile_size_y, bytes_per_pixel, | ||
| 385 | stride, height, depth, block_height, block_depth); | ||
| 386 | } else { | ||
| 387 | Tegra::Texture::CopySwizzledData((stride + tile_size_x - 1) / tile_size_x, | ||
| 388 | (height + tile_size_y - 1) / tile_size_y, depth, | ||
| 389 | bytes_per_pixel, bytes_per_pixel, Memory::GetPointer(addr), | ||
| 390 | gl_buffer, false, block_height, block_depth); | ||
| 391 | } | ||
| 392 | } | ||
| 393 | |||
| 394 | using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr), | ||
| 395 | VideoCore::Surface::MaxPixelFormat>; | ||
| 396 | |||
| 397 | static constexpr GLConversionArray morton_to_gl_fns = { | ||
| 398 | // clang-format off | ||
| 399 | MortonCopy<true, PixelFormat::ABGR8U>, | ||
| 400 | MortonCopy<true, PixelFormat::ABGR8S>, | ||
| 401 | MortonCopy<true, PixelFormat::ABGR8UI>, | ||
| 402 | MortonCopy<true, PixelFormat::B5G6R5U>, | ||
| 403 | MortonCopy<true, PixelFormat::A2B10G10R10U>, | ||
| 404 | MortonCopy<true, PixelFormat::A1B5G5R5U>, | ||
| 405 | MortonCopy<true, PixelFormat::R8U>, | ||
| 406 | MortonCopy<true, PixelFormat::R8UI>, | ||
| 407 | MortonCopy<true, PixelFormat::RGBA16F>, | ||
| 408 | MortonCopy<true, PixelFormat::RGBA16U>, | ||
| 409 | MortonCopy<true, PixelFormat::RGBA16UI>, | ||
| 410 | MortonCopy<true, PixelFormat::R11FG11FB10F>, | ||
| 411 | MortonCopy<true, PixelFormat::RGBA32UI>, | ||
| 412 | MortonCopy<true, PixelFormat::DXT1>, | ||
| 413 | MortonCopy<true, PixelFormat::DXT23>, | ||
| 414 | MortonCopy<true, PixelFormat::DXT45>, | ||
| 415 | MortonCopy<true, PixelFormat::DXN1>, | ||
| 416 | MortonCopy<true, PixelFormat::DXN2UNORM>, | ||
| 417 | MortonCopy<true, PixelFormat::DXN2SNORM>, | ||
| 418 | MortonCopy<true, PixelFormat::BC7U>, | ||
| 419 | MortonCopy<true, PixelFormat::BC6H_UF16>, | ||
| 420 | MortonCopy<true, PixelFormat::BC6H_SF16>, | ||
| 421 | MortonCopy<true, PixelFormat::ASTC_2D_4X4>, | ||
| 422 | MortonCopy<true, PixelFormat::G8R8U>, | ||
| 423 | MortonCopy<true, PixelFormat::G8R8S>, | ||
| 424 | MortonCopy<true, PixelFormat::BGRA8>, | ||
| 425 | MortonCopy<true, PixelFormat::RGBA32F>, | ||
| 426 | MortonCopy<true, PixelFormat::RG32F>, | ||
| 427 | MortonCopy<true, PixelFormat::R32F>, | ||
| 428 | MortonCopy<true, PixelFormat::R16F>, | ||
| 429 | MortonCopy<true, PixelFormat::R16U>, | ||
| 430 | MortonCopy<true, PixelFormat::R16S>, | ||
| 431 | MortonCopy<true, PixelFormat::R16UI>, | ||
| 432 | MortonCopy<true, PixelFormat::R16I>, | ||
| 433 | MortonCopy<true, PixelFormat::RG16>, | ||
| 434 | MortonCopy<true, PixelFormat::RG16F>, | ||
| 435 | MortonCopy<true, PixelFormat::RG16UI>, | ||
| 436 | MortonCopy<true, PixelFormat::RG16I>, | ||
| 437 | MortonCopy<true, PixelFormat::RG16S>, | ||
| 438 | MortonCopy<true, PixelFormat::RGB32F>, | ||
| 439 | MortonCopy<true, PixelFormat::RGBA8_SRGB>, | ||
| 440 | MortonCopy<true, PixelFormat::RG8U>, | ||
| 441 | MortonCopy<true, PixelFormat::RG8S>, | ||
| 442 | MortonCopy<true, PixelFormat::RG32UI>, | ||
| 443 | MortonCopy<true, PixelFormat::R32UI>, | ||
| 444 | MortonCopy<true, PixelFormat::ASTC_2D_8X8>, | ||
| 445 | MortonCopy<true, PixelFormat::ASTC_2D_8X5>, | ||
| 446 | MortonCopy<true, PixelFormat::ASTC_2D_5X4>, | ||
| 447 | MortonCopy<true, PixelFormat::BGRA8_SRGB>, | ||
| 448 | MortonCopy<true, PixelFormat::DXT1_SRGB>, | ||
| 449 | MortonCopy<true, PixelFormat::DXT23_SRGB>, | ||
| 450 | MortonCopy<true, PixelFormat::DXT45_SRGB>, | ||
| 451 | MortonCopy<true, PixelFormat::BC7U_SRGB>, | ||
| 452 | MortonCopy<true, PixelFormat::ASTC_2D_4X4_SRGB>, | ||
| 453 | MortonCopy<true, PixelFormat::ASTC_2D_8X8_SRGB>, | ||
| 454 | MortonCopy<true, PixelFormat::ASTC_2D_8X5_SRGB>, | ||
| 455 | MortonCopy<true, PixelFormat::ASTC_2D_5X4_SRGB>, | ||
| 456 | MortonCopy<true, PixelFormat::ASTC_2D_5X5>, | ||
| 457 | MortonCopy<true, PixelFormat::ASTC_2D_5X5_SRGB>, | ||
| 458 | MortonCopy<true, PixelFormat::ASTC_2D_10X8>, | ||
| 459 | MortonCopy<true, PixelFormat::ASTC_2D_10X8_SRGB>, | ||
| 460 | MortonCopy<true, PixelFormat::Z32F>, | ||
| 461 | MortonCopy<true, PixelFormat::Z16>, | ||
| 462 | MortonCopy<true, PixelFormat::Z24S8>, | ||
| 463 | MortonCopy<true, PixelFormat::S8Z24>, | ||
| 464 | MortonCopy<true, PixelFormat::Z32FS8>, | ||
| 465 | // clang-format on | ||
| 466 | }; | ||
| 467 | |||
| 468 | static constexpr GLConversionArray gl_to_morton_fns = { | ||
| 469 | // clang-format off | ||
| 470 | MortonCopy<false, PixelFormat::ABGR8U>, | ||
| 471 | MortonCopy<false, PixelFormat::ABGR8S>, | ||
| 472 | MortonCopy<false, PixelFormat::ABGR8UI>, | ||
| 473 | MortonCopy<false, PixelFormat::B5G6R5U>, | ||
| 474 | MortonCopy<false, PixelFormat::A2B10G10R10U>, | ||
| 475 | MortonCopy<false, PixelFormat::A1B5G5R5U>, | ||
| 476 | MortonCopy<false, PixelFormat::R8U>, | ||
| 477 | MortonCopy<false, PixelFormat::R8UI>, | ||
| 478 | MortonCopy<false, PixelFormat::RGBA16F>, | ||
| 479 | MortonCopy<false, PixelFormat::RGBA16U>, | ||
| 480 | MortonCopy<false, PixelFormat::RGBA16UI>, | ||
| 481 | MortonCopy<false, PixelFormat::R11FG11FB10F>, | ||
| 482 | MortonCopy<false, PixelFormat::RGBA32UI>, | ||
| 483 | MortonCopy<false, PixelFormat::DXT1>, | ||
| 484 | MortonCopy<false, PixelFormat::DXT23>, | ||
| 485 | MortonCopy<false, PixelFormat::DXT45>, | ||
| 486 | MortonCopy<false, PixelFormat::DXN1>, | ||
| 487 | MortonCopy<false, PixelFormat::DXN2UNORM>, | ||
| 488 | MortonCopy<false, PixelFormat::DXN2SNORM>, | ||
| 489 | MortonCopy<false, PixelFormat::BC7U>, | ||
| 490 | MortonCopy<false, PixelFormat::BC6H_UF16>, | ||
| 491 | MortonCopy<false, PixelFormat::BC6H_SF16>, | ||
| 492 | // TODO(Subv): Swizzling ASTC formats are not supported | ||
| 493 | nullptr, | ||
| 494 | MortonCopy<false, PixelFormat::G8R8U>, | ||
| 495 | MortonCopy<false, PixelFormat::G8R8S>, | ||
| 496 | MortonCopy<false, PixelFormat::BGRA8>, | ||
| 497 | MortonCopy<false, PixelFormat::RGBA32F>, | ||
| 498 | MortonCopy<false, PixelFormat::RG32F>, | ||
| 499 | MortonCopy<false, PixelFormat::R32F>, | ||
| 500 | MortonCopy<false, PixelFormat::R16F>, | ||
| 501 | MortonCopy<false, PixelFormat::R16U>, | ||
| 502 | MortonCopy<false, PixelFormat::R16S>, | ||
| 503 | MortonCopy<false, PixelFormat::R16UI>, | ||
| 504 | MortonCopy<false, PixelFormat::R16I>, | ||
| 505 | MortonCopy<false, PixelFormat::RG16>, | ||
| 506 | MortonCopy<false, PixelFormat::RG16F>, | ||
| 507 | MortonCopy<false, PixelFormat::RG16UI>, | ||
| 508 | MortonCopy<false, PixelFormat::RG16I>, | ||
| 509 | MortonCopy<false, PixelFormat::RG16S>, | ||
| 510 | MortonCopy<false, PixelFormat::RGB32F>, | ||
| 511 | MortonCopy<false, PixelFormat::RGBA8_SRGB>, | ||
| 512 | MortonCopy<false, PixelFormat::RG8U>, | ||
| 513 | MortonCopy<false, PixelFormat::RG8S>, | ||
| 514 | MortonCopy<false, PixelFormat::RG32UI>, | ||
| 515 | MortonCopy<false, PixelFormat::R32UI>, | ||
| 516 | nullptr, | ||
| 517 | nullptr, | ||
| 518 | nullptr, | ||
| 519 | MortonCopy<false, PixelFormat::BGRA8_SRGB>, | ||
| 520 | MortonCopy<false, PixelFormat::DXT1_SRGB>, | ||
| 521 | MortonCopy<false, PixelFormat::DXT23_SRGB>, | ||
| 522 | MortonCopy<false, PixelFormat::DXT45_SRGB>, | ||
| 523 | MortonCopy<false, PixelFormat::BC7U_SRGB>, | ||
| 524 | nullptr, | ||
| 525 | nullptr, | ||
| 526 | nullptr, | ||
| 527 | nullptr, | ||
| 528 | nullptr, | ||
| 529 | nullptr, | ||
| 530 | nullptr, | ||
| 531 | nullptr, | ||
| 532 | MortonCopy<false, PixelFormat::Z32F>, | ||
| 533 | MortonCopy<false, PixelFormat::Z16>, | ||
| 534 | MortonCopy<false, PixelFormat::Z24S8>, | ||
| 535 | MortonCopy<false, PixelFormat::S8Z24>, | ||
| 536 | MortonCopy<false, PixelFormat::Z32FS8>, | ||
| 537 | // clang-format on | ||
| 538 | }; | ||
| 539 | |||
| 540 | void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params, | ||
| 541 | std::vector<u8>& gl_buffer, u32 mip_level) { | 380 | std::vector<u8>& gl_buffer, u32 mip_level) { |
| 542 | u32 depth = params.MipDepth(mip_level); | 381 | u32 depth = params.MipDepth(mip_level); |
| 543 | if (params.target == SurfaceTarget::Texture2D) { | 382 | if (params.target == SurfaceTarget::Texture2D) { |
| @@ -550,19 +389,19 @@ void SwizzleFunc(const GLConversionArray& functions, const SurfaceParams& params | |||
| 550 | const u64 layer_size = params.LayerMemorySize(); | 389 | const u64 layer_size = params.LayerMemorySize(); |
| 551 | const u64 gl_size = params.LayerSizeGL(mip_level); | 390 | const u64 gl_size = params.LayerSizeGL(mip_level); |
| 552 | for (u32 i = 0; i < params.depth; i++) { | 391 | for (u32 i = 0; i < params.depth; i++) { |
| 553 | functions[static_cast<std::size_t>(params.pixel_format)]( | 392 | MortonSwizzle(mode, params.pixel_format, params.MipWidth(mip_level), |
| 554 | params.MipWidth(mip_level), params.MipBlockHeight(mip_level), | 393 | params.MipBlockHeight(mip_level), params.MipHeight(mip_level), |
| 555 | params.MipHeight(mip_level), params.MipBlockDepth(mip_level), 1, | 394 | params.MipBlockDepth(mip_level), params.tile_width_spacing, 1, |
| 556 | gl_buffer.data() + offset_gl, gl_size, params.addr + offset); | 395 | gl_buffer.data() + offset_gl, gl_size, params.addr + offset); |
| 557 | offset += layer_size; | 396 | offset += layer_size; |
| 558 | offset_gl += gl_size; | 397 | offset_gl += gl_size; |
| 559 | } | 398 | } |
| 560 | } else { | 399 | } else { |
| 561 | const u64 offset = params.GetMipmapLevelOffset(mip_level); | 400 | const u64 offset = params.GetMipmapLevelOffset(mip_level); |
| 562 | functions[static_cast<std::size_t>(params.pixel_format)]( | 401 | MortonSwizzle(mode, params.pixel_format, params.MipWidth(mip_level), |
| 563 | params.MipWidth(mip_level), params.MipBlockHeight(mip_level), | 402 | params.MipBlockHeight(mip_level), params.MipHeight(mip_level), |
| 564 | params.MipHeight(mip_level), params.MipBlockDepth(mip_level), depth, gl_buffer.data(), | 403 | params.MipBlockDepth(mip_level), depth, params.tile_width_spacing, |
| 565 | gl_buffer.size(), params.addr + offset); | 404 | gl_buffer.data(), gl_buffer.size(), params.addr + offset); |
| 566 | } | 405 | } |
| 567 | } | 406 | } |
| 568 | 407 | ||
| @@ -726,7 +565,7 @@ static void CopySurface(const Surface& src_surface, const Surface& dst_surface, | |||
| 726 | const std::size_t buffer_size = std::max(src_params.size_in_bytes, dst_params.size_in_bytes); | 565 | const std::size_t buffer_size = std::max(src_params.size_in_bytes, dst_params.size_in_bytes); |
| 727 | 566 | ||
| 728 | glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle); | 567 | glBindBuffer(GL_PIXEL_PACK_BUFFER, copy_pbo_handle); |
| 729 | glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW_ARB); | 568 | glBufferData(GL_PIXEL_PACK_BUFFER, buffer_size, nullptr, GL_STREAM_DRAW); |
| 730 | if (source_format.compressed) { | 569 | if (source_format.compressed) { |
| 731 | glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment, | 570 | glGetCompressedTextureImage(src_surface->Texture().handle, src_attachment, |
| 732 | static_cast<GLsizei>(src_params.size_in_bytes), nullptr); | 571 | static_cast<GLsizei>(src_params.size_in_bytes), nullptr); |
| @@ -996,7 +835,7 @@ void CachedSurface::LoadGLBuffer() { | |||
| 996 | ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", | 835 | ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", |
| 997 | params.block_width, static_cast<u32>(params.target)); | 836 | params.block_width, static_cast<u32>(params.target)); |
| 998 | for (u32 i = 0; i < params.max_mip_level; i++) | 837 | for (u32 i = 0; i < params.max_mip_level; i++) |
| 999 | SwizzleFunc(morton_to_gl_fns, params, gl_buffer[i], i); | 838 | SwizzleFunc(MortonSwizzleMode::MortonToLinear, params, gl_buffer[i], i); |
| 1000 | } else { | 839 | } else { |
| 1001 | const auto texture_src_data{Memory::GetPointer(params.addr)}; | 840 | const auto texture_src_data{Memory::GetPointer(params.addr)}; |
| 1002 | const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; | 841 | const auto texture_src_data_end{texture_src_data + params.size_in_bytes_gl}; |
| @@ -1035,7 +874,7 @@ void CachedSurface::FlushGLBuffer() { | |||
| 1035 | ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", | 874 | ASSERT_MSG(params.block_width == 1, "Block width is defined as {} on texture type {}", |
| 1036 | params.block_width, static_cast<u32>(params.target)); | 875 | params.block_width, static_cast<u32>(params.target)); |
| 1037 | 876 | ||
| 1038 | SwizzleFunc(gl_to_morton_fns, params, gl_buffer[0], 0); | 877 | SwizzleFunc(MortonSwizzleMode::LinearToMorton, params, gl_buffer[0], 0); |
| 1039 | } else { | 878 | } else { |
| 1040 | std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes()); | 879 | std::memcpy(Memory::GetPointer(GetAddr()), gl_buffer[0].data(), GetSizeInBytes()); |
| 1041 | } | 880 | } |
| @@ -1275,6 +1114,31 @@ Surface RasterizerCacheOpenGL::GetUncachedSurface(const SurfaceParams& params) { | |||
| 1275 | return surface; | 1114 | return surface; |
| 1276 | } | 1115 | } |
| 1277 | 1116 | ||
| 1117 | void RasterizerCacheOpenGL::FastLayeredCopySurface(const Surface& src_surface, | ||
| 1118 | const Surface& dst_surface) { | ||
| 1119 | const auto& init_params{src_surface->GetSurfaceParams()}; | ||
| 1120 | const auto& dst_params{dst_surface->GetSurfaceParams()}; | ||
| 1121 | VAddr address = init_params.addr; | ||
| 1122 | const std::size_t layer_size = dst_params.LayerMemorySize(); | ||
| 1123 | for (u32 layer = 0; layer < dst_params.depth; layer++) { | ||
| 1124 | for (u32 mipmap = 0; mipmap < dst_params.max_mip_level; mipmap++) { | ||
| 1125 | const VAddr sub_address = address + dst_params.GetMipmapLevelOffset(mipmap); | ||
| 1126 | const Surface& copy = TryGet(sub_address); | ||
| 1127 | if (!copy) | ||
| 1128 | continue; | ||
| 1129 | const auto& src_params{copy->GetSurfaceParams()}; | ||
| 1130 | const u32 width{std::min(src_params.width, dst_params.MipWidth(mipmap))}; | ||
| 1131 | const u32 height{std::min(src_params.height, dst_params.MipHeight(mipmap))}; | ||
| 1132 | |||
| 1133 | glCopyImageSubData(copy->Texture().handle, SurfaceTargetToGL(src_params.target), 0, 0, | ||
| 1134 | 0, 0, dst_surface->Texture().handle, | ||
| 1135 | SurfaceTargetToGL(dst_params.target), mipmap, 0, 0, layer, width, | ||
| 1136 | height, 1); | ||
| 1137 | } | ||
| 1138 | address += layer_size; | ||
| 1139 | } | ||
| 1140 | } | ||
| 1141 | |||
| 1278 | void RasterizerCacheOpenGL::FermiCopySurface( | 1142 | void RasterizerCacheOpenGL::FermiCopySurface( |
| 1279 | const Tegra::Engines::Fermi2D::Regs::Surface& src_config, | 1143 | const Tegra::Engines::Fermi2D::Regs::Surface& src_config, |
| 1280 | const Tegra::Engines::Fermi2D::Regs::Surface& dst_config) { | 1144 | const Tegra::Engines::Fermi2D::Regs::Surface& dst_config) { |
| @@ -1340,11 +1204,13 @@ Surface RasterizerCacheOpenGL::RecreateSurface(const Surface& old_surface, | |||
| 1340 | CopySurface(old_surface, new_surface, copy_pbo.handle); | 1204 | CopySurface(old_surface, new_surface, copy_pbo.handle); |
| 1341 | } | 1205 | } |
| 1342 | break; | 1206 | break; |
| 1343 | case SurfaceTarget::TextureCubemap: | ||
| 1344 | case SurfaceTarget::Texture3D: | 1207 | case SurfaceTarget::Texture3D: |
| 1208 | AccurateCopySurface(old_surface, new_surface); | ||
| 1209 | break; | ||
| 1210 | case SurfaceTarget::TextureCubemap: | ||
| 1345 | case SurfaceTarget::Texture2DArray: | 1211 | case SurfaceTarget::Texture2DArray: |
| 1346 | case SurfaceTarget::TextureCubeArray: | 1212 | case SurfaceTarget::TextureCubeArray: |
| 1347 | AccurateCopySurface(old_surface, new_surface); | 1213 | FastLayeredCopySurface(old_surface, new_surface); |
| 1348 | break; | 1214 | break; |
| 1349 | default: | 1215 | default: |
| 1350 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", | 1216 | LOG_CRITICAL(Render_OpenGL, "Unimplemented surface target={}", |
diff --git a/src/video_core/renderer_opengl/gl_rasterizer_cache.h b/src/video_core/renderer_opengl/gl_rasterizer_cache.h index 494f6b903..c710aa245 100644 --- a/src/video_core/renderer_opengl/gl_rasterizer_cache.h +++ b/src/video_core/renderer_opengl/gl_rasterizer_cache.h | |||
| @@ -196,9 +196,15 @@ struct SurfaceParams { | |||
| 196 | 196 | ||
| 197 | /// Checks if surfaces are compatible for caching | 197 | /// Checks if surfaces are compatible for caching |
| 198 | bool IsCompatibleSurface(const SurfaceParams& other) const { | 198 | bool IsCompatibleSurface(const SurfaceParams& other) const { |
| 199 | return std::tie(pixel_format, type, width, height, target, depth) == | 199 | if (std::tie(pixel_format, type, width, height, target, depth, is_tiled) == |
| 200 | std::tie(other.pixel_format, other.type, other.width, other.height, other.target, | 200 | std::tie(other.pixel_format, other.type, other.width, other.height, other.target, |
| 201 | other.depth); | 201 | other.depth, other.is_tiled)) { |
| 202 | if (!is_tiled) | ||
| 203 | return true; | ||
| 204 | return std::tie(block_height, block_depth, tile_width_spacing) == | ||
| 205 | std::tie(other.block_height, other.block_depth, other.tile_width_spacing); | ||
| 206 | } | ||
| 207 | return false; | ||
| 202 | } | 208 | } |
| 203 | 209 | ||
| 204 | /// Initializes parameters for caching, should be called after everything has been initialized | 210 | /// Initializes parameters for caching, should be called after everything has been initialized |
| @@ -208,6 +214,7 @@ struct SurfaceParams { | |||
| 208 | u32 block_width; | 214 | u32 block_width; |
| 209 | u32 block_height; | 215 | u32 block_height; |
| 210 | u32 block_depth; | 216 | u32 block_depth; |
| 217 | u32 tile_width_spacing; | ||
| 211 | PixelFormat pixel_format; | 218 | PixelFormat pixel_format; |
| 212 | ComponentType component_type; | 219 | ComponentType component_type; |
| 213 | SurfaceType type; | 220 | SurfaceType type; |
| @@ -350,6 +357,7 @@ private: | |||
| 350 | 357 | ||
| 351 | /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data | 358 | /// Performs a slow but accurate surface copy, flushing to RAM and reinterpreting the data |
| 352 | void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface); | 359 | void AccurateCopySurface(const Surface& src_surface, const Surface& dst_surface); |
| 360 | void FastLayeredCopySurface(const Surface& src_surface, const Surface& dst_surface); | ||
| 353 | 361 | ||
| 354 | /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have | 362 | /// The surface reserve is a "backup" cache, this is where we put unique surfaces that have |
| 355 | /// previously been used. This is to prevent surfaces from being constantly created and | 363 | /// previously been used. This is to prevent surfaces from being constantly created and |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.cpp b/src/video_core/renderer_opengl/gl_shader_cache.cpp index a85a7c0c5..038b25c75 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.cpp +++ b/src/video_core/renderer_opengl/gl_shader_cache.cpp | |||
| @@ -84,6 +84,7 @@ CachedShader::CachedShader(VAddr addr, Maxwell::ShaderProgram program_type) | |||
| 84 | } | 84 | } |
| 85 | 85 | ||
| 86 | entries = program_result.second; | 86 | entries = program_result.second; |
| 87 | shader_length = entries.shader_length; | ||
| 87 | 88 | ||
| 88 | if (program_type != Maxwell::ShaderProgram::Geometry) { | 89 | if (program_type != Maxwell::ShaderProgram::Geometry) { |
| 89 | OGLShader shader; | 90 | OGLShader shader; |
diff --git a/src/video_core/renderer_opengl/gl_shader_cache.h b/src/video_core/renderer_opengl/gl_shader_cache.h index ffbf21831..08f470de3 100644 --- a/src/video_core/renderer_opengl/gl_shader_cache.h +++ b/src/video_core/renderer_opengl/gl_shader_cache.h | |||
| @@ -30,7 +30,7 @@ public: | |||
| 30 | } | 30 | } |
| 31 | 31 | ||
| 32 | std::size_t GetSizeInBytes() const override { | 32 | std::size_t GetSizeInBytes() const override { |
| 33 | return GLShader::MAX_PROGRAM_CODE_LENGTH * sizeof(u64); | 33 | return shader_length; |
| 34 | } | 34 | } |
| 35 | 35 | ||
| 36 | // We do not have to flush this cache as things in it are never modified by us. | 36 | // We do not have to flush this cache as things in it are never modified by us. |
| @@ -82,6 +82,7 @@ private: | |||
| 82 | u32 max_vertices, const std::string& debug_name); | 82 | u32 max_vertices, const std::string& debug_name); |
| 83 | 83 | ||
| 84 | VAddr addr; | 84 | VAddr addr; |
| 85 | std::size_t shader_length; | ||
| 85 | Maxwell::ShaderProgram program_type; | 86 | Maxwell::ShaderProgram program_type; |
| 86 | GLShader::ShaderSetup setup; | 87 | GLShader::ShaderSetup setup; |
| 87 | GLShader::ShaderEntries entries; | 88 | GLShader::ShaderEntries entries; |
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp index 90a88b91a..0c4524d5c 100644 --- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp +++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp | |||
| @@ -34,6 +34,17 @@ constexpr u32 PROGRAM_HEADER_SIZE = sizeof(Tegra::Shader::Header); | |||
| 34 | constexpr u32 MAX_GEOMETRY_BUFFERS = 6; | 34 | constexpr u32 MAX_GEOMETRY_BUFFERS = 6; |
| 35 | constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested | 35 | constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested |
| 36 | 36 | ||
| 37 | static const char* INTERNAL_FLAG_NAMES[] = {"zero_flag", "sign_flag", "carry_flag", | ||
| 38 | "overflow_flag"}; | ||
| 39 | |||
| 40 | enum class InternalFlag : u64 { | ||
| 41 | ZeroFlag = 0, | ||
| 42 | SignFlag = 1, | ||
| 43 | CarryFlag = 2, | ||
| 44 | OverflowFlag = 3, | ||
| 45 | Amount | ||
| 46 | }; | ||
| 47 | |||
| 37 | class DecompileFail : public std::runtime_error { | 48 | class DecompileFail : public std::runtime_error { |
| 38 | public: | 49 | public: |
| 39 | using std::runtime_error::runtime_error; | 50 | using std::runtime_error::runtime_error; |
| @@ -84,7 +95,8 @@ struct Subroutine { | |||
| 84 | class ControlFlowAnalyzer { | 95 | class ControlFlowAnalyzer { |
| 85 | public: | 96 | public: |
| 86 | ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset, const std::string& suffix) | 97 | ControlFlowAnalyzer(const ProgramCode& program_code, u32 main_offset, const std::string& suffix) |
| 87 | : program_code(program_code) { | 98 | : program_code(program_code), shader_coverage_begin(main_offset), |
| 99 | shader_coverage_end(main_offset + 1) { | ||
| 88 | 100 | ||
| 89 | // Recursively finds all subroutines. | 101 | // Recursively finds all subroutines. |
| 90 | const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END, suffix); | 102 | const Subroutine& program_main = AddSubroutine(main_offset, PROGRAM_END, suffix); |
| @@ -96,10 +108,16 @@ public: | |||
| 96 | return std::move(subroutines); | 108 | return std::move(subroutines); |
| 97 | } | 109 | } |
| 98 | 110 | ||
| 111 | std::size_t GetShaderLength() const { | ||
| 112 | return shader_coverage_end * sizeof(u64); | ||
| 113 | } | ||
| 114 | |||
| 99 | private: | 115 | private: |
| 100 | const ProgramCode& program_code; | 116 | const ProgramCode& program_code; |
| 101 | std::set<Subroutine> subroutines; | 117 | std::set<Subroutine> subroutines; |
| 102 | std::map<std::pair<u32, u32>, ExitMethod> exit_method_map; | 118 | std::map<std::pair<u32, u32>, ExitMethod> exit_method_map; |
| 119 | u32 shader_coverage_begin; | ||
| 120 | u32 shader_coverage_end; | ||
| 103 | 121 | ||
| 104 | /// Adds and analyzes a new subroutine if it is not added yet. | 122 | /// Adds and analyzes a new subroutine if it is not added yet. |
| 105 | const Subroutine& AddSubroutine(u32 begin, u32 end, const std::string& suffix) { | 123 | const Subroutine& AddSubroutine(u32 begin, u32 end, const std::string& suffix) { |
| @@ -141,6 +159,9 @@ private: | |||
| 141 | return exit_method; | 159 | return exit_method; |
| 142 | 160 | ||
| 143 | for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) { | 161 | for (u32 offset = begin; offset != end && offset != PROGRAM_END; ++offset) { |
| 162 | shader_coverage_begin = std::min(shader_coverage_begin, offset); | ||
| 163 | shader_coverage_end = std::max(shader_coverage_end, offset + 1); | ||
| 164 | |||
| 144 | const Instruction instr = {program_code[offset]}; | 165 | const Instruction instr = {program_code[offset]}; |
| 145 | if (const auto opcode = OpCode::Decode(instr)) { | 166 | if (const auto opcode = OpCode::Decode(instr)) { |
| 146 | switch (opcode->get().GetId()) { | 167 | switch (opcode->get().GetId()) { |
| @@ -257,14 +278,6 @@ private: | |||
| 257 | const std::string& suffix; | 278 | const std::string& suffix; |
| 258 | }; | 279 | }; |
| 259 | 280 | ||
| 260 | enum class InternalFlag : u64 { | ||
| 261 | ZeroFlag = 0, | ||
| 262 | CarryFlag = 1, | ||
| 263 | OverflowFlag = 2, | ||
| 264 | NaNFlag = 3, | ||
| 265 | Amount | ||
| 266 | }; | ||
| 267 | |||
| 268 | /** | 281 | /** |
| 269 | * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state | 282 | * Used to manage shader registers that are emulated with GLSL. This class keeps track of the state |
| 270 | * of all registers (e.g. whether they are currently being used as Floats or Integers), and | 283 | * of all registers (e.g. whether they are currently being used as Floats or Integers), and |
| @@ -371,7 +384,7 @@ public: | |||
| 371 | if (sets_cc) { | 384 | if (sets_cc) { |
| 372 | const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; | 385 | const std::string zero_condition = "( " + ConvertIntegerSize(value, size) + " == 0 )"; |
| 373 | SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); | 386 | SetInternalFlag(InternalFlag::ZeroFlag, zero_condition); |
| 374 | LOG_WARNING(HW_GPU, "Control Codes Imcomplete."); | 387 | LOG_WARNING(HW_GPU, "Condition codes implementation is incomplete."); |
| 375 | } | 388 | } |
| 376 | } | 389 | } |
| 377 | 390 | ||
| @@ -454,23 +467,25 @@ public: | |||
| 454 | shader.AddLine("lmem[" + index + "] = " + func + '(' + value + ");"); | 467 | shader.AddLine("lmem[" + index + "] = " + func + '(' + value + ");"); |
| 455 | } | 468 | } |
| 456 | 469 | ||
| 457 | std::string GetControlCode(const Tegra::Shader::ControlCode cc) const { | 470 | std::string GetConditionCode(const Tegra::Shader::ConditionCode cc) const { |
| 458 | switch (cc) { | 471 | switch (cc) { |
| 459 | case Tegra::Shader::ControlCode::NEU: | 472 | case Tegra::Shader::ConditionCode::NEU: |
| 460 | return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')'; | 473 | return "!(" + GetInternalFlag(InternalFlag::ZeroFlag) + ')'; |
| 461 | default: | 474 | default: |
| 462 | UNIMPLEMENTED_MSG("Unimplemented Control Code: {}", static_cast<u32>(cc)); | 475 | UNIMPLEMENTED_MSG("Unimplemented condition code: {}", static_cast<u32>(cc)); |
| 463 | return "false"; | 476 | return "false"; |
| 464 | } | 477 | } |
| 465 | } | 478 | } |
| 466 | 479 | ||
| 467 | std::string GetInternalFlag(const InternalFlag ii) const { | 480 | std::string GetInternalFlag(const InternalFlag flag) const { |
| 468 | const u32 code = static_cast<u32>(ii); | 481 | const auto index = static_cast<u32>(flag); |
| 469 | return "internalFlag_" + std::to_string(code) + suffix; | 482 | ASSERT(index < static_cast<u32>(InternalFlag::Amount)); |
| 483 | |||
| 484 | return std::string(INTERNAL_FLAG_NAMES[index]) + '_' + suffix; | ||
| 470 | } | 485 | } |
| 471 | 486 | ||
| 472 | void SetInternalFlag(const InternalFlag ii, const std::string& value) const { | 487 | void SetInternalFlag(const InternalFlag flag, const std::string& value) const { |
| 473 | shader.AddLine(GetInternalFlag(ii) + " = " + value + ';'); | 488 | shader.AddLine(GetInternalFlag(flag) + " = " + value + ';'); |
| 474 | } | 489 | } |
| 475 | 490 | ||
| 476 | /** | 491 | /** |
| @@ -485,27 +500,42 @@ public: | |||
| 485 | const Register& buf_reg) { | 500 | const Register& buf_reg) { |
| 486 | const std::string dest = GetOutputAttribute(attribute); | 501 | const std::string dest = GetOutputAttribute(attribute); |
| 487 | const std::string src = GetRegisterAsFloat(val_reg); | 502 | const std::string src = GetRegisterAsFloat(val_reg); |
| 503 | if (dest.empty()) | ||
| 504 | return; | ||
| 488 | 505 | ||
| 489 | if (!dest.empty()) { | 506 | // Can happen with unknown/unimplemented output attributes, in which case we ignore the |
| 490 | // Can happen with unknown/unimplemented output attributes, in which case we ignore the | 507 | // instruction for now. |
| 491 | // instruction for now. | 508 | if (stage == Maxwell3D::Regs::ShaderStage::Geometry) { |
| 492 | if (stage == Maxwell3D::Regs::ShaderStage::Geometry) { | 509 | // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry |
| 493 | // TODO(Rodrigo): nouveau sets some attributes after setting emitting a geometry | 510 | // shader. These instructions use a dirty register as buffer index, to avoid some |
| 494 | // shader. These instructions use a dirty register as buffer index, to avoid some | 511 | // drivers from complaining about out of boundary writes, guard them. |
| 495 | // drivers from complaining about out of boundary writes, guard them. | 512 | const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " + |
| 496 | const std::string buf_index{"((" + GetRegisterAsInteger(buf_reg) + ") % " + | 513 | std::to_string(MAX_GEOMETRY_BUFFERS) + ')'}; |
| 497 | std::to_string(MAX_GEOMETRY_BUFFERS) + ')'}; | 514 | shader.AddLine("amem[" + buf_index + "][" + |
| 498 | shader.AddLine("amem[" + buf_index + "][" + | 515 | std::to_string(static_cast<u32>(attribute)) + ']' + GetSwizzle(elem) + |
| 499 | std::to_string(static_cast<u32>(attribute)) + ']' + | 516 | " = " + src + ';'); |
| 500 | GetSwizzle(elem) + " = " + src + ';'); | 517 | return; |
| 501 | } else { | 518 | } |
| 502 | if (attribute == Attribute::Index::PointSize) { | 519 | |
| 503 | fixed_pipeline_output_attributes_used.insert(attribute); | 520 | switch (attribute) { |
| 504 | shader.AddLine(dest + " = " + src + ';'); | 521 | case Attribute::Index::ClipDistances0123: |
| 505 | } else { | 522 | case Attribute::Index::ClipDistances4567: { |
| 506 | shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';'); | 523 | const u64 index = (attribute == Attribute::Index::ClipDistances4567 ? 4 : 0) + elem; |
| 507 | } | 524 | UNIMPLEMENTED_IF_MSG( |
| 508 | } | 525 | ((header.vtg.clip_distances >> index) & 1) == 0, |
| 526 | "Shader is setting gl_ClipDistance{} without enabling it in the header", index); | ||
| 527 | |||
| 528 | fixed_pipeline_output_attributes_used.insert(attribute); | ||
| 529 | shader.AddLine(dest + '[' + std::to_string(index) + "] = " + src + ';'); | ||
| 530 | break; | ||
| 531 | } | ||
| 532 | case Attribute::Index::PointSize: | ||
| 533 | fixed_pipeline_output_attributes_used.insert(attribute); | ||
| 534 | shader.AddLine(dest + " = " + src + ';'); | ||
| 535 | break; | ||
| 536 | default: | ||
| 537 | shader.AddLine(dest + GetSwizzle(elem) + " = " + src + ';'); | ||
| 538 | break; | ||
| 509 | } | 539 | } |
| 510 | } | 540 | } |
| 511 | 541 | ||
| @@ -621,8 +651,8 @@ private: | |||
| 621 | 651 | ||
| 622 | /// Generates declarations for internal flags. | 652 | /// Generates declarations for internal flags. |
| 623 | void GenerateInternalFlags() { | 653 | void GenerateInternalFlags() { |
| 624 | for (u32 ii = 0; ii < static_cast<u64>(InternalFlag::Amount); ii++) { | 654 | for (u32 flag = 0; flag < static_cast<u32>(InternalFlag::Amount); flag++) { |
| 625 | const InternalFlag code = static_cast<InternalFlag>(ii); | 655 | const InternalFlag code = static_cast<InternalFlag>(flag); |
| 626 | declarations.AddLine("bool " + GetInternalFlag(code) + " = false;"); | 656 | declarations.AddLine("bool " + GetInternalFlag(code) + " = false;"); |
| 627 | } | 657 | } |
| 628 | declarations.AddNewLine(); | 658 | declarations.AddNewLine(); |
| @@ -725,12 +755,19 @@ private: | |||
| 725 | void GenerateVertex() { | 755 | void GenerateVertex() { |
| 726 | if (stage != Maxwell3D::Regs::ShaderStage::Vertex) | 756 | if (stage != Maxwell3D::Regs::ShaderStage::Vertex) |
| 727 | return; | 757 | return; |
| 758 | bool clip_distances_declared = false; | ||
| 759 | |||
| 728 | declarations.AddLine("out gl_PerVertex {"); | 760 | declarations.AddLine("out gl_PerVertex {"); |
| 729 | ++declarations.scope; | 761 | ++declarations.scope; |
| 730 | declarations.AddLine("vec4 gl_Position;"); | 762 | declarations.AddLine("vec4 gl_Position;"); |
| 731 | for (auto& o : fixed_pipeline_output_attributes_used) { | 763 | for (auto& o : fixed_pipeline_output_attributes_used) { |
| 732 | if (o == Attribute::Index::PointSize) | 764 | if (o == Attribute::Index::PointSize) |
| 733 | declarations.AddLine("float gl_PointSize;"); | 765 | declarations.AddLine("float gl_PointSize;"); |
| 766 | if (!clip_distances_declared && (o == Attribute::Index::ClipDistances0123 || | ||
| 767 | o == Attribute::Index::ClipDistances4567)) { | ||
| 768 | declarations.AddLine("float gl_ClipDistance[];"); | ||
| 769 | clip_distances_declared = true; | ||
| 770 | } | ||
| 734 | } | 771 | } |
| 735 | --declarations.scope; | 772 | --declarations.scope; |
| 736 | declarations.AddLine("};"); | 773 | declarations.AddLine("};"); |
| @@ -830,7 +867,8 @@ private: | |||
| 830 | // vertex shader, and what's the value of the fourth element when inside a Tess Eval | 867 | // vertex shader, and what's the value of the fourth element when inside a Tess Eval |
| 831 | // shader. | 868 | // shader. |
| 832 | ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex); | 869 | ASSERT(stage == Maxwell3D::Regs::ShaderStage::Vertex); |
| 833 | return "vec4(0, 0, uintBitsToFloat(instance_id.x), uintBitsToFloat(gl_VertexID))"; | 870 | // Config pack's first value is instance_id. |
| 871 | return "vec4(0, 0, uintBitsToFloat(config_pack[0]), uintBitsToFloat(gl_VertexID))"; | ||
| 834 | case Attribute::Index::FrontFacing: | 872 | case Attribute::Index::FrontFacing: |
| 835 | // TODO(Subv): Find out what the values are for the other elements. | 873 | // TODO(Subv): Find out what the values are for the other elements. |
| 836 | ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment); | 874 | ASSERT(stage == Maxwell3D::Regs::ShaderStage::Fragment); |
| @@ -901,6 +939,10 @@ private: | |||
| 901 | return "gl_PointSize"; | 939 | return "gl_PointSize"; |
| 902 | case Attribute::Index::Position: | 940 | case Attribute::Index::Position: |
| 903 | return "position"; | 941 | return "position"; |
| 942 | case Attribute::Index::ClipDistances0123: | ||
| 943 | case Attribute::Index::ClipDistances4567: { | ||
| 944 | return "gl_ClipDistance"; | ||
| 945 | } | ||
| 904 | default: | 946 | default: |
| 905 | const u32 index{static_cast<u32>(attribute) - | 947 | const u32 index{static_cast<u32>(attribute) - |
| 906 | static_cast<u32>(Attribute::Index::Attribute_0)}; | 948 | static_cast<u32>(Attribute::Index::Attribute_0)}; |
| @@ -939,9 +981,10 @@ private: | |||
| 939 | class GLSLGenerator { | 981 | class GLSLGenerator { |
| 940 | public: | 982 | public: |
| 941 | GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, | 983 | GLSLGenerator(const std::set<Subroutine>& subroutines, const ProgramCode& program_code, |
| 942 | u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix) | 984 | u32 main_offset, Maxwell3D::Regs::ShaderStage stage, const std::string& suffix, |
| 985 | std::size_t shader_length) | ||
| 943 | : subroutines(subroutines), program_code(program_code), main_offset(main_offset), | 986 | : subroutines(subroutines), program_code(program_code), main_offset(main_offset), |
| 944 | stage(stage), suffix(suffix) { | 987 | stage(stage), suffix(suffix), shader_length(shader_length) { |
| 945 | std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); | 988 | std::memcpy(&header, program_code.data(), sizeof(Tegra::Shader::Header)); |
| 946 | local_memory_size = header.GetLocalMemorySize(); | 989 | local_memory_size = header.GetLocalMemorySize(); |
| 947 | regs.SetLocalMemory(local_memory_size); | 990 | regs.SetLocalMemory(local_memory_size); |
| @@ -954,7 +997,7 @@ public: | |||
| 954 | 997 | ||
| 955 | /// Returns entries in the shader that are useful for external functions | 998 | /// Returns entries in the shader that are useful for external functions |
| 956 | ShaderEntries GetEntries() const { | 999 | ShaderEntries GetEntries() const { |
| 957 | return {regs.GetConstBuffersDeclarations(), regs.GetSamplers()}; | 1000 | return {regs.GetConstBuffersDeclarations(), regs.GetSamplers(), shader_length}; |
| 958 | } | 1001 | } |
| 959 | 1002 | ||
| 960 | private: | 1003 | private: |
| @@ -1059,11 +1102,17 @@ private: | |||
| 1059 | const std::string& op_a, const std::string& op_b) const { | 1102 | const std::string& op_a, const std::string& op_b) const { |
| 1060 | using Tegra::Shader::PredCondition; | 1103 | using Tegra::Shader::PredCondition; |
| 1061 | static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = { | 1104 | static const std::unordered_map<PredCondition, const char*> PredicateComparisonStrings = { |
| 1062 | {PredCondition::LessThan, "<"}, {PredCondition::Equal, "=="}, | 1105 | {PredCondition::LessThan, "<"}, |
| 1063 | {PredCondition::LessEqual, "<="}, {PredCondition::GreaterThan, ">"}, | 1106 | {PredCondition::Equal, "=="}, |
| 1064 | {PredCondition::NotEqual, "!="}, {PredCondition::GreaterEqual, ">="}, | 1107 | {PredCondition::LessEqual, "<="}, |
| 1065 | {PredCondition::LessThanWithNan, "<"}, {PredCondition::NotEqualWithNan, "!="}, | 1108 | {PredCondition::GreaterThan, ">"}, |
| 1066 | {PredCondition::GreaterThanWithNan, ">"}, {PredCondition::GreaterEqualWithNan, ">="}}; | 1109 | {PredCondition::NotEqual, "!="}, |
| 1110 | {PredCondition::GreaterEqual, ">="}, | ||
| 1111 | {PredCondition::LessThanWithNan, "<"}, | ||
| 1112 | {PredCondition::NotEqualWithNan, "!="}, | ||
| 1113 | {PredCondition::LessEqualWithNan, "<="}, | ||
| 1114 | {PredCondition::GreaterThanWithNan, ">"}, | ||
| 1115 | {PredCondition::GreaterEqualWithNan, ">="}}; | ||
| 1067 | 1116 | ||
| 1068 | const auto& comparison{PredicateComparisonStrings.find(condition)}; | 1117 | const auto& comparison{PredicateComparisonStrings.find(condition)}; |
| 1069 | UNIMPLEMENTED_IF_MSG(comparison == PredicateComparisonStrings.end(), | 1118 | UNIMPLEMENTED_IF_MSG(comparison == PredicateComparisonStrings.end(), |
| @@ -1072,6 +1121,7 @@ private: | |||
| 1072 | std::string predicate{'(' + op_a + ") " + comparison->second + " (" + op_b + ')'}; | 1121 | std::string predicate{'(' + op_a + ") " + comparison->second + " (" + op_b + ')'}; |
| 1073 | if (condition == PredCondition::LessThanWithNan || | 1122 | if (condition == PredCondition::LessThanWithNan || |
| 1074 | condition == PredCondition::NotEqualWithNan || | 1123 | condition == PredCondition::NotEqualWithNan || |
| 1124 | condition == PredCondition::LessEqualWithNan || | ||
| 1075 | condition == PredCondition::GreaterThanWithNan || | 1125 | condition == PredCondition::GreaterThanWithNan || |
| 1076 | condition == PredCondition::GreaterEqualWithNan) { | 1126 | condition == PredCondition::GreaterEqualWithNan) { |
| 1077 | predicate += " || isnan(" + op_a + ") || isnan(" + op_b + ')'; | 1127 | predicate += " || isnan(" + op_a + ") || isnan(" + op_b + ')'; |
| @@ -1250,6 +1300,7 @@ private: | |||
| 1250 | shader.AddLine('{'); | 1300 | shader.AddLine('{'); |
| 1251 | ++shader.scope; | 1301 | ++shader.scope; |
| 1252 | shader.AddLine(coord); | 1302 | shader.AddLine(coord); |
| 1303 | shader.AddLine("vec4 texture_tmp = " + texture + ';'); | ||
| 1253 | 1304 | ||
| 1254 | // TEXS has two destination registers and a swizzle. The first two elements in the swizzle | 1305 | // TEXS has two destination registers and a swizzle. The first two elements in the swizzle |
| 1255 | // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1 | 1306 | // go into gpr0+0 and gpr0+1, and the rest goes into gpr28+0 and gpr28+1 |
| @@ -1262,18 +1313,17 @@ private: | |||
| 1262 | 1313 | ||
| 1263 | if (written_components < 2) { | 1314 | if (written_components < 2) { |
| 1264 | // Write the first two swizzle components to gpr0 and gpr0+1 | 1315 | // Write the first two swizzle components to gpr0 and gpr0+1 |
| 1265 | regs.SetRegisterToFloat(instr.gpr0, component, texture, 1, 4, false, | 1316 | regs.SetRegisterToFloat(instr.gpr0, component, "texture_tmp", 1, 4, false, |
| 1266 | written_components % 2); | 1317 | written_components % 2); |
| 1267 | } else { | 1318 | } else { |
| 1268 | ASSERT(instr.texs.HasTwoDestinations()); | 1319 | ASSERT(instr.texs.HasTwoDestinations()); |
| 1269 | // Write the rest of the swizzle components to gpr28 and gpr28+1 | 1320 | // Write the rest of the swizzle components to gpr28 and gpr28+1 |
| 1270 | regs.SetRegisterToFloat(instr.gpr28, component, texture, 1, 4, false, | 1321 | regs.SetRegisterToFloat(instr.gpr28, component, "texture_tmp", 1, 4, false, |
| 1271 | written_components % 2); | 1322 | written_components % 2); |
| 1272 | } | 1323 | } |
| 1273 | 1324 | ||
| 1274 | ++written_components; | 1325 | ++written_components; |
| 1275 | } | 1326 | } |
| 1276 | |||
| 1277 | --shader.scope; | 1327 | --shader.scope; |
| 1278 | shader.AddLine('}'); | 1328 | shader.AddLine('}'); |
| 1279 | } | 1329 | } |
| @@ -1508,9 +1558,8 @@ private: | |||
| 1508 | instr.fmul.tab5c68_0 != 1, "FMUL tab5cb8_0({}) is not implemented", | 1558 | instr.fmul.tab5c68_0 != 1, "FMUL tab5cb8_0({}) is not implemented", |
| 1509 | instr.fmul.tab5c68_0 | 1559 | instr.fmul.tab5c68_0 |
| 1510 | .Value()); // SMO typical sends 1 here which seems to be the default | 1560 | .Value()); // SMO typical sends 1 here which seems to be the default |
| 1511 | UNIMPLEMENTED_IF_MSG(instr.fmul.cc != 0, "FMUL cc is not implemented"); | ||
| 1512 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | 1561 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 1513 | "FMUL Generates an unhandled Control Code"); | 1562 | "Condition codes generation in FMUL is not implemented"); |
| 1514 | 1563 | ||
| 1515 | op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b); | 1564 | op_b = GetOperandAbsNeg(op_b, false, instr.fmul.negate_b); |
| 1516 | 1565 | ||
| @@ -1522,7 +1571,7 @@ private: | |||
| 1522 | case OpCode::Id::FADD_R: | 1571 | case OpCode::Id::FADD_R: |
| 1523 | case OpCode::Id::FADD_IMM: { | 1572 | case OpCode::Id::FADD_IMM: { |
| 1524 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | 1573 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 1525 | "FADD Generates an unhandled Control Code"); | 1574 | "Condition codes generation in FADD is not implemented"); |
| 1526 | 1575 | ||
| 1527 | op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); | 1576 | op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); |
| 1528 | op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); | 1577 | op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); |
| @@ -1572,7 +1621,7 @@ private: | |||
| 1572 | case OpCode::Id::FMNMX_R: | 1621 | case OpCode::Id::FMNMX_R: |
| 1573 | case OpCode::Id::FMNMX_IMM: { | 1622 | case OpCode::Id::FMNMX_IMM: { |
| 1574 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | 1623 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 1575 | "FMNMX Generates an unhandled Control Code"); | 1624 | "Condition codes generation in FMNMX is not implemented"); |
| 1576 | 1625 | ||
| 1577 | op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); | 1626 | op_a = GetOperandAbsNeg(op_a, instr.alu.abs_a, instr.alu.negate_a); |
| 1578 | op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); | 1627 | op_b = GetOperandAbsNeg(op_b, instr.alu.abs_b, instr.alu.negate_b); |
| @@ -1609,7 +1658,7 @@ private: | |||
| 1609 | } | 1658 | } |
| 1610 | case OpCode::Id::FMUL32_IMM: { | 1659 | case OpCode::Id::FMUL32_IMM: { |
| 1611 | UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, | 1660 | UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, |
| 1612 | "FMUL32 Generates an unhandled Control Code"); | 1661 | "Condition codes generation in FMUL32 is not implemented"); |
| 1613 | 1662 | ||
| 1614 | regs.SetRegisterToFloat(instr.gpr0, 0, | 1663 | regs.SetRegisterToFloat(instr.gpr0, 0, |
| 1615 | regs.GetRegisterAsFloat(instr.gpr8) + " * " + | 1664 | regs.GetRegisterAsFloat(instr.gpr8) + " * " + |
| @@ -1619,7 +1668,7 @@ private: | |||
| 1619 | } | 1668 | } |
| 1620 | case OpCode::Id::FADD32I: { | 1669 | case OpCode::Id::FADD32I: { |
| 1621 | UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, | 1670 | UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, |
| 1622 | "FADD32 Generates an unhandled Control Code"); | 1671 | "Condition codes generation in FADD32I is not implemented"); |
| 1623 | 1672 | ||
| 1624 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 1673 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| 1625 | std::string op_b = GetImmediate32(instr); | 1674 | std::string op_b = GetImmediate32(instr); |
| @@ -1654,7 +1703,8 @@ private: | |||
| 1654 | 1703 | ||
| 1655 | switch (opcode->get().GetId()) { | 1704 | switch (opcode->get().GetId()) { |
| 1656 | case OpCode::Id::BFE_IMM: { | 1705 | case OpCode::Id::BFE_IMM: { |
| 1657 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, "BFE Generates an unhandled Control Code"); | 1706 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 1707 | "Condition codes generation in BFE is not implemented"); | ||
| 1658 | 1708 | ||
| 1659 | std::string inner_shift = | 1709 | std::string inner_shift = |
| 1660 | '(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')'; | 1710 | '(' + op_a + " << " + std::to_string(instr.bfe.GetLeftShiftValue()) + ')'; |
| @@ -1672,6 +1722,26 @@ private: | |||
| 1672 | 1722 | ||
| 1673 | break; | 1723 | break; |
| 1674 | } | 1724 | } |
| 1725 | case OpCode::Type::Bfi: { | ||
| 1726 | UNIMPLEMENTED_IF(instr.generates_cc); | ||
| 1727 | |||
| 1728 | const auto [base, packed_shift] = [&]() -> std::tuple<std::string, std::string> { | ||
| 1729 | switch (opcode->get().GetId()) { | ||
| 1730 | case OpCode::Id::BFI_IMM_R: | ||
| 1731 | return {regs.GetRegisterAsInteger(instr.gpr39, 0, false), | ||
| 1732 | std::to_string(instr.alu.GetSignedImm20_20())}; | ||
| 1733 | default: | ||
| 1734 | UNREACHABLE(); | ||
| 1735 | } | ||
| 1736 | }(); | ||
| 1737 | const std::string offset = '(' + packed_shift + " & 0xff)"; | ||
| 1738 | const std::string bits = "((" + packed_shift + " >> 8) & 0xff)"; | ||
| 1739 | const std::string insert = regs.GetRegisterAsInteger(instr.gpr8, 0, false); | ||
| 1740 | regs.SetRegisterToInteger( | ||
| 1741 | instr.gpr0, false, 0, | ||
| 1742 | "bitfieldInsert(" + base + ", " + insert + ", " + offset + ", " + bits + ')', 1, 1); | ||
| 1743 | break; | ||
| 1744 | } | ||
| 1675 | case OpCode::Type::Shift: { | 1745 | case OpCode::Type::Shift: { |
| 1676 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true); | 1746 | std::string op_a = regs.GetRegisterAsInteger(instr.gpr8, 0, true); |
| 1677 | std::string op_b; | 1747 | std::string op_b; |
| @@ -1691,7 +1761,8 @@ private: | |||
| 1691 | case OpCode::Id::SHR_C: | 1761 | case OpCode::Id::SHR_C: |
| 1692 | case OpCode::Id::SHR_R: | 1762 | case OpCode::Id::SHR_R: |
| 1693 | case OpCode::Id::SHR_IMM: { | 1763 | case OpCode::Id::SHR_IMM: { |
| 1694 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, "SHR Generates an unhandled Control Code"); | 1764 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 1765 | "Condition codes generation in SHR is not implemented"); | ||
| 1695 | 1766 | ||
| 1696 | if (!instr.shift.is_signed) { | 1767 | if (!instr.shift.is_signed) { |
| 1697 | // Logical shift right | 1768 | // Logical shift right |
| @@ -1706,8 +1777,8 @@ private: | |||
| 1706 | case OpCode::Id::SHL_C: | 1777 | case OpCode::Id::SHL_C: |
| 1707 | case OpCode::Id::SHL_R: | 1778 | case OpCode::Id::SHL_R: |
| 1708 | case OpCode::Id::SHL_IMM: | 1779 | case OpCode::Id::SHL_IMM: |
| 1709 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, "SHL Generates an unhandled Control Code"); | 1780 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 1710 | 1781 | "Condition codes generation in SHL is not implemented"); | |
| 1711 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1); | 1782 | regs.SetRegisterToInteger(instr.gpr0, true, 0, op_a + " << " + op_b, 1, 1); |
| 1712 | break; | 1783 | break; |
| 1713 | default: { | 1784 | default: { |
| @@ -1723,7 +1794,7 @@ private: | |||
| 1723 | switch (opcode->get().GetId()) { | 1794 | switch (opcode->get().GetId()) { |
| 1724 | case OpCode::Id::IADD32I: | 1795 | case OpCode::Id::IADD32I: |
| 1725 | UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, | 1796 | UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, |
| 1726 | "IADD32 Generates an unhandled Control Code"); | 1797 | "Condition codes generation in IADD32I is not implemented"); |
| 1727 | 1798 | ||
| 1728 | if (instr.iadd32i.negate_a) | 1799 | if (instr.iadd32i.negate_a) |
| 1729 | op_a = "-(" + op_a + ')'; | 1800 | op_a = "-(" + op_a + ')'; |
| @@ -1733,7 +1804,7 @@ private: | |||
| 1733 | break; | 1804 | break; |
| 1734 | case OpCode::Id::LOP32I: { | 1805 | case OpCode::Id::LOP32I: { |
| 1735 | UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, | 1806 | UNIMPLEMENTED_IF_MSG(instr.op_32.generates_cc, |
| 1736 | "LOP32I Generates an unhandled Control Code"); | 1807 | "Condition codes generation in LOP32I is not implemented"); |
| 1737 | 1808 | ||
| 1738 | if (instr.alu.lop32i.invert_a) | 1809 | if (instr.alu.lop32i.invert_a) |
| 1739 | op_a = "~(" + op_a + ')'; | 1810 | op_a = "~(" + op_a + ')'; |
| @@ -1772,7 +1843,7 @@ private: | |||
| 1772 | case OpCode::Id::IADD_R: | 1843 | case OpCode::Id::IADD_R: |
| 1773 | case OpCode::Id::IADD_IMM: { | 1844 | case OpCode::Id::IADD_IMM: { |
| 1774 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | 1845 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 1775 | "IADD Generates an unhandled Control Code"); | 1846 | "Condition codes generation in IADD is not implemented"); |
| 1776 | 1847 | ||
| 1777 | if (instr.alu_integer.negate_a) | 1848 | if (instr.alu_integer.negate_a) |
| 1778 | op_a = "-(" + op_a + ')'; | 1849 | op_a = "-(" + op_a + ')'; |
| @@ -1788,7 +1859,7 @@ private: | |||
| 1788 | case OpCode::Id::IADD3_R: | 1859 | case OpCode::Id::IADD3_R: |
| 1789 | case OpCode::Id::IADD3_IMM: { | 1860 | case OpCode::Id::IADD3_IMM: { |
| 1790 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | 1861 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 1791 | "IADD3 Generates an unhandled Control Code"); | 1862 | "Condition codes generation in IADD3 is not implemented"); |
| 1792 | 1863 | ||
| 1793 | std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); | 1864 | std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); |
| 1794 | 1865 | ||
| @@ -1851,7 +1922,7 @@ private: | |||
| 1851 | case OpCode::Id::ISCADD_R: | 1922 | case OpCode::Id::ISCADD_R: |
| 1852 | case OpCode::Id::ISCADD_IMM: { | 1923 | case OpCode::Id::ISCADD_IMM: { |
| 1853 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | 1924 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 1854 | "ISCADD Generates an unhandled Control Code"); | 1925 | "Condition codes generation in ISCADD is not implemented"); |
| 1855 | 1926 | ||
| 1856 | if (instr.alu_integer.negate_a) | 1927 | if (instr.alu_integer.negate_a) |
| 1857 | op_a = "-(" + op_a + ')'; | 1928 | op_a = "-(" + op_a + ')'; |
| @@ -1886,7 +1957,8 @@ private: | |||
| 1886 | case OpCode::Id::LOP_C: | 1957 | case OpCode::Id::LOP_C: |
| 1887 | case OpCode::Id::LOP_R: | 1958 | case OpCode::Id::LOP_R: |
| 1888 | case OpCode::Id::LOP_IMM: { | 1959 | case OpCode::Id::LOP_IMM: { |
| 1889 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, "LOP Generates an unhandled Control Code"); | 1960 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 1961 | "Condition codes generation in LOP is not implemented"); | ||
| 1890 | 1962 | ||
| 1891 | if (instr.alu.lop.invert_a) | 1963 | if (instr.alu.lop.invert_a) |
| 1892 | op_a = "~(" + op_a + ')'; | 1964 | op_a = "~(" + op_a + ')'; |
| @@ -1902,7 +1974,7 @@ private: | |||
| 1902 | case OpCode::Id::LOP3_R: | 1974 | case OpCode::Id::LOP3_R: |
| 1903 | case OpCode::Id::LOP3_IMM: { | 1975 | case OpCode::Id::LOP3_IMM: { |
| 1904 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | 1976 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 1905 | "LOP3 Generates an unhandled Control Code"); | 1977 | "Condition codes generation in LOP3 is not implemented"); |
| 1906 | 1978 | ||
| 1907 | const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); | 1979 | const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39); |
| 1908 | std::string lut; | 1980 | std::string lut; |
| @@ -1921,7 +1993,7 @@ private: | |||
| 1921 | case OpCode::Id::IMNMX_IMM: { | 1993 | case OpCode::Id::IMNMX_IMM: { |
| 1922 | UNIMPLEMENTED_IF(instr.imnmx.exchange != Tegra::Shader::IMinMaxExchange::None); | 1994 | UNIMPLEMENTED_IF(instr.imnmx.exchange != Tegra::Shader::IMinMaxExchange::None); |
| 1923 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | 1995 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 1924 | "IMNMX Generates an unhandled Control Code"); | 1996 | "Condition codes generation in IMNMX is not implemented"); |
| 1925 | 1997 | ||
| 1926 | const std::string condition = | 1998 | const std::string condition = |
| 1927 | GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0); | 1999 | GetPredicateCondition(instr.imnmx.pred, instr.imnmx.negate_pred != 0); |
| @@ -2094,7 +2166,8 @@ private: | |||
| 2094 | instr.ffma.tab5980_0.Value()); // Seems to be 1 by default based on SMO | 2166 | instr.ffma.tab5980_0.Value()); // Seems to be 1 by default based on SMO |
| 2095 | UNIMPLEMENTED_IF_MSG(instr.ffma.tab5980_1 != 0, "FFMA tab5980_1({}) not implemented", | 2167 | UNIMPLEMENTED_IF_MSG(instr.ffma.tab5980_1 != 0, "FFMA tab5980_1({}) not implemented", |
| 2096 | instr.ffma.tab5980_1.Value()); | 2168 | instr.ffma.tab5980_1.Value()); |
| 2097 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, "FFMA Generates an unhandled Control Code"); | 2169 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 2170 | "Condition codes generation in FFMA is not implemented"); | ||
| 2098 | 2171 | ||
| 2099 | switch (opcode->get().GetId()) { | 2172 | switch (opcode->get().GetId()) { |
| 2100 | case OpCode::Id::FFMA_CR: { | 2173 | case OpCode::Id::FFMA_CR: { |
| @@ -2204,7 +2277,8 @@ private: | |||
| 2204 | case OpCode::Id::I2F_C: { | 2277 | case OpCode::Id::I2F_C: { |
| 2205 | UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word); | 2278 | UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word); |
| 2206 | UNIMPLEMENTED_IF(instr.conversion.selector); | 2279 | UNIMPLEMENTED_IF(instr.conversion.selector); |
| 2207 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, "I2F Generates an unhandled Control Code"); | 2280 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 2281 | "Condition codes generation in I2F is not implemented"); | ||
| 2208 | 2282 | ||
| 2209 | std::string op_a{}; | 2283 | std::string op_a{}; |
| 2210 | 2284 | ||
| @@ -2234,7 +2308,8 @@ private: | |||
| 2234 | case OpCode::Id::F2F_R: { | 2308 | case OpCode::Id::F2F_R: { |
| 2235 | UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word); | 2309 | UNIMPLEMENTED_IF(instr.conversion.dest_size != Register::Size::Word); |
| 2236 | UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); | 2310 | UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); |
| 2237 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, "F2F Generates an unhandled Control Code"); | 2311 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 2312 | "Condition codes generation in F2F is not implemented"); | ||
| 2238 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); | 2313 | std::string op_a = regs.GetRegisterAsFloat(instr.gpr20); |
| 2239 | 2314 | ||
| 2240 | if (instr.conversion.abs_a) { | 2315 | if (instr.conversion.abs_a) { |
| @@ -2272,7 +2347,8 @@ private: | |||
| 2272 | case OpCode::Id::F2I_R: | 2347 | case OpCode::Id::F2I_R: |
| 2273 | case OpCode::Id::F2I_C: { | 2348 | case OpCode::Id::F2I_C: { |
| 2274 | UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); | 2349 | UNIMPLEMENTED_IF(instr.conversion.src_size != Register::Size::Word); |
| 2275 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, "F2I Generates an unhandled Control Code"); | 2350 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 2351 | "Condition codes generation in F2I is not implemented"); | ||
| 2276 | std::string op_a{}; | 2352 | std::string op_a{}; |
| 2277 | 2353 | ||
| 2278 | if (instr.is_b_gpr) { | 2354 | if (instr.is_b_gpr) { |
| @@ -2491,61 +2567,83 @@ private: | |||
| 2491 | const bool depth_compare = | 2567 | const bool depth_compare = |
| 2492 | instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); | 2568 | instr.tex.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); |
| 2493 | u32 num_coordinates = TextureCoordinates(texture_type); | 2569 | u32 num_coordinates = TextureCoordinates(texture_type); |
| 2494 | if (depth_compare) | 2570 | u32 start_index = 0; |
| 2495 | num_coordinates += 1; | 2571 | std::string array_elem; |
| 2572 | if (is_array) { | ||
| 2573 | array_elem = regs.GetRegisterAsInteger(instr.gpr8); | ||
| 2574 | start_index = 1; | ||
| 2575 | } | ||
| 2576 | const auto process_mode = instr.tex.GetTextureProcessMode(); | ||
| 2577 | u32 start_index_b = 0; | ||
| 2578 | std::string lod_value; | ||
| 2579 | if (process_mode != Tegra::Shader::TextureProcessMode::LZ && | ||
| 2580 | process_mode != Tegra::Shader::TextureProcessMode::None) { | ||
| 2581 | start_index_b = 1; | ||
| 2582 | lod_value = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2583 | } | ||
| 2584 | |||
| 2585 | std::string depth_value; | ||
| 2586 | if (depth_compare) { | ||
| 2587 | depth_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + start_index_b); | ||
| 2588 | } | ||
| 2589 | |||
| 2590 | bool depth_compare_extra = false; | ||
| 2496 | 2591 | ||
| 2497 | switch (num_coordinates) { | 2592 | switch (num_coordinates) { |
| 2498 | case 1: { | 2593 | case 1: { |
| 2594 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index); | ||
| 2499 | if (is_array) { | 2595 | if (is_array) { |
| 2500 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); | 2596 | if (depth_compare) { |
| 2501 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2597 | coord = "vec3 coords = vec3(" + x + ", " + depth_value + ", " + |
| 2502 | coord = "vec2 coords = vec2(" + x + ", " + index + ");"; | 2598 | array_elem + ");"; |
| 2599 | } else { | ||
| 2600 | coord = "vec2 coords = vec2(" + x + ", " + array_elem + ");"; | ||
| 2601 | } | ||
| 2503 | } else { | 2602 | } else { |
| 2504 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2603 | if (depth_compare) { |
| 2505 | coord = "float coords = " + x + ';'; | 2604 | coord = "vec2 coords = vec2(" + x + ", " + depth_value + ");"; |
| 2605 | } else { | ||
| 2606 | coord = "float coords = " + x + ';'; | ||
| 2607 | } | ||
| 2506 | } | 2608 | } |
| 2507 | break; | 2609 | break; |
| 2508 | } | 2610 | } |
| 2509 | case 2: { | 2611 | case 2: { |
| 2612 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index); | ||
| 2613 | const std::string y = | ||
| 2614 | regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1); | ||
| 2510 | if (is_array) { | 2615 | if (is_array) { |
| 2511 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); | 2616 | if (depth_compare) { |
| 2512 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2617 | coord = "vec4 coords = vec4(" + x + ", " + y + ", " + depth_value + |
| 2513 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2); | 2618 | ", " + array_elem + ");"; |
| 2514 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");"; | 2619 | } else { |
| 2620 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + array_elem + ");"; | ||
| 2621 | } | ||
| 2515 | } else { | 2622 | } else { |
| 2516 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2623 | if (depth_compare) { |
| 2517 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2624 | coord = |
| 2518 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 2625 | "vec3 coords = vec3(" + x + ", " + y + ", " + depth_value + ");"; |
| 2626 | } else { | ||
| 2627 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | ||
| 2628 | } | ||
| 2519 | } | 2629 | } |
| 2520 | break; | 2630 | break; |
| 2521 | } | 2631 | } |
| 2522 | case 3: { | 2632 | case 3: { |
| 2523 | if (depth_compare) { | 2633 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index); |
| 2524 | if (is_array) { | 2634 | const std::string y = |
| 2525 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); | 2635 | regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 1); |
| 2526 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2636 | const std::string z = |
| 2527 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | 2637 | regs.GetRegisterAsFloat(instr.gpr8.Value() + start_index + 2); |
| 2528 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); | 2638 | if (is_array) { |
| 2529 | coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index + | 2639 | depth_compare_extra = depth_compare; |
| 2530 | ");"; | 2640 | coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + |
| 2531 | } else { | 2641 | array_elem + ");"; |
| 2532 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2533 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2534 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2535 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | ||
| 2536 | } | ||
| 2537 | } else { | 2642 | } else { |
| 2538 | if (is_array) { | 2643 | if (depth_compare) { |
| 2539 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); | 2644 | coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + |
| 2540 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2645 | depth_value + ");"; |
| 2541 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2); | ||
| 2542 | const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 3); | ||
| 2543 | coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index + | ||
| 2544 | ");"; | ||
| 2545 | } else { | 2646 | } else { |
| 2546 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2547 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2548 | const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2); | ||
| 2549 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | 2647 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; |
| 2550 | } | 2648 | } |
| 2551 | } | 2649 | } |
| @@ -2561,79 +2659,88 @@ private: | |||
| 2561 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 2659 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; |
| 2562 | texture_type = Tegra::Shader::TextureType::Texture2D; | 2660 | texture_type = Tegra::Shader::TextureType::Texture2D; |
| 2563 | } | 2661 | } |
| 2564 | // TODO: make sure coordinates are always indexed to gpr8 and gpr20 is always bias | ||
| 2565 | // or lod. | ||
| 2566 | std::string op_c; | ||
| 2567 | 2662 | ||
| 2568 | const std::string sampler = | 2663 | const std::string sampler = |
| 2569 | GetSampler(instr.sampler, texture_type, is_array, depth_compare); | 2664 | GetSampler(instr.sampler, texture_type, is_array, depth_compare); |
| 2570 | // Add an extra scope and declare the texture coords inside to prevent | 2665 | // Add an extra scope and declare the texture coords inside to prevent |
| 2571 | // overwriting them in case they are used as outputs of the texs instruction. | 2666 | // overwriting them in case they are used as outputs of the texs instruction. |
| 2572 | 2667 | ||
| 2573 | shader.AddLine("{"); | 2668 | shader.AddLine('{'); |
| 2574 | ++shader.scope; | 2669 | ++shader.scope; |
| 2575 | shader.AddLine(coord); | 2670 | shader.AddLine(coord); |
| 2576 | std::string texture; | 2671 | std::string texture; |
| 2577 | 2672 | ||
| 2578 | switch (instr.tex.GetTextureProcessMode()) { | 2673 | switch (instr.tex.GetTextureProcessMode()) { |
| 2579 | case Tegra::Shader::TextureProcessMode::None: { | 2674 | case Tegra::Shader::TextureProcessMode::None: { |
| 2580 | texture = "texture(" + sampler + ", coords)"; | 2675 | if (!depth_compare_extra) { |
| 2676 | texture = "texture(" + sampler + ", coords)"; | ||
| 2677 | } else { | ||
| 2678 | texture = "texture(" + sampler + ", coords, " + depth_value + ')'; | ||
| 2679 | } | ||
| 2581 | break; | 2680 | break; |
| 2582 | } | 2681 | } |
| 2583 | case Tegra::Shader::TextureProcessMode::LZ: { | 2682 | case Tegra::Shader::TextureProcessMode::LZ: { |
| 2584 | texture = "textureLod(" + sampler + ", coords, 0.0)"; | 2683 | if (!depth_compare_extra) { |
| 2684 | texture = "textureLod(" + sampler + ", coords, 0.0)"; | ||
| 2685 | } else { | ||
| 2686 | texture = "texture(" + sampler + ", coords, " + depth_value + ')'; | ||
| 2687 | } | ||
| 2585 | break; | 2688 | break; |
| 2586 | } | 2689 | } |
| 2587 | case Tegra::Shader::TextureProcessMode::LB: | 2690 | case Tegra::Shader::TextureProcessMode::LB: |
| 2588 | case Tegra::Shader::TextureProcessMode::LBA: { | 2691 | case Tegra::Shader::TextureProcessMode::LBA: { |
| 2589 | if (depth_compare) { | 2692 | // TODO: Figure if A suffix changes the equation at all. |
| 2590 | if (is_array) | 2693 | if (!depth_compare_extra) { |
| 2591 | op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 2); | 2694 | texture = "texture(" + sampler + ", coords, " + lod_value + ')'; |
| 2592 | else | ||
| 2593 | op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); | ||
| 2594 | } else { | 2695 | } else { |
| 2595 | op_c = regs.GetRegisterAsFloat(instr.gpr20); | 2696 | texture = "texture(" + sampler + ", coords, " + depth_value + ')'; |
| 2697 | LOG_WARNING(HW_GPU, | ||
| 2698 | "OpenGL Limitation: can't set bias value along depth compare"); | ||
| 2596 | } | 2699 | } |
| 2597 | // TODO: Figure if A suffix changes the equation at all. | ||
| 2598 | texture = "texture(" + sampler + ", coords, " + op_c + ')'; | ||
| 2599 | break; | 2700 | break; |
| 2600 | } | 2701 | } |
| 2601 | case Tegra::Shader::TextureProcessMode::LL: | 2702 | case Tegra::Shader::TextureProcessMode::LL: |
| 2602 | case Tegra::Shader::TextureProcessMode::LLA: { | 2703 | case Tegra::Shader::TextureProcessMode::LLA: { |
| 2603 | if (num_coordinates <= 2) { | 2704 | // TODO: Figure if A suffix changes the equation at all. |
| 2604 | op_c = regs.GetRegisterAsFloat(instr.gpr20); | 2705 | if (!depth_compare_extra) { |
| 2706 | texture = "textureLod(" + sampler + ", coords, " + lod_value + ')'; | ||
| 2605 | } else { | 2707 | } else { |
| 2606 | op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); | 2708 | texture = "texture(" + sampler + ", coords, " + depth_value + ')'; |
| 2709 | LOG_WARNING(HW_GPU, | ||
| 2710 | "OpenGL Limitation: can't set lod value along depth compare"); | ||
| 2607 | } | 2711 | } |
| 2608 | // TODO: Figure if A suffix changes the equation at all. | ||
| 2609 | texture = "textureLod(" + sampler + ", coords, " + op_c + ')'; | ||
| 2610 | break; | 2712 | break; |
| 2611 | } | 2713 | } |
| 2612 | default: { | 2714 | default: { |
| 2613 | texture = "texture(" + sampler + ", coords)"; | 2715 | if (!depth_compare_extra) { |
| 2716 | texture = "texture(" + sampler + ", coords)"; | ||
| 2717 | } else { | ||
| 2718 | texture = "texture(" + sampler + ", coords, " + depth_value + ')'; | ||
| 2719 | } | ||
| 2614 | UNIMPLEMENTED_MSG("Unhandled texture process mode {}", | 2720 | UNIMPLEMENTED_MSG("Unhandled texture process mode {}", |
| 2615 | static_cast<u32>(instr.tex.GetTextureProcessMode())); | 2721 | static_cast<u32>(instr.tex.GetTextureProcessMode())); |
| 2616 | } | 2722 | } |
| 2617 | } | 2723 | } |
| 2618 | if (!depth_compare) { | 2724 | if (!depth_compare) { |
| 2725 | shader.AddLine("vec4 texture_tmp = " + texture + ';'); | ||
| 2619 | std::size_t dest_elem{}; | 2726 | std::size_t dest_elem{}; |
| 2620 | for (std::size_t elem = 0; elem < 4; ++elem) { | 2727 | for (std::size_t elem = 0; elem < 4; ++elem) { |
| 2621 | if (!instr.tex.IsComponentEnabled(elem)) { | 2728 | if (!instr.tex.IsComponentEnabled(elem)) { |
| 2622 | // Skip disabled components | 2729 | // Skip disabled components |
| 2623 | continue; | 2730 | continue; |
| 2624 | } | 2731 | } |
| 2625 | regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); | 2732 | regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, |
| 2733 | dest_elem); | ||
| 2626 | ++dest_elem; | 2734 | ++dest_elem; |
| 2627 | } | 2735 | } |
| 2628 | } else { | 2736 | } else { |
| 2629 | regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); | 2737 | regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); |
| 2630 | } | 2738 | } |
| 2631 | --shader.scope; | 2739 | --shader.scope; |
| 2632 | shader.AddLine("}"); | 2740 | shader.AddLine('}'); |
| 2633 | break; | 2741 | break; |
| 2634 | } | 2742 | } |
| 2635 | case OpCode::Id::TEXS: { | 2743 | case OpCode::Id::TEXS: { |
| 2636 | std::string coord; | ||
| 2637 | Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; | 2744 | Tegra::Shader::TextureType texture_type{instr.texs.GetTextureType()}; |
| 2638 | bool is_array{instr.texs.IsArrayTexture()}; | 2745 | bool is_array{instr.texs.IsArrayTexture()}; |
| 2639 | 2746 | ||
| @@ -2643,37 +2750,76 @@ private: | |||
| 2643 | const bool depth_compare = | 2750 | const bool depth_compare = |
| 2644 | instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); | 2751 | instr.texs.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); |
| 2645 | u32 num_coordinates = TextureCoordinates(texture_type); | 2752 | u32 num_coordinates = TextureCoordinates(texture_type); |
| 2646 | if (depth_compare) | 2753 | const auto process_mode = instr.texs.GetTextureProcessMode(); |
| 2647 | num_coordinates += 1; | 2754 | std::string lod_value; |
| 2755 | std::string coord; | ||
| 2756 | u32 lod_offset = 0; | ||
| 2757 | if (process_mode == Tegra::Shader::TextureProcessMode::LL) { | ||
| 2758 | if (num_coordinates > 2) { | ||
| 2759 | lod_value = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); | ||
| 2760 | lod_offset = 2; | ||
| 2761 | } else { | ||
| 2762 | lod_value = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2763 | lod_offset = 1; | ||
| 2764 | } | ||
| 2765 | } | ||
| 2648 | 2766 | ||
| 2649 | switch (num_coordinates) { | 2767 | switch (num_coordinates) { |
| 2768 | case 1: { | ||
| 2769 | coord = "float coords = " + regs.GetRegisterAsFloat(instr.gpr8) + ';'; | ||
| 2770 | break; | ||
| 2771 | } | ||
| 2650 | case 2: { | 2772 | case 2: { |
| 2651 | if (is_array) { | 2773 | if (is_array) { |
| 2652 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); | 2774 | if (depth_compare) { |
| 2653 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2775 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); |
| 2654 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | 2776 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2655 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");"; | 2777 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); |
| 2778 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); | ||
| 2779 | coord = "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index + | ||
| 2780 | ");"; | ||
| 2781 | } else { | ||
| 2782 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); | ||
| 2783 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2784 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2785 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + index + ");"; | ||
| 2786 | } | ||
| 2656 | } else { | 2787 | } else { |
| 2657 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2788 | if (lod_offset != 0) { |
| 2658 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | 2789 | if (depth_compare) { |
| 2659 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 2790 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 2791 | const std::string y = | ||
| 2792 | regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2793 | const std::string z = | ||
| 2794 | regs.GetRegisterAsFloat(instr.gpr20.Value() + lod_offset); | ||
| 2795 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | ||
| 2796 | } else { | ||
| 2797 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2798 | const std::string y = | ||
| 2799 | regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2800 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | ||
| 2801 | } | ||
| 2802 | } else { | ||
| 2803 | if (depth_compare) { | ||
| 2804 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2805 | const std::string y = | ||
| 2806 | regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2807 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2808 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | ||
| 2809 | } else { | ||
| 2810 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2811 | const std::string y = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2812 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | ||
| 2813 | } | ||
| 2814 | } | ||
| 2660 | } | 2815 | } |
| 2661 | break; | 2816 | break; |
| 2662 | } | 2817 | } |
| 2663 | case 3: { | 2818 | case 3: { |
| 2664 | if (is_array) { | 2819 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 2665 | const std::string index = regs.GetRegisterAsInteger(instr.gpr8); | 2820 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2666 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2821 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); |
| 2667 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2); | 2822 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; |
| 2668 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2669 | coord = | ||
| 2670 | "vec4 coords = vec4(" + x + ", " + y + ", " + z + ", " + index + ");"; | ||
| 2671 | } else { | ||
| 2672 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | ||
| 2673 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | ||
| 2674 | const std::string z = regs.GetRegisterAsFloat(instr.gpr20); | ||
| 2675 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | ||
| 2676 | } | ||
| 2677 | break; | 2823 | break; |
| 2678 | } | 2824 | } |
| 2679 | default: | 2825 | default: |
| @@ -2690,7 +2836,7 @@ private: | |||
| 2690 | const std::string sampler = | 2836 | const std::string sampler = |
| 2691 | GetSampler(instr.sampler, texture_type, is_array, depth_compare); | 2837 | GetSampler(instr.sampler, texture_type, is_array, depth_compare); |
| 2692 | std::string texture; | 2838 | std::string texture; |
| 2693 | switch (instr.texs.GetTextureProcessMode()) { | 2839 | switch (process_mode) { |
| 2694 | case Tegra::Shader::TextureProcessMode::None: { | 2840 | case Tegra::Shader::TextureProcessMode::None: { |
| 2695 | texture = "texture(" + sampler + ", coords)"; | 2841 | texture = "texture(" + sampler + ", coords)"; |
| 2696 | break; | 2842 | break; |
| @@ -2704,8 +2850,7 @@ private: | |||
| 2704 | break; | 2850 | break; |
| 2705 | } | 2851 | } |
| 2706 | case Tegra::Shader::TextureProcessMode::LL: { | 2852 | case Tegra::Shader::TextureProcessMode::LL: { |
| 2707 | const std::string op_c = regs.GetRegisterAsFloat(instr.gpr20.Value() + 1); | 2853 | texture = "textureLod(" + sampler + ", coords, " + lod_value + ')'; |
| 2708 | texture = "textureLod(" + sampler + ", coords, " + op_c + ')'; | ||
| 2709 | break; | 2854 | break; |
| 2710 | } | 2855 | } |
| 2711 | default: { | 2856 | default: { |
| @@ -2719,10 +2864,10 @@ private: | |||
| 2719 | } else { | 2864 | } else { |
| 2720 | WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); | 2865 | WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); |
| 2721 | } | 2866 | } |
| 2867 | |||
| 2722 | break; | 2868 | break; |
| 2723 | } | 2869 | } |
| 2724 | case OpCode::Id::TLDS: { | 2870 | case OpCode::Id::TLDS: { |
| 2725 | std::string coord; | ||
| 2726 | const Tegra::Shader::TextureType texture_type{instr.tlds.GetTextureType()}; | 2871 | const Tegra::Shader::TextureType texture_type{instr.tlds.GetTextureType()}; |
| 2727 | const bool is_array{instr.tlds.IsArrayTexture()}; | 2872 | const bool is_array{instr.tlds.IsArrayTexture()}; |
| 2728 | 2873 | ||
| @@ -2736,12 +2881,17 @@ private: | |||
| 2736 | UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::MZ), | 2881 | UNIMPLEMENTED_IF_MSG(instr.tlds.UsesMiscMode(Tegra::Shader::TextureMiscMode::MZ), |
| 2737 | "MZ is not implemented"); | 2882 | "MZ is not implemented"); |
| 2738 | 2883 | ||
| 2739 | u32 op_c_offset = 0; | 2884 | u32 extra_op_offset = 0; |
| 2885 | |||
| 2886 | // Scope to avoid variable name overlaps. | ||
| 2887 | shader.AddLine('{'); | ||
| 2888 | ++shader.scope; | ||
| 2889 | std::string coords; | ||
| 2740 | 2890 | ||
| 2741 | switch (texture_type) { | 2891 | switch (texture_type) { |
| 2742 | case Tegra::Shader::TextureType::Texture1D: { | 2892 | case Tegra::Shader::TextureType::Texture1D: { |
| 2743 | const std::string x = regs.GetRegisterAsInteger(instr.gpr8); | 2893 | const std::string x = regs.GetRegisterAsInteger(instr.gpr8); |
| 2744 | coord = "int coords = " + x + ';'; | 2894 | coords = "float coords = " + x + ';'; |
| 2745 | break; | 2895 | break; |
| 2746 | } | 2896 | } |
| 2747 | case Tegra::Shader::TextureType::Texture2D: { | 2897 | case Tegra::Shader::TextureType::Texture2D: { |
| @@ -2749,8 +2899,9 @@ private: | |||
| 2749 | 2899 | ||
| 2750 | const std::string x = regs.GetRegisterAsInteger(instr.gpr8); | 2900 | const std::string x = regs.GetRegisterAsInteger(instr.gpr8); |
| 2751 | const std::string y = regs.GetRegisterAsInteger(instr.gpr20); | 2901 | const std::string y = regs.GetRegisterAsInteger(instr.gpr20); |
| 2752 | coord = "ivec2 coords = ivec2(" + x + ", " + y + ");"; | 2902 | // shader.AddLine("ivec2 coords = ivec2(" + x + ", " + y + ");"); |
| 2753 | op_c_offset = 1; | 2903 | coords = "ivec2 coords = ivec2(" + x + ", " + y + ");"; |
| 2904 | extra_op_offset = 1; | ||
| 2754 | break; | 2905 | break; |
| 2755 | } | 2906 | } |
| 2756 | default: | 2907 | default: |
| @@ -2765,9 +2916,10 @@ private: | |||
| 2765 | break; | 2916 | break; |
| 2766 | } | 2917 | } |
| 2767 | case Tegra::Shader::TextureProcessMode::LL: { | 2918 | case Tegra::Shader::TextureProcessMode::LL: { |
| 2768 | const std::string op_c = | 2919 | shader.AddLine( |
| 2769 | regs.GetRegisterAsInteger(instr.gpr20.Value() + op_c_offset); | 2920 | "float lod = " + |
| 2770 | texture = "texelFetch(" + sampler + ", coords, " + op_c + ')'; | 2921 | regs.GetRegisterAsInteger(instr.gpr20.Value() + extra_op_offset) + ';'); |
| 2922 | texture = "texelFetch(" + sampler + ", coords, lod)"; | ||
| 2771 | break; | 2923 | break; |
| 2772 | } | 2924 | } |
| 2773 | default: { | 2925 | default: { |
| @@ -2776,7 +2928,10 @@ private: | |||
| 2776 | static_cast<u32>(instr.tlds.GetTextureProcessMode())); | 2928 | static_cast<u32>(instr.tlds.GetTextureProcessMode())); |
| 2777 | } | 2929 | } |
| 2778 | } | 2930 | } |
| 2779 | WriteTexsInstruction(instr, coord, texture); | 2931 | WriteTexsInstruction(instr, coords, texture); |
| 2932 | |||
| 2933 | --shader.scope; | ||
| 2934 | shader.AddLine('}'); | ||
| 2780 | break; | 2935 | break; |
| 2781 | } | 2936 | } |
| 2782 | case OpCode::Id::TLD4: { | 2937 | case OpCode::Id::TLD4: { |
| @@ -2799,18 +2954,23 @@ private: | |||
| 2799 | if (depth_compare) | 2954 | if (depth_compare) |
| 2800 | num_coordinates += 1; | 2955 | num_coordinates += 1; |
| 2801 | 2956 | ||
| 2957 | // Add an extra scope and declare the texture coords inside to prevent | ||
| 2958 | // overwriting them in case they are used as outputs of the texs instruction. | ||
| 2959 | shader.AddLine('{'); | ||
| 2960 | ++shader.scope; | ||
| 2961 | |||
| 2802 | switch (num_coordinates) { | 2962 | switch (num_coordinates) { |
| 2803 | case 2: { | 2963 | case 2: { |
| 2804 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2964 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 2805 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2965 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2806 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 2966 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); |
| 2807 | break; | 2967 | break; |
| 2808 | } | 2968 | } |
| 2809 | case 3: { | 2969 | case 3: { |
| 2810 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2970 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 2811 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2971 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2812 | const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2); | 2972 | const std::string z = regs.GetRegisterAsFloat(instr.gpr8.Value() + 2); |
| 2813 | coord = "vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"; | 2973 | shader.AddLine("vec3 coords = vec3(" + x + ", " + y + ", " + z + ");"); |
| 2814 | break; | 2974 | break; |
| 2815 | } | 2975 | } |
| 2816 | default: | 2976 | default: |
| @@ -2818,34 +2978,33 @@ private: | |||
| 2818 | static_cast<u32>(num_coordinates)); | 2978 | static_cast<u32>(num_coordinates)); |
| 2819 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); | 2979 | const std::string x = regs.GetRegisterAsFloat(instr.gpr8); |
| 2820 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 2980 | const std::string y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2821 | coord = "vec2 coords = vec2(" + x + ", " + y + ");"; | 2981 | shader.AddLine("vec2 coords = vec2(" + x + ", " + y + ");"); |
| 2822 | texture_type = Tegra::Shader::TextureType::Texture2D; | 2982 | texture_type = Tegra::Shader::TextureType::Texture2D; |
| 2823 | } | 2983 | } |
| 2824 | 2984 | ||
| 2825 | const std::string sampler = | 2985 | const std::string sampler = |
| 2826 | GetSampler(instr.sampler, texture_type, false, depth_compare); | 2986 | GetSampler(instr.sampler, texture_type, false, depth_compare); |
| 2827 | // Add an extra scope and declare the texture coords inside to prevent | 2987 | |
| 2828 | // overwriting them in case they are used as outputs of the texs instruction. | ||
| 2829 | shader.AddLine("{"); | ||
| 2830 | ++shader.scope; | ||
| 2831 | shader.AddLine(coord); | ||
| 2832 | const std::string texture = "textureGather(" + sampler + ", coords, " + | 2988 | const std::string texture = "textureGather(" + sampler + ", coords, " + |
| 2833 | std::to_string(instr.tld4.component) + ')'; | 2989 | std::to_string(instr.tld4.component) + ')'; |
| 2990 | |||
| 2834 | if (!depth_compare) { | 2991 | if (!depth_compare) { |
| 2992 | shader.AddLine("vec4 texture_tmp = " + texture + ';'); | ||
| 2835 | std::size_t dest_elem{}; | 2993 | std::size_t dest_elem{}; |
| 2836 | for (std::size_t elem = 0; elem < 4; ++elem) { | 2994 | for (std::size_t elem = 0; elem < 4; ++elem) { |
| 2837 | if (!instr.tex.IsComponentEnabled(elem)) { | 2995 | if (!instr.tex.IsComponentEnabled(elem)) { |
| 2838 | // Skip disabled components | 2996 | // Skip disabled components |
| 2839 | continue; | 2997 | continue; |
| 2840 | } | 2998 | } |
| 2841 | regs.SetRegisterToFloat(instr.gpr0, elem, texture, 1, 4, false, dest_elem); | 2999 | regs.SetRegisterToFloat(instr.gpr0, elem, "texture_tmp", 1, 4, false, |
| 3000 | dest_elem); | ||
| 2842 | ++dest_elem; | 3001 | ++dest_elem; |
| 2843 | } | 3002 | } |
| 2844 | } else { | 3003 | } else { |
| 2845 | regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); | 3004 | regs.SetRegisterToFloat(instr.gpr0, 0, texture, 1, 1, false); |
| 2846 | } | 3005 | } |
| 2847 | --shader.scope; | 3006 | --shader.scope; |
| 2848 | shader.AddLine("}"); | 3007 | shader.AddLine('}'); |
| 2849 | break; | 3008 | break; |
| 2850 | } | 3009 | } |
| 2851 | case OpCode::Id::TLD4S: { | 3010 | case OpCode::Id::TLD4S: { |
| @@ -2856,6 +3015,11 @@ private: | |||
| 2856 | instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), | 3015 | instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::AOFFI), |
| 2857 | "AOFFI is not implemented"); | 3016 | "AOFFI is not implemented"); |
| 2858 | 3017 | ||
| 3018 | // Scope to avoid variable name overlaps. | ||
| 3019 | shader.AddLine('{'); | ||
| 3020 | ++shader.scope; | ||
| 3021 | std::string coords; | ||
| 3022 | |||
| 2859 | const bool depth_compare = | 3023 | const bool depth_compare = |
| 2860 | instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); | 3024 | instr.tld4s.UsesMiscMode(Tegra::Shader::TextureMiscMode::DC); |
| 2861 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); | 3025 | const std::string op_a = regs.GetRegisterAsFloat(instr.gpr8); |
| @@ -2863,28 +3027,32 @@ private: | |||
| 2863 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. | 3027 | // TODO(Subv): Figure out how the sampler type is encoded in the TLD4S instruction. |
| 2864 | const std::string sampler = GetSampler( | 3028 | const std::string sampler = GetSampler( |
| 2865 | instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare); | 3029 | instr.sampler, Tegra::Shader::TextureType::Texture2D, false, depth_compare); |
| 2866 | std::string coord; | ||
| 2867 | if (!depth_compare) { | 3030 | if (!depth_compare) { |
| 2868 | coord = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; | 3031 | coords = "vec2 coords = vec2(" + op_a + ", " + op_b + ");"; |
| 2869 | } else { | 3032 | } else { |
| 2870 | // Note: TLD4S coordinate encoding works just like TEXS's | 3033 | // Note: TLD4S coordinate encoding works just like TEXS's |
| 2871 | const std::string op_c = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); | 3034 | const std::string op_y = regs.GetRegisterAsFloat(instr.gpr8.Value() + 1); |
| 2872 | coord = "vec3 coords = vec3(" + op_a + ", " + op_c + ", " + op_b + ");"; | 3035 | coords = "vec3 coords = vec3(" + op_a + ", " + op_y + ", " + op_b + ");"; |
| 2873 | } | 3036 | } |
| 2874 | const std::string texture = "textureGather(" + sampler + ", coords, " + | 3037 | const std::string texture = "textureGather(" + sampler + ", coords, " + |
| 2875 | std::to_string(instr.tld4s.component) + ')'; | 3038 | std::to_string(instr.tld4s.component) + ')'; |
| 2876 | 3039 | ||
| 2877 | if (!depth_compare) { | 3040 | if (!depth_compare) { |
| 2878 | WriteTexsInstruction(instr, coord, texture); | 3041 | WriteTexsInstruction(instr, coords, texture); |
| 2879 | } else { | 3042 | } else { |
| 2880 | WriteTexsInstruction(instr, coord, "vec4(" + texture + ')'); | 3043 | WriteTexsInstruction(instr, coords, "vec4(" + texture + ')'); |
| 2881 | } | 3044 | } |
| 3045 | |||
| 3046 | --shader.scope; | ||
| 3047 | shader.AddLine('}'); | ||
| 2882 | break; | 3048 | break; |
| 2883 | } | 3049 | } |
| 2884 | case OpCode::Id::TXQ: { | 3050 | case OpCode::Id::TXQ: { |
| 2885 | UNIMPLEMENTED_IF_MSG(instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), | 3051 | UNIMPLEMENTED_IF_MSG(instr.txq.UsesMiscMode(Tegra::Shader::TextureMiscMode::NODEP), |
| 2886 | "NODEP is not implemented"); | 3052 | "NODEP is not implemented"); |
| 2887 | 3053 | ||
| 3054 | ++shader.scope; | ||
| 3055 | shader.AddLine('{'); | ||
| 2888 | // TODO: the new commits on the texture refactor, change the way samplers work. | 3056 | // TODO: the new commits on the texture refactor, change the way samplers work. |
| 2889 | // Sadly, not all texture instructions specify the type of texture their sampler | 3057 | // Sadly, not all texture instructions specify the type of texture their sampler |
| 2890 | // uses. This must be fixed at a later instance. | 3058 | // uses. This must be fixed at a later instance. |
| @@ -2892,8 +3060,14 @@ private: | |||
| 2892 | GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false); | 3060 | GetSampler(instr.sampler, Tegra::Shader::TextureType::Texture2D, false, false); |
| 2893 | switch (instr.txq.query_type) { | 3061 | switch (instr.txq.query_type) { |
| 2894 | case Tegra::Shader::TextureQueryType::Dimension: { | 3062 | case Tegra::Shader::TextureQueryType::Dimension: { |
| 2895 | const std::string texture = "textureQueryLevels(" + sampler + ')'; | 3063 | const std::string texture = "textureSize(" + sampler + ", " + |
| 2896 | regs.SetRegisterToInteger(instr.gpr0, true, 0, texture, 1, 1); | 3064 | regs.GetRegisterAsInteger(instr.gpr8) + ')'; |
| 3065 | const std::string mip_level = "textureQueryLevels(" + sampler + ')'; | ||
| 3066 | shader.AddLine("ivec2 sizes = " + texture + ';'); | ||
| 3067 | regs.SetRegisterToInteger(instr.gpr0, true, 0, "sizes.x", 1, 1); | ||
| 3068 | regs.SetRegisterToInteger(instr.gpr0.Value() + 1, true, 0, "sizes.y", 1, 1); | ||
| 3069 | regs.SetRegisterToInteger(instr.gpr0.Value() + 2, true, 0, "0", 1, 1); | ||
| 3070 | regs.SetRegisterToInteger(instr.gpr0.Value() + 3, true, 0, mip_level, 1, 1); | ||
| 2897 | break; | 3071 | break; |
| 2898 | } | 3072 | } |
| 2899 | default: { | 3073 | default: { |
| @@ -2901,6 +3075,8 @@ private: | |||
| 2901 | static_cast<u32>(instr.txq.query_type.Value())); | 3075 | static_cast<u32>(instr.txq.query_type.Value())); |
| 2902 | } | 3076 | } |
| 2903 | } | 3077 | } |
| 3078 | --shader.scope; | ||
| 3079 | shader.AddLine('}'); | ||
| 2904 | break; | 3080 | break; |
| 2905 | } | 3081 | } |
| 2906 | case OpCode::Id::TMML: { | 3082 | case OpCode::Id::TMML: { |
| @@ -3083,7 +3259,8 @@ private: | |||
| 3083 | break; | 3259 | break; |
| 3084 | } | 3260 | } |
| 3085 | case OpCode::Type::PredicateSetRegister: { | 3261 | case OpCode::Type::PredicateSetRegister: { |
| 3086 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, "PSET Generates an unhandled Control Code"); | 3262 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 3263 | "Condition codes generation in PSET is not implemented"); | ||
| 3087 | 3264 | ||
| 3088 | const std::string op_a = | 3265 | const std::string op_a = |
| 3089 | GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0); | 3266 | GetPredicateCondition(instr.pset.pred12, instr.pset.neg_pred12 != 0); |
| @@ -3142,14 +3319,14 @@ private: | |||
| 3142 | const std::string pred = | 3319 | const std::string pred = |
| 3143 | GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0); | 3320 | GetPredicateCondition(instr.csetp.pred39, instr.csetp.neg_pred39 != 0); |
| 3144 | const std::string combiner = GetPredicateCombiner(instr.csetp.op); | 3321 | const std::string combiner = GetPredicateCombiner(instr.csetp.op); |
| 3145 | const std::string control_code = regs.GetControlCode(instr.csetp.cc); | 3322 | const std::string condition_code = regs.GetConditionCode(instr.csetp.cc); |
| 3146 | if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) { | 3323 | if (instr.csetp.pred3 != static_cast<u64>(Pred::UnusedIndex)) { |
| 3147 | SetPredicate(instr.csetp.pred3, | 3324 | SetPredicate(instr.csetp.pred3, |
| 3148 | '(' + control_code + ") " + combiner + " (" + pred + ')'); | 3325 | '(' + condition_code + ") " + combiner + " (" + pred + ')'); |
| 3149 | } | 3326 | } |
| 3150 | if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { | 3327 | if (instr.csetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) { |
| 3151 | SetPredicate(instr.csetp.pred0, | 3328 | SetPredicate(instr.csetp.pred0, |
| 3152 | "!(" + control_code + ") " + combiner + " (" + pred + ')'); | 3329 | "!(" + condition_code + ") " + combiner + " (" + pred + ')'); |
| 3153 | } | 3330 | } |
| 3154 | break; | 3331 | break; |
| 3155 | } | 3332 | } |
| @@ -3159,6 +3336,34 @@ private: | |||
| 3159 | } | 3336 | } |
| 3160 | break; | 3337 | break; |
| 3161 | } | 3338 | } |
| 3339 | case OpCode::Type::RegisterSetPredicate: { | ||
| 3340 | UNIMPLEMENTED_IF(instr.r2p.mode != Tegra::Shader::R2pMode::Pr); | ||
| 3341 | |||
| 3342 | const std::string apply_mask = [&]() { | ||
| 3343 | switch (opcode->get().GetId()) { | ||
| 3344 | case OpCode::Id::R2P_IMM: | ||
| 3345 | return std::to_string(instr.r2p.immediate_mask); | ||
| 3346 | default: | ||
| 3347 | UNREACHABLE(); | ||
| 3348 | } | ||
| 3349 | }(); | ||
| 3350 | const std::string mask = '(' + regs.GetRegisterAsInteger(instr.gpr8, 0, false) + | ||
| 3351 | " >> " + std::to_string(instr.r2p.byte) + ')'; | ||
| 3352 | |||
| 3353 | constexpr u64 programmable_preds = 7; | ||
| 3354 | for (u64 pred = 0; pred < programmable_preds; ++pred) { | ||
| 3355 | const auto shift = std::to_string(1 << pred); | ||
| 3356 | |||
| 3357 | shader.AddLine("if ((" + apply_mask + " & " + shift + ") != 0) {"); | ||
| 3358 | ++shader.scope; | ||
| 3359 | |||
| 3360 | SetPredicate(pred, '(' + mask + " & " + shift + ") != 0"); | ||
| 3361 | |||
| 3362 | --shader.scope; | ||
| 3363 | shader.AddLine('}'); | ||
| 3364 | } | ||
| 3365 | break; | ||
| 3366 | } | ||
| 3162 | case OpCode::Type::FloatSet: { | 3367 | case OpCode::Type::FloatSet: { |
| 3163 | const std::string op_a = GetOperandAbsNeg(regs.GetRegisterAsFloat(instr.gpr8), | 3368 | const std::string op_a = GetOperandAbsNeg(regs.GetRegisterAsFloat(instr.gpr8), |
| 3164 | instr.fset.abs_a != 0, instr.fset.neg_a != 0); | 3369 | instr.fset.abs_a != 0, instr.fset.neg_a != 0); |
| @@ -3196,6 +3401,10 @@ private: | |||
| 3196 | regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1, | 3401 | regs.SetRegisterToInteger(instr.gpr0, false, 0, predicate + " ? 0xFFFFFFFF : 0", 1, |
| 3197 | 1); | 3402 | 1); |
| 3198 | } | 3403 | } |
| 3404 | if (instr.generates_cc.Value() != 0) { | ||
| 3405 | regs.SetInternalFlag(InternalFlag::ZeroFlag, predicate); | ||
| 3406 | LOG_WARNING(HW_GPU, "FSET Condition Code is incomplete"); | ||
| 3407 | } | ||
| 3199 | break; | 3408 | break; |
| 3200 | } | 3409 | } |
| 3201 | case OpCode::Type::IntegerSet: { | 3410 | case OpCode::Type::IntegerSet: { |
| @@ -3280,7 +3489,8 @@ private: | |||
| 3280 | case OpCode::Type::Xmad: { | 3489 | case OpCode::Type::Xmad: { |
| 3281 | UNIMPLEMENTED_IF(instr.xmad.sign_a); | 3490 | UNIMPLEMENTED_IF(instr.xmad.sign_a); |
| 3282 | UNIMPLEMENTED_IF(instr.xmad.sign_b); | 3491 | UNIMPLEMENTED_IF(instr.xmad.sign_b); |
| 3283 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, "XMAD Generates an unhandled Control Code"); | 3492 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, |
| 3493 | "Condition codes generation in XMAD is not implemented"); | ||
| 3284 | 3494 | ||
| 3285 | std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)}; | 3495 | std::string op_a{regs.GetRegisterAsInteger(instr.gpr8, 0, instr.xmad.sign_a)}; |
| 3286 | std::string op_b; | 3496 | std::string op_b; |
| @@ -3372,9 +3582,9 @@ private: | |||
| 3372 | default: { | 3582 | default: { |
| 3373 | switch (opcode->get().GetId()) { | 3583 | switch (opcode->get().GetId()) { |
| 3374 | case OpCode::Id::EXIT: { | 3584 | case OpCode::Id::EXIT: { |
| 3375 | const Tegra::Shader::ControlCode cc = instr.flow_control_code; | 3585 | const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; |
| 3376 | UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T, | 3586 | UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, |
| 3377 | "EXIT Control Code used: {}", static_cast<u32>(cc)); | 3587 | "EXIT condition code used: {}", static_cast<u32>(cc)); |
| 3378 | 3588 | ||
| 3379 | if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { | 3589 | if (stage == Maxwell3D::Regs::ShaderStage::Fragment) { |
| 3380 | EmitFragmentOutputsWrite(); | 3590 | EmitFragmentOutputsWrite(); |
| @@ -3406,9 +3616,9 @@ private: | |||
| 3406 | case OpCode::Id::KIL: { | 3616 | case OpCode::Id::KIL: { |
| 3407 | UNIMPLEMENTED_IF(instr.flow.cond != Tegra::Shader::FlowCondition::Always); | 3617 | UNIMPLEMENTED_IF(instr.flow.cond != Tegra::Shader::FlowCondition::Always); |
| 3408 | 3618 | ||
| 3409 | const Tegra::Shader::ControlCode cc = instr.flow_control_code; | 3619 | const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; |
| 3410 | UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T, | 3620 | UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, |
| 3411 | "KIL Control Code used: {}", static_cast<u32>(cc)); | 3621 | "KIL condition code used: {}", static_cast<u32>(cc)); |
| 3412 | 3622 | ||
| 3413 | // Enclose "discard" in a conditional, so that GLSL compilation does not complain | 3623 | // Enclose "discard" in a conditional, so that GLSL compilation does not complain |
| 3414 | // about unexecuted instructions that may follow this. | 3624 | // about unexecuted instructions that may follow this. |
| @@ -3448,6 +3658,11 @@ private: | |||
| 3448 | regs.SetRegisterToInteger(instr.gpr0, false, 0, "0u", 1, 1); | 3658 | regs.SetRegisterToInteger(instr.gpr0, false, 0, "0u", 1, 1); |
| 3449 | break; | 3659 | break; |
| 3450 | } | 3660 | } |
| 3661 | case Tegra::Shader::SystemVariable::Ydirection: { | ||
| 3662 | // Config pack's third value is Y_NEGATE's state. | ||
| 3663 | regs.SetRegisterToFloat(instr.gpr0, 0, "uintBitsToFloat(config_pack[2])", 1, 1); | ||
| 3664 | break; | ||
| 3665 | } | ||
| 3451 | default: { | 3666 | default: { |
| 3452 | UNIMPLEMENTED_MSG("Unhandled system move: {}", | 3667 | UNIMPLEMENTED_MSG("Unhandled system move: {}", |
| 3453 | static_cast<u32>(instr.sys20.Value())); | 3668 | static_cast<u32>(instr.sys20.Value())); |
| @@ -3470,12 +3685,18 @@ private: | |||
| 3470 | UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, | 3685 | UNIMPLEMENTED_IF_MSG(instr.bra.constant_buffer != 0, |
| 3471 | "BRA with constant buffers are not implemented"); | 3686 | "BRA with constant buffers are not implemented"); |
| 3472 | 3687 | ||
| 3473 | const Tegra::Shader::ControlCode cc = instr.flow_control_code; | 3688 | const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; |
| 3474 | UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T, | ||
| 3475 | "BRA Control Code used: {}", static_cast<u32>(cc)); | ||
| 3476 | |||
| 3477 | const u32 target = offset + instr.bra.GetBranchTarget(); | 3689 | const u32 target = offset + instr.bra.GetBranchTarget(); |
| 3478 | shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); | 3690 | if (cc != Tegra::Shader::ConditionCode::T) { |
| 3691 | const std::string condition_code = regs.GetConditionCode(cc); | ||
| 3692 | shader.AddLine("if (" + condition_code + "){"); | ||
| 3693 | shader.scope++; | ||
| 3694 | shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); | ||
| 3695 | shader.scope--; | ||
| 3696 | shader.AddLine('}'); | ||
| 3697 | } else { | ||
| 3698 | shader.AddLine("{ jmp_to = " + std::to_string(target) + "u; break; }"); | ||
| 3699 | } | ||
| 3479 | break; | 3700 | break; |
| 3480 | } | 3701 | } |
| 3481 | case OpCode::Id::IPA: { | 3702 | case OpCode::Id::IPA: { |
| @@ -3515,9 +3736,9 @@ private: | |||
| 3515 | break; | 3736 | break; |
| 3516 | } | 3737 | } |
| 3517 | case OpCode::Id::SYNC: { | 3738 | case OpCode::Id::SYNC: { |
| 3518 | const Tegra::Shader::ControlCode cc = instr.flow_control_code; | 3739 | const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; |
| 3519 | UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ControlCode::T, | 3740 | UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, |
| 3520 | "SYNC Control Code used: {}", static_cast<u32>(cc)); | 3741 | "SYNC condition code used: {}", static_cast<u32>(cc)); |
| 3521 | 3742 | ||
| 3522 | // The SYNC opcode jumps to the address previously set by the SSY opcode | 3743 | // The SYNC opcode jumps to the address previously set by the SSY opcode |
| 3523 | EmitPopFromFlowStack(); | 3744 | EmitPopFromFlowStack(); |
| @@ -3525,10 +3746,10 @@ private: | |||
| 3525 | } | 3746 | } |
| 3526 | case OpCode::Id::BRK: { | 3747 | case OpCode::Id::BRK: { |
| 3527 | // The BRK opcode jumps to the address previously set by the PBK opcode | 3748 | // The BRK opcode jumps to the address previously set by the PBK opcode |
| 3528 | const Tegra::Shader::ControlCode cc = instr.flow_control_code; | 3749 | const Tegra::Shader::ConditionCode cc = instr.flow_condition_code; |
| 3529 | if (cc != Tegra::Shader::ControlCode::T) { | 3750 | UNIMPLEMENTED_IF_MSG(cc != Tegra::Shader::ConditionCode::T, |
| 3530 | UNIMPLEMENTED_MSG("BRK Control Code used: {}", static_cast<u32>(cc)); | 3751 | "BRK condition code used: {}", static_cast<u32>(cc)); |
| 3531 | } | 3752 | |
| 3532 | EmitPopFromFlowStack(); | 3753 | EmitPopFromFlowStack(); |
| 3533 | break; | 3754 | break; |
| 3534 | } | 3755 | } |
| @@ -3539,6 +3760,9 @@ private: | |||
| 3539 | break; | 3760 | break; |
| 3540 | } | 3761 | } |
| 3541 | case OpCode::Id::VMAD: { | 3762 | case OpCode::Id::VMAD: { |
| 3763 | UNIMPLEMENTED_IF_MSG(instr.generates_cc, | ||
| 3764 | "Condition codes generation in VMAD is not implemented"); | ||
| 3765 | |||
| 3542 | const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1; | 3766 | const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1; |
| 3543 | const std::string op_a = GetVideoOperandA(instr); | 3767 | const std::string op_a = GetVideoOperandA(instr); |
| 3544 | const std::string op_b = GetVideoOperandB(instr); | 3768 | const std::string op_b = GetVideoOperandB(instr); |
| @@ -3558,10 +3782,6 @@ private: | |||
| 3558 | regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1, | 3782 | regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1, |
| 3559 | instr.vmad.saturate == 1, 0, Register::Size::Word, | 3783 | instr.vmad.saturate == 1, 0, Register::Size::Word, |
| 3560 | instr.vmad.cc); | 3784 | instr.vmad.cc); |
| 3561 | if (instr.generates_cc) { | ||
| 3562 | UNIMPLEMENTED_MSG("VMAD Generates an unhandled Control Code"); | ||
| 3563 | } | ||
| 3564 | |||
| 3565 | break; | 3785 | break; |
| 3566 | } | 3786 | } |
| 3567 | case OpCode::Id::VSETP: { | 3787 | case OpCode::Id::VSETP: { |
| @@ -3713,6 +3933,7 @@ private: | |||
| 3713 | Maxwell3D::Regs::ShaderStage stage; | 3933 | Maxwell3D::Regs::ShaderStage stage; |
| 3714 | const std::string& suffix; | 3934 | const std::string& suffix; |
| 3715 | u64 local_memory_size; | 3935 | u64 local_memory_size; |
| 3936 | std::size_t shader_length; | ||
| 3716 | 3937 | ||
| 3717 | ShaderWriter shader; | 3938 | ShaderWriter shader; |
| 3718 | ShaderWriter declarations; | 3939 | ShaderWriter declarations; |
| @@ -3731,9 +3952,10 @@ std::optional<ProgramResult> DecompileProgram(const ProgramCode& program_code, u | |||
| 3731 | Maxwell3D::Regs::ShaderStage stage, | 3952 | Maxwell3D::Regs::ShaderStage stage, |
| 3732 | const std::string& suffix) { | 3953 | const std::string& suffix) { |
| 3733 | try { | 3954 | try { |
| 3734 | const auto subroutines = | 3955 | ControlFlowAnalyzer analyzer(program_code, main_offset, suffix); |
| 3735 | ControlFlowAnalyzer(program_code, main_offset, suffix).GetSubroutines(); | 3956 | const auto subroutines = analyzer.GetSubroutines(); |
| 3736 | GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix); | 3957 | GLSLGenerator generator(subroutines, program_code, main_offset, stage, suffix, |
| 3958 | analyzer.GetShaderLength()); | ||
| 3737 | return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; | 3959 | return ProgramResult{generator.GetShaderCode(), generator.GetEntries()}; |
| 3738 | } catch (const DecompileFail& exception) { | 3960 | } catch (const DecompileFail& exception) { |
| 3739 | LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what()); | 3961 | LOG_ERROR(HW_GPU, "Shader decompilation failed: {}", exception.what()); |
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp index eea090e52..23ed91e27 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.cpp +++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp | |||
| @@ -24,8 +24,7 @@ layout (location = 0) out vec4 position; | |||
| 24 | 24 | ||
| 25 | layout(std140) uniform vs_config { | 25 | layout(std140) uniform vs_config { |
| 26 | vec4 viewport_flip; | 26 | vec4 viewport_flip; |
| 27 | uvec4 instance_id; | 27 | uvec4 config_pack; // instance_id, flip_stage, y_direction, padding |
| 28 | uvec4 flip_stage; | ||
| 29 | uvec4 alpha_test; | 28 | uvec4 alpha_test; |
| 30 | }; | 29 | }; |
| 31 | )"; | 30 | )"; |
| @@ -63,7 +62,8 @@ void main() { | |||
| 63 | out += R"( | 62 | out += R"( |
| 64 | 63 | ||
| 65 | // Check if the flip stage is VertexB | 64 | // Check if the flip stage is VertexB |
| 66 | if (flip_stage[0] == 1) { | 65 | // Config pack's second value is flip_stage |
| 66 | if (config_pack[1] == 1) { | ||
| 67 | // Viewport can be flipped, which is unsupported by glViewport | 67 | // Viewport can be flipped, which is unsupported by glViewport |
| 68 | position.xy *= viewport_flip.xy; | 68 | position.xy *= viewport_flip.xy; |
| 69 | } | 69 | } |
| @@ -71,7 +71,7 @@ void main() { | |||
| 71 | 71 | ||
| 72 | // TODO(bunnei): This is likely a hack, position.w should be interpolated as 1.0 | 72 | // TODO(bunnei): This is likely a hack, position.w should be interpolated as 1.0 |
| 73 | // For now, this is here to bring order in lieu of proper emulation | 73 | // For now, this is here to bring order in lieu of proper emulation |
| 74 | if (flip_stage[0] == 1) { | 74 | if (config_pack[1] == 1) { |
| 75 | position.w = 1.0; | 75 | position.w = 1.0; |
| 76 | } | 76 | } |
| 77 | } | 77 | } |
| @@ -101,8 +101,7 @@ layout (location = 0) out vec4 position; | |||
| 101 | 101 | ||
| 102 | layout (std140) uniform gs_config { | 102 | layout (std140) uniform gs_config { |
| 103 | vec4 viewport_flip; | 103 | vec4 viewport_flip; |
| 104 | uvec4 instance_id; | 104 | uvec4 config_pack; // instance_id, flip_stage, y_direction, padding |
| 105 | uvec4 flip_stage; | ||
| 106 | uvec4 alpha_test; | 105 | uvec4 alpha_test; |
| 107 | }; | 106 | }; |
| 108 | 107 | ||
| @@ -139,8 +138,7 @@ layout (location = 0) in vec4 position; | |||
| 139 | 138 | ||
| 140 | layout (std140) uniform fs_config { | 139 | layout (std140) uniform fs_config { |
| 141 | vec4 viewport_flip; | 140 | vec4 viewport_flip; |
| 142 | uvec4 instance_id; | 141 | uvec4 config_pack; // instance_id, flip_stage, y_direction, padding |
| 143 | uvec4 flip_stage; | ||
| 144 | uvec4 alpha_test; | 142 | uvec4 alpha_test; |
| 145 | }; | 143 | }; |
| 146 | 144 | ||
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.h b/src/video_core/renderer_opengl/gl_shader_gen.h index 520b9d4e3..b425d98ae 100644 --- a/src/video_core/renderer_opengl/gl_shader_gen.h +++ b/src/video_core/renderer_opengl/gl_shader_gen.h | |||
| @@ -163,6 +163,7 @@ private: | |||
| 163 | struct ShaderEntries { | 163 | struct ShaderEntries { |
| 164 | std::vector<ConstBufferEntry> const_buffer_entries; | 164 | std::vector<ConstBufferEntry> const_buffer_entries; |
| 165 | std::vector<SamplerEntry> texture_samplers; | 165 | std::vector<SamplerEntry> texture_samplers; |
| 166 | std::size_t shader_length; | ||
| 166 | }; | 167 | }; |
| 167 | 168 | ||
| 168 | using ProgramResult = std::pair<std::string, ShaderEntries>; | 169 | using ProgramResult = std::pair<std::string, ShaderEntries>; |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp index 8b8869ecb..6a30c28d2 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.cpp +++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp | |||
| @@ -27,16 +27,18 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh | |||
| 27 | alpha_test.func = func; | 27 | alpha_test.func = func; |
| 28 | alpha_test.ref = regs.alpha_test_ref; | 28 | alpha_test.ref = regs.alpha_test_ref; |
| 29 | 29 | ||
| 30 | // We only assign the instance to the first component of the vector, the rest is just padding. | 30 | instance_id = state.current_instance; |
| 31 | instance_id[0] = state.current_instance; | ||
| 32 | 31 | ||
| 33 | // Assign in which stage the position has to be flipped | 32 | // Assign in which stage the position has to be flipped |
| 34 | // (the last stage before the fragment shader). | 33 | // (the last stage before the fragment shader). |
| 35 | if (gpu.regs.shader_config[static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry)].enable) { | 34 | if (gpu.regs.shader_config[static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry)].enable) { |
| 36 | flip_stage[0] = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry); | 35 | flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::Geometry); |
| 37 | } else { | 36 | } else { |
| 38 | flip_stage[0] = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB); | 37 | flip_stage = static_cast<u32>(Maxwell3D::Regs::ShaderProgram::VertexB); |
| 39 | } | 38 | } |
| 39 | |||
| 40 | // Y_NEGATE controls what value S2R returns for the Y_DIRECTION system value. | ||
| 41 | y_direction = regs.screen_y_control.y_negate == 0 ? 1.f : -1.f; | ||
| 40 | } | 42 | } |
| 41 | 43 | ||
| 42 | } // namespace OpenGL::GLShader | 44 | } // namespace OpenGL::GLShader |
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h index 9a5d7e289..b757f5f44 100644 --- a/src/video_core/renderer_opengl/gl_shader_manager.h +++ b/src/video_core/renderer_opengl/gl_shader_manager.h | |||
| @@ -21,8 +21,11 @@ using Tegra::Engines::Maxwell3D; | |||
| 21 | struct MaxwellUniformData { | 21 | struct MaxwellUniformData { |
| 22 | void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage); | 22 | void SetFromRegs(const Maxwell3D::State::ShaderStageInfo& shader_stage); |
| 23 | alignas(16) GLvec4 viewport_flip; | 23 | alignas(16) GLvec4 viewport_flip; |
| 24 | alignas(16) GLuvec4 instance_id; | 24 | struct alignas(16) { |
| 25 | alignas(16) GLuvec4 flip_stage; | 25 | GLuint instance_id; |
| 26 | GLuint flip_stage; | ||
| 27 | GLfloat y_direction; | ||
| 28 | }; | ||
| 26 | struct alignas(16) { | 29 | struct alignas(16) { |
| 27 | GLuint enabled; | 30 | GLuint enabled; |
| 28 | GLuint func; | 31 | GLuint func; |
| @@ -30,7 +33,7 @@ struct MaxwellUniformData { | |||
| 30 | GLuint padding; | 33 | GLuint padding; |
| 31 | } alpha_test; | 34 | } alpha_test; |
| 32 | }; | 35 | }; |
| 33 | static_assert(sizeof(MaxwellUniformData) == 64, "MaxwellUniformData structure size is incorrect"); | 36 | static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect"); |
| 34 | static_assert(sizeof(MaxwellUniformData) < 16384, | 37 | static_assert(sizeof(MaxwellUniformData) < 16384, |
| 35 | "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); | 38 | "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); |
| 36 | 39 | ||
diff --git a/src/video_core/renderer_opengl/gl_state.cpp b/src/video_core/renderer_opengl/gl_state.cpp index d9910c6e8..dc0a5ed5e 100644 --- a/src/video_core/renderer_opengl/gl_state.cpp +++ b/src/video_core/renderer_opengl/gl_state.cpp | |||
| @@ -92,6 +92,14 @@ OpenGLState::OpenGLState() { | |||
| 92 | 92 | ||
| 93 | point.size = 1; | 93 | point.size = 1; |
| 94 | fragment_color_clamp.enabled = false; | 94 | fragment_color_clamp.enabled = false; |
| 95 | depth_clamp.far_plane = false; | ||
| 96 | depth_clamp.near_plane = false; | ||
| 97 | polygon_offset.fill_enable = false; | ||
| 98 | polygon_offset.line_enable = false; | ||
| 99 | polygon_offset.point_enable = false; | ||
| 100 | polygon_offset.factor = 0.0f; | ||
| 101 | polygon_offset.units = 0.0f; | ||
| 102 | polygon_offset.clamp = 0.0f; | ||
| 95 | } | 103 | } |
| 96 | 104 | ||
| 97 | void OpenGLState::ApplyDefaultState() { | 105 | void OpenGLState::ApplyDefaultState() { |
| @@ -140,7 +148,7 @@ void OpenGLState::ApplyCulling() const { | |||
| 140 | } | 148 | } |
| 141 | 149 | ||
| 142 | void OpenGLState::ApplyColorMask() const { | 150 | void OpenGLState::ApplyColorMask() const { |
| 143 | if (GLAD_GL_ARB_viewport_array && independant_blend.enabled) { | 151 | if (independant_blend.enabled) { |
| 144 | for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { | 152 | for (size_t i = 0; i < Tegra::Engines::Maxwell3D::Regs::NumRenderTargets; i++) { |
| 145 | const auto& updated = color_mask[i]; | 153 | const auto& updated = color_mask[i]; |
| 146 | const auto& current = cur_state.color_mask[i]; | 154 | const auto& current = cur_state.color_mask[i]; |
| @@ -233,16 +241,40 @@ void OpenGLState::ApplyStencilTest() const { | |||
| 233 | config_stencil(GL_BACK, stencil.back, cur_state.stencil.back); | 241 | config_stencil(GL_BACK, stencil.back, cur_state.stencil.back); |
| 234 | } | 242 | } |
| 235 | } | 243 | } |
| 244 | // Viewport does not affects glClearBuffer so emulate viewport using scissor test | ||
| 245 | void OpenGLState::EmulateViewportWithScissor() { | ||
| 246 | auto& current = viewports[0]; | ||
| 247 | if (current.scissor.enabled) { | ||
| 248 | const GLint left = std::max(current.x, current.scissor.x); | ||
| 249 | const GLint right = | ||
| 250 | std::max(current.x + current.width, current.scissor.x + current.scissor.width); | ||
| 251 | const GLint bottom = std::max(current.y, current.scissor.y); | ||
| 252 | const GLint top = | ||
| 253 | std::max(current.y + current.height, current.scissor.y + current.scissor.height); | ||
| 254 | current.scissor.x = std::max(left, 0); | ||
| 255 | current.scissor.y = std::max(bottom, 0); | ||
| 256 | current.scissor.width = std::max(right - left, 0); | ||
| 257 | current.scissor.height = std::max(top - bottom, 0); | ||
| 258 | } else { | ||
| 259 | current.scissor.enabled = true; | ||
| 260 | current.scissor.x = current.x; | ||
| 261 | current.scissor.y = current.y; | ||
| 262 | current.scissor.width = current.width; | ||
| 263 | current.scissor.height = current.height; | ||
| 264 | } | ||
| 265 | } | ||
| 236 | 266 | ||
| 237 | void OpenGLState::ApplyViewport() const { | 267 | void OpenGLState::ApplyViewport() const { |
| 238 | if (GLAD_GL_ARB_viewport_array && geometry_shaders.enabled) { | 268 | if (geometry_shaders.enabled) { |
| 239 | for (GLuint i = 0; i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumViewports); | 269 | for (GLuint i = 0; i < static_cast<GLuint>(Tegra::Engines::Maxwell3D::Regs::NumViewports); |
| 240 | i++) { | 270 | i++) { |
| 241 | const auto& current = cur_state.viewports[i]; | 271 | const auto& current = cur_state.viewports[i]; |
| 242 | const auto& updated = viewports[i]; | 272 | const auto& updated = viewports[i]; |
| 243 | if (updated.x != current.x || updated.y != current.y || | 273 | if (updated.x != current.x || updated.y != current.y || |
| 244 | updated.width != current.width || updated.height != current.height) { | 274 | updated.width != current.width || updated.height != current.height) { |
| 245 | glViewportIndexedf(i, updated.x, updated.y, updated.width, updated.height); | 275 | glViewportIndexedf( |
| 276 | i, static_cast<GLfloat>(updated.x), static_cast<GLfloat>(updated.y), | ||
| 277 | static_cast<GLfloat>(updated.width), static_cast<GLfloat>(updated.height)); | ||
| 246 | } | 278 | } |
| 247 | if (updated.depth_range_near != current.depth_range_near || | 279 | if (updated.depth_range_near != current.depth_range_near || |
| 248 | updated.depth_range_far != current.depth_range_far) { | 280 | updated.depth_range_far != current.depth_range_far) { |
| @@ -270,8 +302,7 @@ void OpenGLState::ApplyViewport() const { | |||
| 270 | const auto& updated = viewports[0]; | 302 | const auto& updated = viewports[0]; |
| 271 | if (updated.x != current.x || updated.y != current.y || updated.width != current.width || | 303 | if (updated.x != current.x || updated.y != current.y || updated.width != current.width || |
| 272 | updated.height != current.height) { | 304 | updated.height != current.height) { |
| 273 | glViewport(static_cast<GLint>(updated.x), static_cast<GLint>(updated.y), | 305 | glViewport(updated.x, updated.y, updated.width, updated.height); |
| 274 | static_cast<GLsizei>(updated.width), static_cast<GLsizei>(updated.height)); | ||
| 275 | } | 306 | } |
| 276 | if (updated.depth_range_near != current.depth_range_near || | 307 | if (updated.depth_range_near != current.depth_range_near || |
| 277 | updated.depth_range_far != current.depth_range_far) { | 308 | updated.depth_range_far != current.depth_range_far) { |
| @@ -339,14 +370,14 @@ void OpenGLState::ApplyTargetBlending(std::size_t target, bool force) const { | |||
| 339 | if (blend_changed || updated.src_rgb_func != current.src_rgb_func || | 370 | if (blend_changed || updated.src_rgb_func != current.src_rgb_func || |
| 340 | updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func || | 371 | updated.dst_rgb_func != current.dst_rgb_func || updated.src_a_func != current.src_a_func || |
| 341 | updated.dst_a_func != current.dst_a_func) { | 372 | updated.dst_a_func != current.dst_a_func) { |
| 342 | glBlendFuncSeparateiARB(static_cast<GLuint>(target), updated.src_rgb_func, | 373 | glBlendFuncSeparatei(static_cast<GLuint>(target), updated.src_rgb_func, |
| 343 | updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); | 374 | updated.dst_rgb_func, updated.src_a_func, updated.dst_a_func); |
| 344 | } | 375 | } |
| 345 | 376 | ||
| 346 | if (blend_changed || updated.rgb_equation != current.rgb_equation || | 377 | if (blend_changed || updated.rgb_equation != current.rgb_equation || |
| 347 | updated.a_equation != current.a_equation) { | 378 | updated.a_equation != current.a_equation) { |
| 348 | glBlendEquationSeparateiARB(static_cast<GLuint>(target), updated.rgb_equation, | 379 | glBlendEquationSeparatei(static_cast<GLuint>(target), updated.rgb_equation, |
| 349 | updated.a_equation); | 380 | updated.a_equation); |
| 350 | } | 381 | } |
| 351 | } | 382 | } |
| 352 | 383 | ||
| @@ -383,6 +414,55 @@ void OpenGLState::ApplyLogicOp() const { | |||
| 383 | } | 414 | } |
| 384 | } | 415 | } |
| 385 | 416 | ||
| 417 | void OpenGLState::ApplyPolygonOffset() const { | ||
| 418 | |||
| 419 | const bool fill_enable_changed = | ||
| 420 | polygon_offset.fill_enable != cur_state.polygon_offset.fill_enable; | ||
| 421 | const bool line_enable_changed = | ||
| 422 | polygon_offset.line_enable != cur_state.polygon_offset.line_enable; | ||
| 423 | const bool point_enable_changed = | ||
| 424 | polygon_offset.point_enable != cur_state.polygon_offset.point_enable; | ||
| 425 | const bool factor_changed = polygon_offset.factor != cur_state.polygon_offset.factor; | ||
| 426 | const bool units_changed = polygon_offset.units != cur_state.polygon_offset.units; | ||
| 427 | const bool clamp_changed = polygon_offset.clamp != cur_state.polygon_offset.clamp; | ||
| 428 | |||
| 429 | if (fill_enable_changed) { | ||
| 430 | if (polygon_offset.fill_enable) { | ||
| 431 | glEnable(GL_POLYGON_OFFSET_FILL); | ||
| 432 | } else { | ||
| 433 | glDisable(GL_POLYGON_OFFSET_FILL); | ||
| 434 | } | ||
| 435 | } | ||
| 436 | |||
| 437 | if (line_enable_changed) { | ||
| 438 | if (polygon_offset.line_enable) { | ||
| 439 | glEnable(GL_POLYGON_OFFSET_LINE); | ||
| 440 | } else { | ||
| 441 | glDisable(GL_POLYGON_OFFSET_LINE); | ||
| 442 | } | ||
| 443 | } | ||
| 444 | |||
| 445 | if (point_enable_changed) { | ||
| 446 | if (polygon_offset.point_enable) { | ||
| 447 | glEnable(GL_POLYGON_OFFSET_POINT); | ||
| 448 | } else { | ||
| 449 | glDisable(GL_POLYGON_OFFSET_POINT); | ||
| 450 | } | ||
| 451 | } | ||
| 452 | |||
| 453 | if ((polygon_offset.fill_enable || polygon_offset.line_enable || polygon_offset.point_enable) && | ||
| 454 | (factor_changed || units_changed || clamp_changed)) { | ||
| 455 | |||
| 456 | if (GLAD_GL_EXT_polygon_offset_clamp && polygon_offset.clamp != 0) { | ||
| 457 | glPolygonOffsetClamp(polygon_offset.factor, polygon_offset.units, polygon_offset.clamp); | ||
| 458 | } else { | ||
| 459 | glPolygonOffset(polygon_offset.factor, polygon_offset.units); | ||
| 460 | UNIMPLEMENTED_IF_MSG(polygon_offset.clamp != 0, | ||
| 461 | "Unimplemented Depth polygon offset clamp."); | ||
| 462 | } | ||
| 463 | } | ||
| 464 | } | ||
| 465 | |||
| 386 | void OpenGLState::ApplyTextures() const { | 466 | void OpenGLState::ApplyTextures() const { |
| 387 | for (std::size_t i = 0; i < std::size(texture_units); ++i) { | 467 | for (std::size_t i = 0; i < std::size(texture_units); ++i) { |
| 388 | const auto& texture_unit = texture_units[i]; | 468 | const auto& texture_unit = texture_units[i]; |
| @@ -446,6 +526,21 @@ void OpenGLState::ApplyVertexBufferState() const { | |||
| 446 | } | 526 | } |
| 447 | } | 527 | } |
| 448 | 528 | ||
| 529 | void OpenGLState::ApplyDepthClamp() const { | ||
| 530 | if (depth_clamp.far_plane == cur_state.depth_clamp.far_plane && | ||
| 531 | depth_clamp.near_plane == cur_state.depth_clamp.near_plane) { | ||
| 532 | return; | ||
| 533 | } | ||
| 534 | if (depth_clamp.far_plane != depth_clamp.near_plane) { | ||
| 535 | UNIMPLEMENTED_MSG("Unimplemented Depth Clamp Separation!"); | ||
| 536 | } | ||
| 537 | if (depth_clamp.far_plane || depth_clamp.near_plane) { | ||
| 538 | glEnable(GL_DEPTH_CLAMP); | ||
| 539 | } else { | ||
| 540 | glDisable(GL_DEPTH_CLAMP); | ||
| 541 | } | ||
| 542 | } | ||
| 543 | |||
| 449 | void OpenGLState::Apply() const { | 544 | void OpenGLState::Apply() const { |
| 450 | ApplyFramebufferState(); | 545 | ApplyFramebufferState(); |
| 451 | ApplyVertexBufferState(); | 546 | ApplyVertexBufferState(); |
| @@ -477,11 +572,9 @@ void OpenGLState::Apply() const { | |||
| 477 | if (point.size != cur_state.point.size) { | 572 | if (point.size != cur_state.point.size) { |
| 478 | glPointSize(point.size); | 573 | glPointSize(point.size); |
| 479 | } | 574 | } |
| 480 | if (GLAD_GL_ARB_color_buffer_float) { | 575 | if (fragment_color_clamp.enabled != cur_state.fragment_color_clamp.enabled) { |
| 481 | if (fragment_color_clamp.enabled != cur_state.fragment_color_clamp.enabled) { | 576 | glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, |
| 482 | glClampColor(GL_CLAMP_FRAGMENT_COLOR_ARB, | 577 | fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE); |
| 483 | fragment_color_clamp.enabled ? GL_TRUE : GL_FALSE); | ||
| 484 | } | ||
| 485 | } | 578 | } |
| 486 | if (multisample_control.alpha_to_coverage != cur_state.multisample_control.alpha_to_coverage) { | 579 | if (multisample_control.alpha_to_coverage != cur_state.multisample_control.alpha_to_coverage) { |
| 487 | if (multisample_control.alpha_to_coverage) { | 580 | if (multisample_control.alpha_to_coverage) { |
| @@ -497,7 +590,7 @@ void OpenGLState::Apply() const { | |||
| 497 | glDisable(GL_SAMPLE_ALPHA_TO_ONE); | 590 | glDisable(GL_SAMPLE_ALPHA_TO_ONE); |
| 498 | } | 591 | } |
| 499 | } | 592 | } |
| 500 | 593 | ApplyDepthClamp(); | |
| 501 | ApplyColorMask(); | 594 | ApplyColorMask(); |
| 502 | ApplyViewport(); | 595 | ApplyViewport(); |
| 503 | ApplyStencilTest(); | 596 | ApplyStencilTest(); |
| @@ -509,6 +602,7 @@ void OpenGLState::Apply() const { | |||
| 509 | ApplyLogicOp(); | 602 | ApplyLogicOp(); |
| 510 | ApplyTextures(); | 603 | ApplyTextures(); |
| 511 | ApplySamplers(); | 604 | ApplySamplers(); |
| 605 | ApplyPolygonOffset(); | ||
| 512 | cur_state = *this; | 606 | cur_state = *this; |
| 513 | } | 607 | } |
| 514 | 608 | ||
diff --git a/src/video_core/renderer_opengl/gl_state.h b/src/video_core/renderer_opengl/gl_state.h index bdc743b0f..439bfbc98 100644 --- a/src/video_core/renderer_opengl/gl_state.h +++ b/src/video_core/renderer_opengl/gl_state.h | |||
| @@ -49,6 +49,11 @@ public: | |||
| 49 | } fragment_color_clamp; | 49 | } fragment_color_clamp; |
| 50 | 50 | ||
| 51 | struct { | 51 | struct { |
| 52 | bool far_plane; | ||
| 53 | bool near_plane; | ||
| 54 | } depth_clamp; // GL_DEPTH_CLAMP | ||
| 55 | |||
| 56 | struct { | ||
| 52 | bool enabled; // viewports arrays are only supported when geometry shaders are enabled. | 57 | bool enabled; // viewports arrays are only supported when geometry shaders are enabled. |
| 53 | } geometry_shaders; | 58 | } geometry_shaders; |
| 54 | 59 | ||
| @@ -156,10 +161,10 @@ public: | |||
| 156 | } draw; | 161 | } draw; |
| 157 | 162 | ||
| 158 | struct viewport { | 163 | struct viewport { |
| 159 | GLfloat x; | 164 | GLint x; |
| 160 | GLfloat y; | 165 | GLint y; |
| 161 | GLfloat width; | 166 | GLint width; |
| 162 | GLfloat height; | 167 | GLint height; |
| 163 | GLfloat depth_range_near; // GL_DEPTH_RANGE | 168 | GLfloat depth_range_near; // GL_DEPTH_RANGE |
| 164 | GLfloat depth_range_far; // GL_DEPTH_RANGE | 169 | GLfloat depth_range_far; // GL_DEPTH_RANGE |
| 165 | struct { | 170 | struct { |
| @@ -176,7 +181,16 @@ public: | |||
| 176 | float size; // GL_POINT_SIZE | 181 | float size; // GL_POINT_SIZE |
| 177 | } point; | 182 | } point; |
| 178 | 183 | ||
| 179 | std::array<bool, 2> clip_distance; // GL_CLIP_DISTANCE | 184 | struct { |
| 185 | bool point_enable; | ||
| 186 | bool line_enable; | ||
| 187 | bool fill_enable; | ||
| 188 | GLfloat units; | ||
| 189 | GLfloat factor; | ||
| 190 | GLfloat clamp; | ||
| 191 | } polygon_offset; | ||
| 192 | |||
| 193 | std::array<bool, 8> clip_distance; // GL_CLIP_DISTANCE | ||
| 180 | 194 | ||
| 181 | OpenGLState(); | 195 | OpenGLState(); |
| 182 | 196 | ||
| @@ -206,6 +220,7 @@ public: | |||
| 206 | OpenGLState& ResetBuffer(GLuint handle); | 220 | OpenGLState& ResetBuffer(GLuint handle); |
| 207 | OpenGLState& ResetVertexArray(GLuint handle); | 221 | OpenGLState& ResetVertexArray(GLuint handle); |
| 208 | OpenGLState& ResetFramebuffer(GLuint handle); | 222 | OpenGLState& ResetFramebuffer(GLuint handle); |
| 223 | void EmulateViewportWithScissor(); | ||
| 209 | 224 | ||
| 210 | private: | 225 | private: |
| 211 | static OpenGLState cur_state; | 226 | static OpenGLState cur_state; |
| @@ -225,6 +240,8 @@ private: | |||
| 225 | void ApplyLogicOp() const; | 240 | void ApplyLogicOp() const; |
| 226 | void ApplyTextures() const; | 241 | void ApplyTextures() const; |
| 227 | void ApplySamplers() const; | 242 | void ApplySamplers() const; |
| 243 | void ApplyDepthClamp() const; | ||
| 244 | void ApplyPolygonOffset() const; | ||
| 228 | }; | 245 | }; |
| 229 | 246 | ||
| 230 | } // namespace OpenGL | 247 | } // namespace OpenGL |
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h index 065b3929c..a8833c06e 100644 --- a/src/video_core/renderer_opengl/maxwell_to_gl.h +++ b/src/video_core/renderer_opengl/maxwell_to_gl.h | |||
| @@ -218,14 +218,19 @@ inline GLenum DepthCompareFunc(Tegra::Texture::DepthCompareFunc func) { | |||
| 218 | inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { | 218 | inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { |
| 219 | switch (equation) { | 219 | switch (equation) { |
| 220 | case Maxwell::Blend::Equation::Add: | 220 | case Maxwell::Blend::Equation::Add: |
| 221 | case Maxwell::Blend::Equation::AddGL: | ||
| 221 | return GL_FUNC_ADD; | 222 | return GL_FUNC_ADD; |
| 222 | case Maxwell::Blend::Equation::Subtract: | 223 | case Maxwell::Blend::Equation::Subtract: |
| 224 | case Maxwell::Blend::Equation::SubtractGL: | ||
| 223 | return GL_FUNC_SUBTRACT; | 225 | return GL_FUNC_SUBTRACT; |
| 224 | case Maxwell::Blend::Equation::ReverseSubtract: | 226 | case Maxwell::Blend::Equation::ReverseSubtract: |
| 227 | case Maxwell::Blend::Equation::ReverseSubtractGL: | ||
| 225 | return GL_FUNC_REVERSE_SUBTRACT; | 228 | return GL_FUNC_REVERSE_SUBTRACT; |
| 226 | case Maxwell::Blend::Equation::Min: | 229 | case Maxwell::Blend::Equation::Min: |
| 230 | case Maxwell::Blend::Equation::MinGL: | ||
| 227 | return GL_MIN; | 231 | return GL_MIN; |
| 228 | case Maxwell::Blend::Equation::Max: | 232 | case Maxwell::Blend::Equation::Max: |
| 233 | case Maxwell::Blend::Equation::MaxGL: | ||
| 229 | return GL_MAX; | 234 | return GL_MAX; |
| 230 | } | 235 | } |
| 231 | LOG_ERROR(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation)); | 236 | LOG_ERROR(Render_OpenGL, "Unimplemented blend equation={}", static_cast<u32>(equation)); |
diff --git a/src/video_core/renderer_opengl/renderer_opengl.cpp b/src/video_core/renderer_opengl/renderer_opengl.cpp index 27b5b8960..4fd0d66c5 100644 --- a/src/video_core/renderer_opengl/renderer_opengl.cpp +++ b/src/video_core/renderer_opengl/renderer_opengl.cpp | |||
| @@ -19,9 +19,9 @@ | |||
| 19 | #include "core/settings.h" | 19 | #include "core/settings.h" |
| 20 | #include "core/telemetry_session.h" | 20 | #include "core/telemetry_session.h" |
| 21 | #include "core/tracer/recorder.h" | 21 | #include "core/tracer/recorder.h" |
| 22 | #include "video_core/morton.h" | ||
| 22 | #include "video_core/renderer_opengl/gl_rasterizer.h" | 23 | #include "video_core/renderer_opengl/gl_rasterizer.h" |
| 23 | #include "video_core/renderer_opengl/renderer_opengl.h" | 24 | #include "video_core/renderer_opengl/renderer_opengl.h" |
| 24 | #include "video_core/utils.h" | ||
| 25 | 25 | ||
| 26 | namespace OpenGL { | 26 | namespace OpenGL { |
| 27 | 27 | ||
| @@ -490,7 +490,7 @@ bool RendererOpenGL::Init() { | |||
| 490 | Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model); | 490 | Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_Model", gpu_model); |
| 491 | Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version", gl_version); | 491 | Core::Telemetry().AddField(Telemetry::FieldType::UserSystem, "GPU_OpenGL_Version", gl_version); |
| 492 | 492 | ||
| 493 | if (!GLAD_GL_VERSION_3_3) { | 493 | if (!GLAD_GL_VERSION_4_3) { |
| 494 | return false; | 494 | return false; |
| 495 | } | 495 | } |
| 496 | 496 | ||
diff --git a/src/video_core/textures/decoders.cpp b/src/video_core/textures/decoders.cpp index 7eabd34f1..bbae9285f 100644 --- a/src/video_core/textures/decoders.cpp +++ b/src/video_core/textures/decoders.cpp | |||
| @@ -127,7 +127,8 @@ void FastProcessBlock(u8* const swizzled_data, u8* const unswizzled_data, const | |||
| 127 | template <bool fast> | 127 | template <bool fast> |
| 128 | void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool unswizzle, | 128 | void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool unswizzle, |
| 129 | const u32 width, const u32 height, const u32 depth, const u32 bytes_per_pixel, | 129 | const u32 width, const u32 height, const u32 depth, const u32 bytes_per_pixel, |
| 130 | const u32 out_bytes_per_pixel, const u32 block_height, const u32 block_depth) { | 130 | const u32 out_bytes_per_pixel, const u32 block_height, const u32 block_depth, |
| 131 | const u32 width_spacing) { | ||
| 131 | auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); }; | 132 | auto div_ceil = [](const u32 x, const u32 y) { return ((x + y - 1) / y); }; |
| 132 | const u32 stride_x = width * out_bytes_per_pixel; | 133 | const u32 stride_x = width * out_bytes_per_pixel; |
| 133 | const u32 layer_z = height * stride_x; | 134 | const u32 layer_z = height * stride_x; |
| @@ -137,7 +138,8 @@ void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool | |||
| 137 | const u32 block_x_elements = gob_elements_x; | 138 | const u32 block_x_elements = gob_elements_x; |
| 138 | const u32 block_y_elements = gob_elements_y * block_height; | 139 | const u32 block_y_elements = gob_elements_y * block_height; |
| 139 | const u32 block_z_elements = gob_elements_z * block_depth; | 140 | const u32 block_z_elements = gob_elements_z * block_depth; |
| 140 | const u32 blocks_on_x = div_ceil(width, block_x_elements); | 141 | const u32 aligned_width = Common::AlignUp(width, gob_elements_x * width_spacing); |
| 142 | const u32 blocks_on_x = div_ceil(aligned_width, block_x_elements); | ||
| 141 | const u32 blocks_on_y = div_ceil(height, block_y_elements); | 143 | const u32 blocks_on_y = div_ceil(height, block_y_elements); |
| 142 | const u32 blocks_on_z = div_ceil(depth, block_z_elements); | 144 | const u32 blocks_on_z = div_ceil(depth, block_z_elements); |
| 143 | const u32 xy_block_size = gob_size * block_height; | 145 | const u32 xy_block_size = gob_size * block_height; |
| @@ -169,13 +171,15 @@ void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool | |||
| 169 | 171 | ||
| 170 | void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel, | 172 | void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel, |
| 171 | u32 out_bytes_per_pixel, u8* const swizzled_data, u8* const unswizzled_data, | 173 | u32 out_bytes_per_pixel, u8* const swizzled_data, u8* const unswizzled_data, |
| 172 | bool unswizzle, u32 block_height, u32 block_depth) { | 174 | bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing) { |
| 173 | if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % fast_swizzle_align == 0) { | 175 | if (bytes_per_pixel % 3 != 0 && (width * bytes_per_pixel) % fast_swizzle_align == 0) { |
| 174 | SwizzledData<true>(swizzled_data, unswizzled_data, unswizzle, width, height, depth, | 176 | SwizzledData<true>(swizzled_data, unswizzled_data, unswizzle, width, height, depth, |
| 175 | bytes_per_pixel, out_bytes_per_pixel, block_height, block_depth); | 177 | bytes_per_pixel, out_bytes_per_pixel, block_height, block_depth, |
| 178 | width_spacing); | ||
| 176 | } else { | 179 | } else { |
| 177 | SwizzledData<false>(swizzled_data, unswizzled_data, unswizzle, width, height, depth, | 180 | SwizzledData<false>(swizzled_data, unswizzled_data, unswizzle, width, height, depth, |
| 178 | bytes_per_pixel, out_bytes_per_pixel, block_height, block_depth); | 181 | bytes_per_pixel, out_bytes_per_pixel, block_height, block_depth, |
| 182 | width_spacing); | ||
| 179 | } | 183 | } |
| 180 | } | 184 | } |
| 181 | 185 | ||
| @@ -228,19 +232,19 @@ u32 BytesPerPixel(TextureFormat format) { | |||
| 228 | 232 | ||
| 229 | void UnswizzleTexture(u8* const unswizzled_data, VAddr address, u32 tile_size_x, u32 tile_size_y, | 233 | void UnswizzleTexture(u8* const unswizzled_data, VAddr address, u32 tile_size_x, u32 tile_size_y, |
| 230 | u32 bytes_per_pixel, u32 width, u32 height, u32 depth, u32 block_height, | 234 | u32 bytes_per_pixel, u32 width, u32 height, u32 depth, u32 block_height, |
| 231 | u32 block_depth) { | 235 | u32 block_depth, u32 width_spacing) { |
| 232 | CopySwizzledData((width + tile_size_x - 1) / tile_size_x, | 236 | CopySwizzledData((width + tile_size_x - 1) / tile_size_x, |
| 233 | (height + tile_size_y - 1) / tile_size_y, depth, bytes_per_pixel, | 237 | (height + tile_size_y - 1) / tile_size_y, depth, bytes_per_pixel, |
| 234 | bytes_per_pixel, Memory::GetPointer(address), unswizzled_data, true, | 238 | bytes_per_pixel, Memory::GetPointer(address), unswizzled_data, true, |
| 235 | block_height, block_depth); | 239 | block_height, block_depth, width_spacing); |
| 236 | } | 240 | } |
| 237 | 241 | ||
| 238 | std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y, | 242 | std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y, |
| 239 | u32 bytes_per_pixel, u32 width, u32 height, u32 depth, | 243 | u32 bytes_per_pixel, u32 width, u32 height, u32 depth, |
| 240 | u32 block_height, u32 block_depth) { | 244 | u32 block_height, u32 block_depth, u32 width_spacing) { |
| 241 | std::vector<u8> unswizzled_data(width * height * depth * bytes_per_pixel); | 245 | std::vector<u8> unswizzled_data(width * height * depth * bytes_per_pixel); |
| 242 | UnswizzleTexture(unswizzled_data.data(), address, tile_size_x, tile_size_y, bytes_per_pixel, | 246 | UnswizzleTexture(unswizzled_data.data(), address, tile_size_x, tile_size_y, bytes_per_pixel, |
| 243 | width, height, depth, block_height, block_depth); | 247 | width, height, depth, block_height, block_depth, width_spacing); |
| 244 | return unswizzled_data; | 248 | return unswizzled_data; |
| 245 | } | 249 | } |
| 246 | 250 | ||
diff --git a/src/video_core/textures/decoders.h b/src/video_core/textures/decoders.h index f4ef7c73e..85b7e9f7b 100644 --- a/src/video_core/textures/decoders.h +++ b/src/video_core/textures/decoders.h | |||
| @@ -22,19 +22,20 @@ inline std::size_t GetGOBSize() { | |||
| 22 | void UnswizzleTexture(u8* unswizzled_data, VAddr address, u32 tile_size_x, u32 tile_size_y, | 22 | void UnswizzleTexture(u8* unswizzled_data, VAddr address, u32 tile_size_x, u32 tile_size_y, |
| 23 | u32 bytes_per_pixel, u32 width, u32 height, u32 depth, | 23 | u32 bytes_per_pixel, u32 width, u32 height, u32 depth, |
| 24 | u32 block_height = TICEntry::DefaultBlockHeight, | 24 | u32 block_height = TICEntry::DefaultBlockHeight, |
| 25 | u32 block_depth = TICEntry::DefaultBlockHeight); | 25 | u32 block_depth = TICEntry::DefaultBlockHeight, u32 width_spacing = 0); |
| 26 | /** | 26 | /** |
| 27 | * Unswizzles a swizzled texture without changing its format. | 27 | * Unswizzles a swizzled texture without changing its format. |
| 28 | */ | 28 | */ |
| 29 | std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y, | 29 | std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y, |
| 30 | u32 bytes_per_pixel, u32 width, u32 height, u32 depth, | 30 | u32 bytes_per_pixel, u32 width, u32 height, u32 depth, |
| 31 | u32 block_height = TICEntry::DefaultBlockHeight, | 31 | u32 block_height = TICEntry::DefaultBlockHeight, |
| 32 | u32 block_depth = TICEntry::DefaultBlockHeight); | 32 | u32 block_depth = TICEntry::DefaultBlockHeight, |
| 33 | u32 width_spacing = 0); | ||
| 33 | 34 | ||
| 34 | /// Copies texture data from a buffer and performs swizzling/unswizzling as necessary. | 35 | /// Copies texture data from a buffer and performs swizzling/unswizzling as necessary. |
| 35 | void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel, | 36 | void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel, |
| 36 | u32 out_bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, | 37 | u32 out_bytes_per_pixel, u8* swizzled_data, u8* unswizzled_data, |
| 37 | bool unswizzle, u32 block_height, u32 block_depth); | 38 | bool unswizzle, u32 block_height, u32 block_depth, u32 width_spacing); |
| 38 | 39 | ||
| 39 | /** | 40 | /** |
| 40 | * Decodes an unswizzled texture into a A8R8G8B8 texture. | 41 | * Decodes an unswizzled texture into a A8R8G8B8 texture. |
diff --git a/src/video_core/textures/texture.h b/src/video_core/textures/texture.h index ffa08f5c1..e7c78bee2 100644 --- a/src/video_core/textures/texture.h +++ b/src/video_core/textures/texture.h | |||
| @@ -166,6 +166,8 @@ struct TICEntry { | |||
| 166 | BitField<3, 3, u32> block_height; | 166 | BitField<3, 3, u32> block_height; |
| 167 | BitField<6, 3, u32> block_depth; | 167 | BitField<6, 3, u32> block_depth; |
| 168 | 168 | ||
| 169 | BitField<10, 3, u32> tile_width_spacing; | ||
| 170 | |||
| 169 | // High 16 bits of the pitch value | 171 | // High 16 bits of the pitch value |
| 170 | BitField<0, 16, u32> pitch_high; | 172 | BitField<0, 16, u32> pitch_high; |
| 171 | BitField<26, 1, u32> use_header_opt_control; | 173 | BitField<26, 1, u32> use_header_opt_control; |
diff --git a/src/video_core/utils.h b/src/video_core/utils.h deleted file mode 100644 index e0a14d48f..000000000 --- a/src/video_core/utils.h +++ /dev/null | |||
| @@ -1,164 +0,0 @@ | |||
| 1 | // Copyright 2014 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 "common/common_types.h" | ||
| 8 | |||
| 9 | namespace VideoCore { | ||
| 10 | |||
| 11 | // 8x8 Z-Order coordinate from 2D coordinates | ||
| 12 | static inline u32 MortonInterleave(u32 x, u32 y) { | ||
| 13 | static const u32 xlut[] = {0x00, 0x01, 0x04, 0x05, 0x10, 0x11, 0x14, 0x15}; | ||
| 14 | static const u32 ylut[] = {0x00, 0x02, 0x08, 0x0a, 0x20, 0x22, 0x28, 0x2a}; | ||
| 15 | return xlut[x % 8] + ylut[y % 8]; | ||
| 16 | } | ||
| 17 | |||
| 18 | /** | ||
| 19 | * Calculates the offset of the position of the pixel in Morton order | ||
| 20 | */ | ||
| 21 | static inline u32 GetMortonOffset(u32 x, u32 y, u32 bytes_per_pixel) { | ||
| 22 | // Images are split into 8x8 tiles. Each tile is composed of four 4x4 subtiles each | ||
| 23 | // of which is composed of four 2x2 subtiles each of which is composed of four texels. | ||
| 24 | // Each structure is embedded into the next-bigger one in a diagonal pattern, e.g. | ||
| 25 | // texels are laid out in a 2x2 subtile like this: | ||
| 26 | // 2 3 | ||
| 27 | // 0 1 | ||
| 28 | // | ||
| 29 | // The full 8x8 tile has the texels arranged like this: | ||
| 30 | // | ||
| 31 | // 42 43 46 47 58 59 62 63 | ||
| 32 | // 40 41 44 45 56 57 60 61 | ||
| 33 | // 34 35 38 39 50 51 54 55 | ||
| 34 | // 32 33 36 37 48 49 52 53 | ||
| 35 | // 10 11 14 15 26 27 30 31 | ||
| 36 | // 08 09 12 13 24 25 28 29 | ||
| 37 | // 02 03 06 07 18 19 22 23 | ||
| 38 | // 00 01 04 05 16 17 20 21 | ||
| 39 | // | ||
| 40 | // This pattern is what's called Z-order curve, or Morton order. | ||
| 41 | |||
| 42 | const unsigned int block_height = 8; | ||
| 43 | const unsigned int coarse_x = x & ~7; | ||
| 44 | |||
| 45 | u32 i = VideoCore::MortonInterleave(x, y); | ||
| 46 | |||
| 47 | const unsigned int offset = coarse_x * block_height; | ||
| 48 | |||
| 49 | return (i + offset) * bytes_per_pixel; | ||
| 50 | } | ||
| 51 | |||
| 52 | static inline u32 MortonInterleave128(u32 x, u32 y) { | ||
| 53 | // 128x128 Z-Order coordinate from 2D coordinates | ||
| 54 | static constexpr u32 xlut[] = { | ||
| 55 | 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, | ||
| 56 | 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, | ||
| 57 | 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, | ||
| 58 | 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, | ||
| 59 | 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, | ||
| 60 | 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, | ||
| 61 | 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, | ||
| 62 | 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, | ||
| 63 | 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, | ||
| 64 | 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, | ||
| 65 | 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, | ||
| 66 | 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, | ||
| 67 | 0x0008, 0x0009, 0x000a, 0x000b, 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, | ||
| 68 | 0x004b, 0x0800, 0x0801, 0x0802, 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, | ||
| 69 | 0x0842, 0x0843, 0x0848, 0x0849, 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, | ||
| 70 | 0x1009, 0x100a, 0x100b, 0x1040, 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, | ||
| 71 | 0x1800, 0x1801, 0x1802, 0x1803, 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, | ||
| 72 | 0x1843, 0x1848, 0x1849, 0x184a, 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, | ||
| 73 | 0x200a, 0x200b, 0x2040, 0x2041, 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, | ||
| 74 | 0x2801, 0x2802, 0x2803, 0x2808, 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, | ||
| 75 | 0x2848, 0x2849, 0x284a, 0x284b, 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, | ||
| 76 | 0x300b, 0x3040, 0x3041, 0x3042, 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, | ||
| 77 | 0x3802, 0x3803, 0x3808, 0x3809, 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, | ||
| 78 | 0x3849, 0x384a, 0x384b, 0x0000, 0x0001, 0x0002, 0x0003, 0x0008, 0x0009, 0x000a, 0x000b, | ||
| 79 | 0x0040, 0x0041, 0x0042, 0x0043, 0x0048, 0x0049, 0x004a, 0x004b, 0x0800, 0x0801, 0x0802, | ||
| 80 | 0x0803, 0x0808, 0x0809, 0x080a, 0x080b, 0x0840, 0x0841, 0x0842, 0x0843, 0x0848, 0x0849, | ||
| 81 | 0x084a, 0x084b, 0x1000, 0x1001, 0x1002, 0x1003, 0x1008, 0x1009, 0x100a, 0x100b, 0x1040, | ||
| 82 | 0x1041, 0x1042, 0x1043, 0x1048, 0x1049, 0x104a, 0x104b, 0x1800, 0x1801, 0x1802, 0x1803, | ||
| 83 | 0x1808, 0x1809, 0x180a, 0x180b, 0x1840, 0x1841, 0x1842, 0x1843, 0x1848, 0x1849, 0x184a, | ||
| 84 | 0x184b, 0x2000, 0x2001, 0x2002, 0x2003, 0x2008, 0x2009, 0x200a, 0x200b, 0x2040, 0x2041, | ||
| 85 | 0x2042, 0x2043, 0x2048, 0x2049, 0x204a, 0x204b, 0x2800, 0x2801, 0x2802, 0x2803, 0x2808, | ||
| 86 | 0x2809, 0x280a, 0x280b, 0x2840, 0x2841, 0x2842, 0x2843, 0x2848, 0x2849, 0x284a, 0x284b, | ||
| 87 | 0x3000, 0x3001, 0x3002, 0x3003, 0x3008, 0x3009, 0x300a, 0x300b, 0x3040, 0x3041, 0x3042, | ||
| 88 | 0x3043, 0x3048, 0x3049, 0x304a, 0x304b, 0x3800, 0x3801, 0x3802, 0x3803, 0x3808, 0x3809, | ||
| 89 | 0x380a, 0x380b, 0x3840, 0x3841, 0x3842, 0x3843, 0x3848, 0x3849, 0x384a, 0x384b, | ||
| 90 | }; | ||
| 91 | static constexpr u32 ylut[] = { | ||
| 92 | 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, | ||
| 93 | 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, | ||
| 94 | 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, | ||
| 95 | 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, | ||
| 96 | 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, | ||
| 97 | 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, | ||
| 98 | 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, | ||
| 99 | 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, | ||
| 100 | 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, | ||
| 101 | 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, | ||
| 102 | 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, | ||
| 103 | 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, | ||
| 104 | 0x0020, 0x0024, 0x0030, 0x0034, 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, | ||
| 105 | 0x00b4, 0x0100, 0x0104, 0x0110, 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, | ||
| 106 | 0x0190, 0x0194, 0x01a0, 0x01a4, 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, | ||
| 107 | 0x0224, 0x0230, 0x0234, 0x0280, 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, | ||
| 108 | 0x0300, 0x0304, 0x0310, 0x0314, 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, | ||
| 109 | 0x0394, 0x03a0, 0x03a4, 0x03b0, 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, | ||
| 110 | 0x0430, 0x0434, 0x0480, 0x0484, 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, | ||
| 111 | 0x0504, 0x0510, 0x0514, 0x0520, 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, | ||
| 112 | 0x05a0, 0x05a4, 0x05b0, 0x05b4, 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, | ||
| 113 | 0x0634, 0x0680, 0x0684, 0x0690, 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, | ||
| 114 | 0x0710, 0x0714, 0x0720, 0x0724, 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, | ||
| 115 | 0x07a4, 0x07b0, 0x07b4, 0x0000, 0x0004, 0x0010, 0x0014, 0x0020, 0x0024, 0x0030, 0x0034, | ||
| 116 | 0x0080, 0x0084, 0x0090, 0x0094, 0x00a0, 0x00a4, 0x00b0, 0x00b4, 0x0100, 0x0104, 0x0110, | ||
| 117 | 0x0114, 0x0120, 0x0124, 0x0130, 0x0134, 0x0180, 0x0184, 0x0190, 0x0194, 0x01a0, 0x01a4, | ||
| 118 | 0x01b0, 0x01b4, 0x0200, 0x0204, 0x0210, 0x0214, 0x0220, 0x0224, 0x0230, 0x0234, 0x0280, | ||
| 119 | 0x0284, 0x0290, 0x0294, 0x02a0, 0x02a4, 0x02b0, 0x02b4, 0x0300, 0x0304, 0x0310, 0x0314, | ||
| 120 | 0x0320, 0x0324, 0x0330, 0x0334, 0x0380, 0x0384, 0x0390, 0x0394, 0x03a0, 0x03a4, 0x03b0, | ||
| 121 | 0x03b4, 0x0400, 0x0404, 0x0410, 0x0414, 0x0420, 0x0424, 0x0430, 0x0434, 0x0480, 0x0484, | ||
| 122 | 0x0490, 0x0494, 0x04a0, 0x04a4, 0x04b0, 0x04b4, 0x0500, 0x0504, 0x0510, 0x0514, 0x0520, | ||
| 123 | 0x0524, 0x0530, 0x0534, 0x0580, 0x0584, 0x0590, 0x0594, 0x05a0, 0x05a4, 0x05b0, 0x05b4, | ||
| 124 | 0x0600, 0x0604, 0x0610, 0x0614, 0x0620, 0x0624, 0x0630, 0x0634, 0x0680, 0x0684, 0x0690, | ||
| 125 | 0x0694, 0x06a0, 0x06a4, 0x06b0, 0x06b4, 0x0700, 0x0704, 0x0710, 0x0714, 0x0720, 0x0724, | ||
| 126 | 0x0730, 0x0734, 0x0780, 0x0784, 0x0790, 0x0794, 0x07a0, 0x07a4, 0x07b0, 0x07b4, | ||
| 127 | }; | ||
| 128 | return xlut[x % 128] + ylut[y % 128]; | ||
| 129 | } | ||
| 130 | |||
| 131 | static inline u32 GetMortonOffset128(u32 x, u32 y, u32 bytes_per_pixel) { | ||
| 132 | // Calculates the offset of the position of the pixel in Morton order | ||
| 133 | // Framebuffer images are split into 128x128 tiles. | ||
| 134 | |||
| 135 | const unsigned int block_height = 128; | ||
| 136 | const unsigned int coarse_x = x & ~127; | ||
| 137 | |||
| 138 | u32 i = MortonInterleave128(x, y); | ||
| 139 | |||
| 140 | const unsigned int offset = coarse_x * block_height; | ||
| 141 | |||
| 142 | return (i + offset) * bytes_per_pixel; | ||
| 143 | } | ||
| 144 | |||
| 145 | static inline void MortonCopyPixels128(u32 width, u32 height, u32 bytes_per_pixel, | ||
| 146 | u32 gl_bytes_per_pixel, u8* morton_data, u8* gl_data, | ||
| 147 | bool morton_to_gl) { | ||
| 148 | u8* data_ptrs[2]; | ||
| 149 | for (unsigned y = 0; y < height; ++y) { | ||
| 150 | for (unsigned x = 0; x < width; ++x) { | ||
| 151 | const u32 coarse_y = y & ~127; | ||
| 152 | u32 morton_offset = | ||
| 153 | GetMortonOffset128(x, y, bytes_per_pixel) + coarse_y * width * bytes_per_pixel; | ||
| 154 | u32 gl_pixel_index = (x + y * width) * gl_bytes_per_pixel; | ||
| 155 | |||
| 156 | data_ptrs[morton_to_gl] = morton_data + morton_offset; | ||
| 157 | data_ptrs[!morton_to_gl] = &gl_data[gl_pixel_index]; | ||
| 158 | |||
| 159 | memcpy(data_ptrs[0], data_ptrs[1], bytes_per_pixel); | ||
| 160 | } | ||
| 161 | } | ||
| 162 | } | ||
| 163 | |||
| 164 | } // namespace VideoCore | ||
diff --git a/src/yuzu/applets/software_keyboard.cpp b/src/yuzu/applets/software_keyboard.cpp index efefb1f99..8a26fdff1 100644 --- a/src/yuzu/applets/software_keyboard.cpp +++ b/src/yuzu/applets/software_keyboard.cpp | |||
| @@ -82,8 +82,8 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog( | |||
| 82 | : QString::fromStdU16String(parameters.submit_text), | 82 | : QString::fromStdU16String(parameters.submit_text), |
| 83 | QDialogButtonBox::AcceptRole); | 83 | QDialogButtonBox::AcceptRole); |
| 84 | 84 | ||
| 85 | connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::Submit); | 85 | connect(buttons, &QDialogButtonBox::accepted, this, &QtSoftwareKeyboardDialog::accept); |
| 86 | connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::Reject); | 86 | connect(buttons, &QDialogButtonBox::rejected, this, &QtSoftwareKeyboardDialog::reject); |
| 87 | layout->addWidget(header_label); | 87 | layout->addWidget(header_label); |
| 88 | layout->addWidget(sub_label); | 88 | layout->addWidget(sub_label); |
| 89 | layout->addWidget(guide_label); | 89 | layout->addWidget(guide_label); |
| @@ -96,16 +96,16 @@ QtSoftwareKeyboardDialog::QtSoftwareKeyboardDialog( | |||
| 96 | 96 | ||
| 97 | QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default; | 97 | QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default; |
| 98 | 98 | ||
| 99 | void QtSoftwareKeyboardDialog::Submit() { | 99 | void QtSoftwareKeyboardDialog::accept() { |
| 100 | ok = true; | 100 | ok = true; |
| 101 | text = line_edit->text().toStdU16String(); | 101 | text = line_edit->text().toStdU16String(); |
| 102 | accept(); | 102 | QDialog::accept(); |
| 103 | } | 103 | } |
| 104 | 104 | ||
| 105 | void QtSoftwareKeyboardDialog::Reject() { | 105 | void QtSoftwareKeyboardDialog::reject() { |
| 106 | ok = false; | 106 | ok = false; |
| 107 | text.clear(); | 107 | text.clear(); |
| 108 | accept(); | 108 | QDialog::reject(); |
| 109 | } | 109 | } |
| 110 | 110 | ||
| 111 | std::u16string QtSoftwareKeyboardDialog::GetText() const { | 111 | std::u16string QtSoftwareKeyboardDialog::GetText() const { |
| @@ -129,13 +129,13 @@ QtSoftwareKeyboard::~QtSoftwareKeyboard() = default; | |||
| 129 | 129 | ||
| 130 | void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out, | 130 | void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out, |
| 131 | Core::Frontend::SoftwareKeyboardParameters parameters) const { | 131 | Core::Frontend::SoftwareKeyboardParameters parameters) const { |
| 132 | text_output = out; | 132 | text_output = std::move(out); |
| 133 | emit MainWindowGetText(parameters); | 133 | emit MainWindowGetText(parameters); |
| 134 | } | 134 | } |
| 135 | 135 | ||
| 136 | void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message, | 136 | void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message, |
| 137 | std::function<void()> finished_check) const { | 137 | std::function<void()> finished_check) const { |
| 138 | this->finished_check = finished_check; | 138 | this->finished_check = std::move(finished_check); |
| 139 | emit MainWindowTextCheckDialog(error_message); | 139 | emit MainWindowTextCheckDialog(error_message); |
| 140 | } | 140 | } |
| 141 | 141 | ||
diff --git a/src/yuzu/applets/software_keyboard.h b/src/yuzu/applets/software_keyboard.h index 73f56714f..c63720ba4 100644 --- a/src/yuzu/applets/software_keyboard.h +++ b/src/yuzu/applets/software_keyboard.h | |||
| @@ -33,8 +33,8 @@ public: | |||
| 33 | Core::Frontend::SoftwareKeyboardParameters parameters); | 33 | Core::Frontend::SoftwareKeyboardParameters parameters); |
| 34 | ~QtSoftwareKeyboardDialog() override; | 34 | ~QtSoftwareKeyboardDialog() override; |
| 35 | 35 | ||
| 36 | void Submit(); | 36 | void accept() override; |
| 37 | void Reject(); | 37 | void reject() override; |
| 38 | 38 | ||
| 39 | std::u16string GetText() const; | 39 | std::u16string GetText() const; |
| 40 | bool GetStatus() const; | 40 | bool GetStatus() const; |
| @@ -70,11 +70,10 @@ signals: | |||
| 70 | void MainWindowGetText(Core::Frontend::SoftwareKeyboardParameters parameters) const; | 70 | void MainWindowGetText(Core::Frontend::SoftwareKeyboardParameters parameters) const; |
| 71 | void MainWindowTextCheckDialog(std::u16string error_message) const; | 71 | void MainWindowTextCheckDialog(std::u16string error_message) const; |
| 72 | 72 | ||
| 73 | public slots: | 73 | private: |
| 74 | void MainWindowFinishedText(std::optional<std::u16string> text); | 74 | void MainWindowFinishedText(std::optional<std::u16string> text); |
| 75 | void MainWindowFinishedCheckDialog(); | 75 | void MainWindowFinishedCheckDialog(); |
| 76 | 76 | ||
| 77 | private: | ||
| 78 | mutable std::function<void(std::optional<std::u16string>)> text_output; | 77 | mutable std::function<void(std::optional<std::u16string>)> text_output; |
| 79 | mutable std::function<void()> finished_check; | 78 | mutable std::function<void()> finished_check; |
| 80 | }; | 79 | }; |
diff --git a/src/yuzu/bootmanager.cpp b/src/yuzu/bootmanager.cpp index 39eef8858..384e17921 100644 --- a/src/yuzu/bootmanager.cpp +++ b/src/yuzu/bootmanager.cpp | |||
| @@ -310,7 +310,7 @@ void GRenderWindow::InitRenderTarget() { | |||
| 310 | // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, | 310 | // TODO: One of these flags might be interesting: WA_OpaquePaintEvent, WA_NoBackground, |
| 311 | // WA_DontShowOnScreen, WA_DeleteOnClose | 311 | // WA_DontShowOnScreen, WA_DeleteOnClose |
| 312 | QGLFormat fmt; | 312 | QGLFormat fmt; |
| 313 | fmt.setVersion(3, 3); | 313 | fmt.setVersion(4, 3); |
| 314 | fmt.setProfile(QGLFormat::CoreProfile); | 314 | fmt.setProfile(QGLFormat::CoreProfile); |
| 315 | fmt.setSwapInterval(false); | 315 | fmt.setSwapInterval(false); |
| 316 | 316 | ||
diff --git a/src/yuzu/configuration/config.cpp b/src/yuzu/configuration/config.cpp index e24ed5f2b..83ebbd1fe 100644 --- a/src/yuzu/configuration/config.cpp +++ b/src/yuzu/configuration/config.cpp | |||
| @@ -432,6 +432,7 @@ void Config::ReadValues() { | |||
| 432 | Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool(); | 432 | Settings::values.use_gdbstub = qt_config->value("use_gdbstub", false).toBool(); |
| 433 | Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt(); | 433 | Settings::values.gdbstub_port = qt_config->value("gdbstub_port", 24689).toInt(); |
| 434 | Settings::values.program_args = qt_config->value("program_args", "").toString().toStdString(); | 434 | Settings::values.program_args = qt_config->value("program_args", "").toString().toStdString(); |
| 435 | Settings::values.dump_exefs = qt_config->value("dump_exefs", false).toBool(); | ||
| 435 | Settings::values.dump_nso = qt_config->value("dump_nso", false).toBool(); | 436 | Settings::values.dump_nso = qt_config->value("dump_nso", false).toBool(); |
| 436 | qt_config->endGroup(); | 437 | qt_config->endGroup(); |
| 437 | 438 | ||
| @@ -638,6 +639,7 @@ void Config::SaveValues() { | |||
| 638 | qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub); | 639 | qt_config->setValue("use_gdbstub", Settings::values.use_gdbstub); |
| 639 | qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port); | 640 | qt_config->setValue("gdbstub_port", Settings::values.gdbstub_port); |
| 640 | qt_config->setValue("program_args", QString::fromStdString(Settings::values.program_args)); | 641 | qt_config->setValue("program_args", QString::fromStdString(Settings::values.program_args)); |
| 642 | qt_config->setValue("dump_exefs", Settings::values.dump_exefs); | ||
| 641 | qt_config->setValue("dump_nso", Settings::values.dump_nso); | 643 | qt_config->setValue("dump_nso", Settings::values.dump_nso); |
| 642 | qt_config->endGroup(); | 644 | qt_config->endGroup(); |
| 643 | 645 | ||
diff --git a/src/yuzu/configuration/configure_debug.cpp b/src/yuzu/configuration/configure_debug.cpp index fd5876b41..aa7de7b54 100644 --- a/src/yuzu/configuration/configure_debug.cpp +++ b/src/yuzu/configuration/configure_debug.cpp | |||
| @@ -34,6 +34,7 @@ void ConfigureDebug::setConfiguration() { | |||
| 34 | ui->toggle_console->setChecked(UISettings::values.show_console); | 34 | ui->toggle_console->setChecked(UISettings::values.show_console); |
| 35 | ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter)); | 35 | ui->log_filter_edit->setText(QString::fromStdString(Settings::values.log_filter)); |
| 36 | ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); | 36 | ui->homebrew_args_edit->setText(QString::fromStdString(Settings::values.program_args)); |
| 37 | ui->dump_exefs->setChecked(Settings::values.dump_exefs); | ||
| 37 | ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso); | 38 | ui->dump_decompressed_nso->setChecked(Settings::values.dump_nso); |
| 38 | } | 39 | } |
| 39 | 40 | ||
| @@ -43,6 +44,7 @@ void ConfigureDebug::applyConfiguration() { | |||
| 43 | UISettings::values.show_console = ui->toggle_console->isChecked(); | 44 | UISettings::values.show_console = ui->toggle_console->isChecked(); |
| 44 | Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); | 45 | Settings::values.log_filter = ui->log_filter_edit->text().toStdString(); |
| 45 | Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); | 46 | Settings::values.program_args = ui->homebrew_args_edit->text().toStdString(); |
| 47 | Settings::values.dump_exefs = ui->dump_exefs->isChecked(); | ||
| 46 | Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked(); | 48 | Settings::values.dump_nso = ui->dump_decompressed_nso->isChecked(); |
| 47 | Debugger::ToggleConsole(); | 49 | Debugger::ToggleConsole(); |
| 48 | Log::Filter filter; | 50 | Log::Filter filter; |
diff --git a/src/yuzu/configuration/configure_debug.ui b/src/yuzu/configuration/configure_debug.ui index 9c5b702f8..758a92335 100644 --- a/src/yuzu/configuration/configure_debug.ui +++ b/src/yuzu/configuration/configure_debug.ui | |||
| @@ -145,6 +145,16 @@ | |||
| 145 | </property> | 145 | </property> |
| 146 | </widget> | 146 | </widget> |
| 147 | </item> | 147 | </item> |
| 148 | <item> | ||
| 149 | <widget class="QCheckBox" name="dump_exefs"> | ||
| 150 | <property name="whatsThis"> | ||
| 151 | <string>When checked, any game that yuzu loads will have its ExeFS dumped to the yuzu/dump directory.</string> | ||
| 152 | </property> | ||
| 153 | <property name="text"> | ||
| 154 | <string>Dump ExeFS</string> | ||
| 155 | </property> | ||
| 156 | </widget> | ||
| 157 | </item> | ||
| 148 | </layout> | 158 | </layout> |
| 149 | </widget> | 159 | </widget> |
| 150 | </item> | 160 | </item> |
diff --git a/src/yuzu/configuration/configure_graphics.ui b/src/yuzu/configuration/configure_graphics.ui index 91fcad994..e278cdd05 100644 --- a/src/yuzu/configuration/configure_graphics.ui +++ b/src/yuzu/configuration/configure_graphics.ui | |||
| @@ -23,31 +23,31 @@ | |||
| 23 | </property> | 23 | </property> |
| 24 | <layout class="QVBoxLayout" name="verticalLayout_2"> | 24 | <layout class="QVBoxLayout" name="verticalLayout_2"> |
| 25 | <item> | 25 | <item> |
| 26 | <layout class="QHBoxLayout" name="horizontalLayout_2"> | 26 | <layout class="QHBoxLayout" name="horizontalLayout_2"> |
| 27 | <item> | 27 | <item> |
| 28 | <widget class="QCheckBox" name="toggle_frame_limit"> | 28 | <widget class="QCheckBox" name="toggle_frame_limit"> |
| 29 | <property name="text"> | 29 | <property name="text"> |
| 30 | <string>Limit Speed Percent</string> | 30 | <string>Limit Speed Percent</string> |
| 31 | </property> | 31 | </property> |
| 32 | </widget> | 32 | </widget> |
| 33 | </item> | 33 | </item> |
| 34 | <item> | 34 | <item> |
| 35 | <widget class="QSpinBox" name="frame_limit"> | 35 | <widget class="QSpinBox" name="frame_limit"> |
| 36 | <property name="suffix"> | 36 | <property name="suffix"> |
| 37 | <string>%</string> | 37 | <string>%</string> |
| 38 | </property> | 38 | </property> |
| 39 | <property name="minimum"> | 39 | <property name="minimum"> |
| 40 | <number>1</number> | 40 | <number>1</number> |
| 41 | </property> | 41 | </property> |
| 42 | <property name="maximum"> | 42 | <property name="maximum"> |
| 43 | <number>9999</number> | 43 | <number>9999</number> |
| 44 | </property> | 44 | </property> |
| 45 | <property name="value"> | 45 | <property name="value"> |
| 46 | <number>100</number> | 46 | <number>100</number> |
| 47 | </property> | 47 | </property> |
| 48 | </widget> | 48 | </widget> |
| 49 | </item> | 49 | </item> |
| 50 | </layout> | 50 | </layout> |
| 51 | </item> | 51 | </item> |
| 52 | <item> | 52 | <item> |
| 53 | <widget class="QCheckBox" name="use_accurate_gpu_emulation"> | 53 | <widget class="QCheckBox" name="use_accurate_gpu_emulation"> |
| @@ -61,7 +61,7 @@ | |||
| 61 | <item> | 61 | <item> |
| 62 | <widget class="QLabel" name="label"> | 62 | <widget class="QLabel" name="label"> |
| 63 | <property name="text"> | 63 | <property name="text"> |
| 64 | <string>Internal Resolution:(Currently does nothing.)</string> | 64 | <string>Internal Resolution</string> |
| 65 | </property> | 65 | </property> |
| 66 | </widget> | 66 | </widget> |
| 67 | </item> | 67 | </item> |
| @@ -96,27 +96,27 @@ | |||
| 96 | </item> | 96 | </item> |
| 97 | </layout> | 97 | </layout> |
| 98 | </item> | 98 | </item> |
| 99 | <item> | 99 | <item> |
| 100 | <layout class="QHBoxLayout" name="horizontalLayout_6"> | 100 | <layout class="QHBoxLayout" name="horizontalLayout_6"> |
| 101 | <item> | 101 | <item> |
| 102 | <widget class="QLabel" name="bg_label"> | 102 | <widget class="QLabel" name="bg_label"> |
| 103 | <property name="text"> | 103 | <property name="text"> |
| 104 | <string>Background Color:</string> | 104 | <string>Background Color:</string> |
| 105 | </property> | 105 | </property> |
| 106 | </widget> | 106 | </widget> |
| 107 | </item> | 107 | </item> |
| 108 | <item> | 108 | <item> |
| 109 | <widget class="QPushButton" name="bg_button"> | 109 | <widget class="QPushButton" name="bg_button"> |
| 110 | <property name="maximumSize"> | 110 | <property name="maximumSize"> |
| 111 | <size> | 111 | <size> |
| 112 | <width>40</width> | 112 | <width>40</width> |
| 113 | <height>16777215</height> | 113 | <height>16777215</height> |
| 114 | </size> | 114 | </size> |
| 115 | </property> | 115 | </property> |
| 116 | </widget> | 116 | </widget> |
| 117 | </item> | 117 | </item> |
| 118 | </layout> | 118 | </layout> |
| 119 | </item> | 119 | </item> |
| 120 | </layout> | 120 | </layout> |
| 121 | </widget> | 121 | </widget> |
| 122 | </item> | 122 | </item> |
diff --git a/src/yuzu/configuration/configure_input.cpp b/src/yuzu/configuration/configure_input.cpp index 07092f001..e25597b7f 100644 --- a/src/yuzu/configuration/configure_input.cpp +++ b/src/yuzu/configuration/configure_input.cpp | |||
| @@ -4,11 +4,9 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <utility> | 7 | |
| 8 | #include <QMenu> | ||
| 9 | #include <QMessageBox> | ||
| 10 | #include <QTimer> | 8 | #include <QTimer> |
| 11 | #include "common/param_package.h" | 9 | |
| 12 | #include "configuration/configure_touchscreen_advanced.h" | 10 | #include "configuration/configure_touchscreen_advanced.h" |
| 13 | #include "core/core.h" | 11 | #include "core/core.h" |
| 14 | #include "core/hle/service/am/am.h" | 12 | #include "core/hle/service/am/am.h" |
| @@ -16,16 +14,25 @@ | |||
| 16 | #include "core/hle/service/am/applet_oe.h" | 14 | #include "core/hle/service/am/applet_oe.h" |
| 17 | #include "core/hle/service/hid/controllers/npad.h" | 15 | #include "core/hle/service/hid/controllers/npad.h" |
| 18 | #include "core/hle/service/sm/sm.h" | 16 | #include "core/hle/service/sm/sm.h" |
| 19 | #include "input_common/main.h" | ||
| 20 | #include "ui_configure_input.h" | 17 | #include "ui_configure_input.h" |
| 21 | #include "ui_configure_input_player.h" | 18 | #include "ui_configure_input_player.h" |
| 22 | #include "ui_configure_mouse_advanced.h" | ||
| 23 | #include "ui_configure_touchscreen_advanced.h" | ||
| 24 | #include "yuzu/configuration/config.h" | ||
| 25 | #include "yuzu/configuration/configure_input.h" | 19 | #include "yuzu/configuration/configure_input.h" |
| 26 | #include "yuzu/configuration/configure_input_player.h" | 20 | #include "yuzu/configuration/configure_input_player.h" |
| 27 | #include "yuzu/configuration/configure_mouse_advanced.h" | 21 | #include "yuzu/configuration/configure_mouse_advanced.h" |
| 28 | 22 | ||
| 23 | namespace { | ||
| 24 | template <typename Dialog, typename... Args> | ||
| 25 | void CallConfigureDialog(ConfigureInput& parent, Args&&... args) { | ||
| 26 | parent.applyConfiguration(); | ||
| 27 | Dialog dialog(&parent, std::forward<Args>(args)...); | ||
| 28 | |||
| 29 | const auto res = dialog.exec(); | ||
| 30 | if (res == QDialog::Accepted) { | ||
| 31 | dialog.applyConfiguration(); | ||
| 32 | } | ||
| 33 | } | ||
| 34 | } // Anonymous namespace | ||
| 35 | |||
| 29 | ConfigureInput::ConfigureInput(QWidget* parent) | 36 | ConfigureInput::ConfigureInput(QWidget* parent) |
| 30 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) { | 37 | : QWidget(parent), ui(std::make_unique<Ui::ConfigureInput>()) { |
| 31 | ui->setupUi(this); | 38 | ui->setupUi(this); |
| @@ -65,31 +72,20 @@ ConfigureInput::ConfigureInput(QWidget* parent) | |||
| 65 | 72 | ||
| 66 | for (std::size_t i = 0; i < players_configure.size(); ++i) { | 73 | for (std::size_t i = 0; i < players_configure.size(); ++i) { |
| 67 | connect(players_configure[i], &QPushButton::pressed, this, | 74 | connect(players_configure[i], &QPushButton::pressed, this, |
| 68 | [this, i]() { CallConfigureDialog<ConfigureInputPlayer>(i, false); }); | 75 | [this, i] { CallConfigureDialog<ConfigureInputPlayer>(*this, i, false); }); |
| 69 | } | 76 | } |
| 70 | 77 | ||
| 71 | connect(ui->handheld_configure, &QPushButton::pressed, this, | 78 | connect(ui->handheld_configure, &QPushButton::pressed, this, |
| 72 | [this]() { CallConfigureDialog<ConfigureInputPlayer>(8, false); }); | 79 | [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 8, false); }); |
| 73 | 80 | ||
| 74 | connect(ui->debug_configure, &QPushButton::pressed, this, | 81 | connect(ui->debug_configure, &QPushButton::pressed, this, |
| 75 | [this]() { CallConfigureDialog<ConfigureInputPlayer>(9, true); }); | 82 | [this] { CallConfigureDialog<ConfigureInputPlayer>(*this, 9, true); }); |
| 76 | 83 | ||
| 77 | connect(ui->mouse_advanced, &QPushButton::pressed, this, | 84 | connect(ui->mouse_advanced, &QPushButton::pressed, this, |
| 78 | [this]() { CallConfigureDialog<ConfigureMouseAdvanced>(); }); | 85 | [this] { CallConfigureDialog<ConfigureMouseAdvanced>(*this); }); |
| 79 | 86 | ||
| 80 | connect(ui->touchscreen_advanced, &QPushButton::pressed, this, | 87 | connect(ui->touchscreen_advanced, &QPushButton::pressed, this, |
| 81 | [this]() { CallConfigureDialog<ConfigureTouchscreenAdvanced>(); }); | 88 | [this] { CallConfigureDialog<ConfigureTouchscreenAdvanced>(*this); }); |
| 82 | } | ||
| 83 | |||
| 84 | template <typename Dialog, typename... Args> | ||
| 85 | void ConfigureInput::CallConfigureDialog(Args&&... args) { | ||
| 86 | this->applyConfiguration(); | ||
| 87 | Dialog dialog(this, std::forward<Args>(args)...); | ||
| 88 | |||
| 89 | const auto res = dialog.exec(); | ||
| 90 | if (res == QDialog::Accepted) { | ||
| 91 | dialog.applyConfiguration(); | ||
| 92 | } | ||
| 93 | } | 89 | } |
| 94 | 90 | ||
| 95 | void ConfigureInput::OnDockedModeChanged(bool last_state, bool new_state) { | 91 | void ConfigureInput::OnDockedModeChanged(bool last_state, bool new_state) { |
diff --git a/src/yuzu/configuration/configure_input.h b/src/yuzu/configuration/configure_input.h index 29a8a03f8..e8723dfcb 100644 --- a/src/yuzu/configuration/configure_input.h +++ b/src/yuzu/configuration/configure_input.h | |||
| @@ -5,20 +5,12 @@ | |||
| 5 | #pragma once | 5 | #pragma once |
| 6 | 6 | ||
| 7 | #include <array> | 7 | #include <array> |
| 8 | #include <functional> | ||
| 9 | #include <memory> | 8 | #include <memory> |
| 10 | #include <optional> | ||
| 11 | #include <string> | ||
| 12 | #include <unordered_map> | ||
| 13 | 9 | ||
| 14 | #include <QKeyEvent> | 10 | #include <QKeyEvent> |
| 15 | #include <QWidget> | 11 | #include <QWidget> |
| 16 | 12 | ||
| 17 | #include "common/param_package.h" | ||
| 18 | #include "core/settings.h" | ||
| 19 | #include "input_common/main.h" | ||
| 20 | #include "ui_configure_input.h" | 13 | #include "ui_configure_input.h" |
| 21 | #include "yuzu/configuration/config.h" | ||
| 22 | 14 | ||
| 23 | class QPushButton; | 15 | class QPushButton; |
| 24 | class QString; | 16 | class QString; |
| @@ -40,9 +32,6 @@ public: | |||
| 40 | private: | 32 | private: |
| 41 | void updateUIEnabled(); | 33 | void updateUIEnabled(); |
| 42 | 34 | ||
| 43 | template <typename Dialog, typename... Args> | ||
| 44 | void CallConfigureDialog(Args&&... args); | ||
| 45 | |||
| 46 | void OnDockedModeChanged(bool last_state, bool new_state); | 35 | void OnDockedModeChanged(bool last_state, bool new_state); |
| 47 | 36 | ||
| 48 | /// Load configuration settings. | 37 | /// Load configuration settings. |
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp index ba6e09368..7dadd83c1 100644 --- a/src/yuzu/configuration/configure_input_player.cpp +++ b/src/yuzu/configuration/configure_input_player.cpp | |||
| @@ -25,13 +25,6 @@ const std::array<std::string, ConfigureInputPlayer::ANALOG_SUB_BUTTONS_NUM> | |||
| 25 | "modifier", | 25 | "modifier", |
| 26 | }}; | 26 | }}; |
| 27 | 27 | ||
| 28 | static void MoveGridElement(QGridLayout* grid, int row_old, int column_old, int row_new, | ||
| 29 | int column_new) { | ||
| 30 | const auto item = grid->itemAtPosition(row_old, column_old); | ||
| 31 | // grid->removeItem(item); | ||
| 32 | grid->addItem(item, row_new, column_new); | ||
| 33 | } | ||
| 34 | |||
| 35 | static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) { | 28 | static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) { |
| 36 | const int index1 = grid->indexOf(item); | 29 | const int index1 = grid->indexOf(item); |
| 37 | const int index2 = grid->indexOf(onTopOf); | 30 | const int index2 = grid->indexOf(onTopOf); |
| @@ -111,11 +104,10 @@ static QString AnalogToText(const Common::ParamPackage& param, const std::string | |||
| 111 | } | 104 | } |
| 112 | }; | 105 | }; |
| 113 | 106 | ||
| 114 | ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, u8 player_index, bool debug) | 107 | ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug) |
| 115 | : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), | 108 | : QDialog(parent), ui(std::make_unique<Ui::ConfigureInputPlayer>()), player_index(player_index), |
| 116 | timeout_timer(std::make_unique<QTimer>()), poll_timer(std::make_unique<QTimer>()), | 109 | debug(debug), timeout_timer(std::make_unique<QTimer>()), |
| 117 | player_index(player_index), debug(debug) { | 110 | poll_timer(std::make_unique<QTimer>()) { |
| 118 | |||
| 119 | ui->setupUi(this); | 111 | ui->setupUi(this); |
| 120 | setFocusPolicy(Qt::ClickFocus); | 112 | setFocusPolicy(Qt::ClickFocus); |
| 121 | 113 | ||
| @@ -315,7 +307,7 @@ ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, u8 player_index, boo | |||
| 315 | 307 | ||
| 316 | for (std::size_t i = 0; i < controller_color_buttons.size(); ++i) { | 308 | for (std::size_t i = 0; i < controller_color_buttons.size(); ++i) { |
| 317 | connect(controller_color_buttons[i], &QPushButton::clicked, this, | 309 | connect(controller_color_buttons[i], &QPushButton::clicked, this, |
| 318 | std::bind(&ConfigureInputPlayer::OnControllerButtonClick, this, i)); | 310 | [this, i] { OnControllerButtonClick(static_cast<int>(i)); }); |
| 319 | } | 311 | } |
| 320 | 312 | ||
| 321 | this->loadConfiguration(); | 313 | this->loadConfiguration(); |
diff --git a/src/yuzu/configuration/configure_input_player.h b/src/yuzu/configuration/configure_input_player.h index b0e5550c5..7a53f6715 100644 --- a/src/yuzu/configuration/configure_input_player.h +++ b/src/yuzu/configuration/configure_input_player.h | |||
| @@ -9,9 +9,10 @@ | |||
| 9 | #include <memory> | 9 | #include <memory> |
| 10 | #include <optional> | 10 | #include <optional> |
| 11 | #include <string> | 11 | #include <string> |
| 12 | #include <unordered_map> | 12 | |
| 13 | #include <QDialog> | 13 | #include <QDialog> |
| 14 | #include <QKeyEvent> | 14 | #include <QKeyEvent> |
| 15 | |||
| 15 | #include "common/param_package.h" | 16 | #include "common/param_package.h" |
| 16 | #include "core/settings.h" | 17 | #include "core/settings.h" |
| 17 | #include "input_common/main.h" | 18 | #include "input_common/main.h" |
| @@ -29,16 +30,39 @@ class ConfigureInputPlayer : public QDialog { | |||
| 29 | Q_OBJECT | 30 | Q_OBJECT |
| 30 | 31 | ||
| 31 | public: | 32 | public: |
| 32 | explicit ConfigureInputPlayer(QWidget* parent, u8 player_index, bool debug = false); | 33 | explicit ConfigureInputPlayer(QWidget* parent, std::size_t player_index, bool debug = false); |
| 33 | ~ConfigureInputPlayer() override; | 34 | ~ConfigureInputPlayer() override; |
| 34 | 35 | ||
| 35 | /// Save all button configurations to settings file | 36 | /// Save all button configurations to settings file |
| 36 | void applyConfiguration(); | 37 | void applyConfiguration(); |
| 37 | 38 | ||
| 38 | private: | 39 | private: |
| 40 | void OnControllerButtonClick(int i); | ||
| 41 | |||
| 42 | /// Load configuration settings. | ||
| 43 | void loadConfiguration(); | ||
| 44 | /// Restore all buttons to their default values. | ||
| 45 | void restoreDefaults(); | ||
| 46 | /// Clear all input configuration | ||
| 47 | void ClearAll(); | ||
| 48 | |||
| 49 | /// Update UI to reflect current configuration. | ||
| 50 | void updateButtonLabels(); | ||
| 51 | |||
| 52 | /// Called when the button was pressed. | ||
| 53 | void handleClick(QPushButton* button, | ||
| 54 | std::function<void(const Common::ParamPackage&)> new_input_setter, | ||
| 55 | InputCommon::Polling::DeviceType type); | ||
| 56 | |||
| 57 | /// Finish polling and configure input using the input_setter | ||
| 58 | void setPollingResult(const Common::ParamPackage& params, bool abort); | ||
| 59 | |||
| 60 | /// Handle key press events. | ||
| 61 | void keyPressEvent(QKeyEvent* event) override; | ||
| 62 | |||
| 39 | std::unique_ptr<Ui::ConfigureInputPlayer> ui; | 63 | std::unique_ptr<Ui::ConfigureInputPlayer> ui; |
| 40 | 64 | ||
| 41 | u8 player_index; | 65 | std::size_t player_index; |
| 42 | bool debug; | 66 | bool debug; |
| 43 | 67 | ||
| 44 | std::unique_ptr<QTimer> timeout_timer; | 68 | std::unique_ptr<QTimer> timeout_timer; |
| @@ -77,27 +101,4 @@ private: | |||
| 77 | 101 | ||
| 78 | std::array<QPushButton*, 4> controller_color_buttons; | 102 | std::array<QPushButton*, 4> controller_color_buttons; |
| 79 | std::array<QColor, 4> controller_colors; | 103 | std::array<QColor, 4> controller_colors; |
| 80 | |||
| 81 | void OnControllerButtonClick(int i); | ||
| 82 | |||
| 83 | /// Load configuration settings. | ||
| 84 | void loadConfiguration(); | ||
| 85 | /// Restore all buttons to their default values. | ||
| 86 | void restoreDefaults(); | ||
| 87 | /// Clear all input configuration | ||
| 88 | void ClearAll(); | ||
| 89 | |||
| 90 | /// Update UI to reflect current configuration. | ||
| 91 | void updateButtonLabels(); | ||
| 92 | |||
| 93 | /// Called when the button was pressed. | ||
| 94 | void handleClick(QPushButton* button, | ||
| 95 | std::function<void(const Common::ParamPackage&)> new_input_setter, | ||
| 96 | InputCommon::Polling::DeviceType type); | ||
| 97 | |||
| 98 | /// Finish polling and configure input using the input_setter | ||
| 99 | void setPollingResult(const Common::ParamPackage& params, bool abort); | ||
| 100 | |||
| 101 | /// Handle key press events. | ||
| 102 | void keyPressEvent(QKeyEvent* event) override; | ||
| 103 | }; | 104 | }; |
diff --git a/src/yuzu/configuration/configure_mouse_advanced.cpp b/src/yuzu/configuration/configure_mouse_advanced.cpp index dab58fbaa..ef857035e 100644 --- a/src/yuzu/configuration/configure_mouse_advanced.cpp +++ b/src/yuzu/configuration/configure_mouse_advanced.cpp | |||
| @@ -4,11 +4,11 @@ | |||
| 4 | 4 | ||
| 5 | #include <algorithm> | 5 | #include <algorithm> |
| 6 | #include <memory> | 6 | #include <memory> |
| 7 | #include <utility> | 7 | |
| 8 | #include <QKeyEvent> | 8 | #include <QKeyEvent> |
| 9 | #include <QMenu> | 9 | #include <QMenu> |
| 10 | #include <QMessageBox> | ||
| 11 | #include <QTimer> | 10 | #include <QTimer> |
| 11 | |||
| 12 | #include "common/assert.h" | 12 | #include "common/assert.h" |
| 13 | #include "common/param_package.h" | 13 | #include "common/param_package.h" |
| 14 | #include "input_common/main.h" | 14 | #include "input_common/main.h" |
diff --git a/src/yuzu/configuration/configure_mouse_advanced.h b/src/yuzu/configuration/configure_mouse_advanced.h index 218df2bda..e04da4bf2 100644 --- a/src/yuzu/configuration/configure_mouse_advanced.h +++ b/src/yuzu/configuration/configure_mouse_advanced.h | |||
| @@ -7,7 +7,7 @@ | |||
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <optional> | 8 | #include <optional> |
| 9 | #include <QDialog> | 9 | #include <QDialog> |
| 10 | #include <QWidget> | 10 | |
| 11 | #include "core/settings.h" | 11 | #include "core/settings.h" |
| 12 | 12 | ||
| 13 | class QCheckBox; | 13 | class QCheckBox; |
| @@ -28,23 +28,6 @@ public: | |||
| 28 | void applyConfiguration(); | 28 | void applyConfiguration(); |
| 29 | 29 | ||
| 30 | private: | 30 | private: |
| 31 | std::unique_ptr<Ui::ConfigureMouseAdvanced> ui; | ||
| 32 | |||
| 33 | /// This will be the the setting function when an input is awaiting configuration. | ||
| 34 | std::optional<std::function<void(const Common::ParamPackage&)>> input_setter; | ||
| 35 | |||
| 36 | std::array<QPushButton*, Settings::NativeMouseButton::NumMouseButtons> button_map; | ||
| 37 | std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons> buttons_param; | ||
| 38 | |||
| 39 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers; | ||
| 40 | |||
| 41 | std::unique_ptr<QTimer> timeout_timer; | ||
| 42 | std::unique_ptr<QTimer> poll_timer; | ||
| 43 | |||
| 44 | /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, | ||
| 45 | /// keyboard events are ignored. | ||
| 46 | bool want_keyboard_keys = false; | ||
| 47 | |||
| 48 | /// Load configuration settings. | 31 | /// Load configuration settings. |
| 49 | void loadConfiguration(); | 32 | void loadConfiguration(); |
| 50 | /// Restore all buttons to their default values. | 33 | /// Restore all buttons to their default values. |
| @@ -65,4 +48,21 @@ private: | |||
| 65 | 48 | ||
| 66 | /// Handle key press events. | 49 | /// Handle key press events. |
| 67 | void keyPressEvent(QKeyEvent* event) override; | 50 | void keyPressEvent(QKeyEvent* event) override; |
| 51 | |||
| 52 | std::unique_ptr<Ui::ConfigureMouseAdvanced> ui; | ||
| 53 | |||
| 54 | /// This will be the the setting function when an input is awaiting configuration. | ||
| 55 | std::optional<std::function<void(const Common::ParamPackage&)>> input_setter; | ||
| 56 | |||
| 57 | std::array<QPushButton*, Settings::NativeMouseButton::NumMouseButtons> button_map; | ||
| 58 | std::array<Common::ParamPackage, Settings::NativeMouseButton::NumMouseButtons> buttons_param; | ||
| 59 | |||
| 60 | std::vector<std::unique_ptr<InputCommon::Polling::DevicePoller>> device_pollers; | ||
| 61 | |||
| 62 | std::unique_ptr<QTimer> timeout_timer; | ||
| 63 | std::unique_ptr<QTimer> poll_timer; | ||
| 64 | |||
| 65 | /// A flag to indicate if keyboard keys are okay when configuring an input. If this is false, | ||
| 66 | /// keyboard events are ignored. | ||
| 67 | bool want_keyboard_keys = false; | ||
| 68 | }; | 68 | }; |
diff --git a/src/yuzu/main.cpp b/src/yuzu/main.cpp index 9e13bbf7c..93bf117c8 100644 --- a/src/yuzu/main.cpp +++ b/src/yuzu/main.cpp | |||
| @@ -518,32 +518,18 @@ void GMainWindow::OnDisplayTitleBars(bool show) { | |||
| 518 | QStringList GMainWindow::GetUnsupportedGLExtensions() { | 518 | QStringList GMainWindow::GetUnsupportedGLExtensions() { |
| 519 | QStringList unsupported_ext; | 519 | QStringList unsupported_ext; |
| 520 | 520 | ||
| 521 | if (!GLAD_GL_ARB_program_interface_query) | ||
| 522 | unsupported_ext.append("ARB_program_interface_query"); | ||
| 523 | if (!GLAD_GL_ARB_separate_shader_objects) | ||
| 524 | unsupported_ext.append("ARB_separate_shader_objects"); | ||
| 525 | if (!GLAD_GL_ARB_vertex_attrib_binding) | ||
| 526 | unsupported_ext.append("ARB_vertex_attrib_binding"); | ||
| 527 | if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) | 521 | if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) |
| 528 | unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev"); | 522 | unsupported_ext.append("ARB_vertex_type_10f_11f_11f_rev"); |
| 529 | if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) | 523 | if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) |
| 530 | unsupported_ext.append("ARB_texture_mirror_clamp_to_edge"); | 524 | unsupported_ext.append("ARB_texture_mirror_clamp_to_edge"); |
| 531 | if (!GLAD_GL_ARB_base_instance) | ||
| 532 | unsupported_ext.append("ARB_base_instance"); | ||
| 533 | if (!GLAD_GL_ARB_texture_storage) | ||
| 534 | unsupported_ext.append("ARB_texture_storage"); | ||
| 535 | if (!GLAD_GL_ARB_multi_bind) | 525 | if (!GLAD_GL_ARB_multi_bind) |
| 536 | unsupported_ext.append("ARB_multi_bind"); | 526 | unsupported_ext.append("ARB_multi_bind"); |
| 537 | if (!GLAD_GL_ARB_copy_image) | ||
| 538 | unsupported_ext.append("ARB_copy_image"); | ||
| 539 | 527 | ||
| 540 | // Extensions required to support some texture formats. | 528 | // Extensions required to support some texture formats. |
| 541 | if (!GLAD_GL_EXT_texture_compression_s3tc) | 529 | if (!GLAD_GL_EXT_texture_compression_s3tc) |
| 542 | unsupported_ext.append("EXT_texture_compression_s3tc"); | 530 | unsupported_ext.append("EXT_texture_compression_s3tc"); |
| 543 | if (!GLAD_GL_ARB_texture_compression_rgtc) | 531 | if (!GLAD_GL_ARB_texture_compression_rgtc) |
| 544 | unsupported_ext.append("ARB_texture_compression_rgtc"); | 532 | unsupported_ext.append("ARB_texture_compression_rgtc"); |
| 545 | if (!GLAD_GL_ARB_texture_compression_bptc) | ||
| 546 | unsupported_ext.append("ARB_texture_compression_bptc"); | ||
| 547 | if (!GLAD_GL_ARB_depth_buffer_float) | 533 | if (!GLAD_GL_ARB_depth_buffer_float) |
| 548 | unsupported_ext.append("ARB_depth_buffer_float"); | 534 | unsupported_ext.append("ARB_depth_buffer_float"); |
| 549 | 535 | ||
| @@ -562,8 +548,8 @@ bool GMainWindow::LoadROM(const QString& filename) { | |||
| 562 | render_window->MakeCurrent(); | 548 | render_window->MakeCurrent(); |
| 563 | 549 | ||
| 564 | if (!gladLoadGL()) { | 550 | if (!gladLoadGL()) { |
| 565 | QMessageBox::critical(this, tr("Error while initializing OpenGL 3.3 Core!"), | 551 | QMessageBox::critical(this, tr("Error while initializing OpenGL 4.3 Core!"), |
| 566 | tr("Your GPU may not support OpenGL 3.3, or you do not " | 552 | tr("Your GPU may not support OpenGL 4.3, or you do not " |
| 567 | "have the latest graphics driver.")); | 553 | "have the latest graphics driver.")); |
| 568 | return false; | 554 | return false; |
| 569 | } | 555 | } |
| @@ -1119,14 +1105,14 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 1119 | return; | 1105 | return; |
| 1120 | } | 1106 | } |
| 1121 | const auto res = | 1107 | const auto res = |
| 1122 | Service::FileSystem::GetUserNANDContents()->InstallEntry(nsp, false, qt_raw_copy); | 1108 | Service::FileSystem::GetUserNANDContents()->InstallEntry(*nsp, false, qt_raw_copy); |
| 1123 | if (res == FileSys::InstallResult::Success) { | 1109 | if (res == FileSys::InstallResult::Success) { |
| 1124 | success(); | 1110 | success(); |
| 1125 | } else { | 1111 | } else { |
| 1126 | if (res == FileSys::InstallResult::ErrorAlreadyExists) { | 1112 | if (res == FileSys::InstallResult::ErrorAlreadyExists) { |
| 1127 | if (overwrite()) { | 1113 | if (overwrite()) { |
| 1128 | const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( | 1114 | const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( |
| 1129 | nsp, true, qt_raw_copy); | 1115 | *nsp, true, qt_raw_copy); |
| 1130 | if (res2 == FileSys::InstallResult::Success) { | 1116 | if (res2 == FileSys::InstallResult::Success) { |
| 1131 | success(); | 1117 | success(); |
| 1132 | } else { | 1118 | } else { |
| @@ -1181,10 +1167,10 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 1181 | FileSys::InstallResult res; | 1167 | FileSys::InstallResult res; |
| 1182 | if (index >= static_cast<size_t>(FileSys::TitleType::Application)) { | 1168 | if (index >= static_cast<size_t>(FileSys::TitleType::Application)) { |
| 1183 | res = Service::FileSystem::GetUserNANDContents()->InstallEntry( | 1169 | res = Service::FileSystem::GetUserNANDContents()->InstallEntry( |
| 1184 | nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); | 1170 | *nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); |
| 1185 | } else { | 1171 | } else { |
| 1186 | res = Service::FileSystem::GetSystemNANDContents()->InstallEntry( | 1172 | res = Service::FileSystem::GetSystemNANDContents()->InstallEntry( |
| 1187 | nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); | 1173 | *nca, static_cast<FileSys::TitleType>(index), false, qt_raw_copy); |
| 1188 | } | 1174 | } |
| 1189 | 1175 | ||
| 1190 | if (res == FileSys::InstallResult::Success) { | 1176 | if (res == FileSys::InstallResult::Success) { |
| @@ -1192,7 +1178,7 @@ void GMainWindow::OnMenuInstallToNAND() { | |||
| 1192 | } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { | 1178 | } else if (res == FileSys::InstallResult::ErrorAlreadyExists) { |
| 1193 | if (overwrite()) { | 1179 | if (overwrite()) { |
| 1194 | const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( | 1180 | const auto res2 = Service::FileSystem::GetUserNANDContents()->InstallEntry( |
| 1195 | nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); | 1181 | *nca, static_cast<FileSys::TitleType>(index), true, qt_raw_copy); |
| 1196 | if (res2 == FileSys::InstallResult::Success) { | 1182 | if (res2 == FileSys::InstallResult::Success) { |
| 1197 | success(); | 1183 | success(); |
| 1198 | } else { | 1184 | } else { |
diff --git a/src/yuzu_cmd/config.cpp b/src/yuzu_cmd/config.cpp index c66353a65..097c1fbe3 100644 --- a/src/yuzu_cmd/config.cpp +++ b/src/yuzu_cmd/config.cpp | |||
| @@ -366,6 +366,7 @@ void Config::ReadValues() { | |||
| 366 | Settings::values.gdbstub_port = | 366 | Settings::values.gdbstub_port = |
| 367 | static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689)); | 367 | static_cast<u16>(sdl2_config->GetInteger("Debugging", "gdbstub_port", 24689)); |
| 368 | Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", ""); | 368 | Settings::values.program_args = sdl2_config->Get("Debugging", "program_args", ""); |
| 369 | Settings::values.dump_exefs = sdl2_config->GetBoolean("Debugging", "dump_exefs", false); | ||
| 369 | Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false); | 370 | Settings::values.dump_nso = sdl2_config->GetBoolean("Debugging", "dump_nso", false); |
| 370 | 371 | ||
| 371 | // Web Service | 372 | // Web Service |
diff --git a/src/yuzu_cmd/default_ini.h b/src/yuzu_cmd/default_ini.h index ecf625e7b..d73669f36 100644 --- a/src/yuzu_cmd/default_ini.h +++ b/src/yuzu_cmd/default_ini.h | |||
| @@ -206,6 +206,8 @@ log_filter = *:Trace | |||
| 206 | # Port for listening to GDB connections. | 206 | # Port for listening to GDB connections. |
| 207 | use_gdbstub=false | 207 | use_gdbstub=false |
| 208 | gdbstub_port=24689 | 208 | gdbstub_port=24689 |
| 209 | # Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them | ||
| 210 | dump_exefs=false | ||
| 209 | # Determines whether or not yuzu will dump all NSOs it attempts to load while loading them | 211 | # Determines whether or not yuzu will dump all NSOs it attempts to load while loading them |
| 210 | dump_nso=false | 212 | dump_nso=false |
| 211 | 213 | ||
diff --git a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp index a9ad92a80..2d6f8cced 100644 --- a/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp +++ b/src/yuzu_cmd/emu_window/emu_window_sdl2.cpp | |||
| @@ -111,32 +111,18 @@ void EmuWindow_SDL2::Fullscreen() { | |||
| 111 | bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { | 111 | bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { |
| 112 | std::vector<std::string> unsupported_ext; | 112 | std::vector<std::string> unsupported_ext; |
| 113 | 113 | ||
| 114 | if (!GLAD_GL_ARB_program_interface_query) | ||
| 115 | unsupported_ext.push_back("ARB_program_interface_query"); | ||
| 116 | if (!GLAD_GL_ARB_separate_shader_objects) | ||
| 117 | unsupported_ext.push_back("ARB_separate_shader_objects"); | ||
| 118 | if (!GLAD_GL_ARB_vertex_attrib_binding) | ||
| 119 | unsupported_ext.push_back("ARB_vertex_attrib_binding"); | ||
| 120 | if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) | 114 | if (!GLAD_GL_ARB_vertex_type_10f_11f_11f_rev) |
| 121 | unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev"); | 115 | unsupported_ext.push_back("ARB_vertex_type_10f_11f_11f_rev"); |
| 122 | if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) | 116 | if (!GLAD_GL_ARB_texture_mirror_clamp_to_edge) |
| 123 | unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); | 117 | unsupported_ext.push_back("ARB_texture_mirror_clamp_to_edge"); |
| 124 | if (!GLAD_GL_ARB_base_instance) | ||
| 125 | unsupported_ext.push_back("ARB_base_instance"); | ||
| 126 | if (!GLAD_GL_ARB_texture_storage) | ||
| 127 | unsupported_ext.push_back("ARB_texture_storage"); | ||
| 128 | if (!GLAD_GL_ARB_multi_bind) | 118 | if (!GLAD_GL_ARB_multi_bind) |
| 129 | unsupported_ext.push_back("ARB_multi_bind"); | 119 | unsupported_ext.push_back("ARB_multi_bind"); |
| 130 | if (!GLAD_GL_ARB_copy_image) | ||
| 131 | unsupported_ext.push_back("ARB_copy_image"); | ||
| 132 | 120 | ||
| 133 | // Extensions required to support some texture formats. | 121 | // Extensions required to support some texture formats. |
| 134 | if (!GLAD_GL_EXT_texture_compression_s3tc) | 122 | if (!GLAD_GL_EXT_texture_compression_s3tc) |
| 135 | unsupported_ext.push_back("EXT_texture_compression_s3tc"); | 123 | unsupported_ext.push_back("EXT_texture_compression_s3tc"); |
| 136 | if (!GLAD_GL_ARB_texture_compression_rgtc) | 124 | if (!GLAD_GL_ARB_texture_compression_rgtc) |
| 137 | unsupported_ext.push_back("ARB_texture_compression_rgtc"); | 125 | unsupported_ext.push_back("ARB_texture_compression_rgtc"); |
| 138 | if (!GLAD_GL_ARB_texture_compression_bptc) | ||
| 139 | unsupported_ext.push_back("ARB_texture_compression_bptc"); | ||
| 140 | if (!GLAD_GL_ARB_depth_buffer_float) | 126 | if (!GLAD_GL_ARB_depth_buffer_float) |
| 141 | unsupported_ext.push_back("ARB_depth_buffer_float"); | 127 | unsupported_ext.push_back("ARB_depth_buffer_float"); |
| 142 | 128 | ||
| @@ -157,7 +143,7 @@ EmuWindow_SDL2::EmuWindow_SDL2(bool fullscreen) { | |||
| 157 | exit(1); | 143 | exit(1); |
| 158 | } | 144 | } |
| 159 | 145 | ||
| 160 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 3); | 146 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MAJOR_VERSION, 4); |
| 161 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); | 147 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_MINOR_VERSION, 3); |
| 162 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); | 148 | SDL_GL_SetAttribute(SDL_GL_CONTEXT_PROFILE_MASK, SDL_GL_CONTEXT_PROFILE_CORE); |
| 163 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); | 149 | SDL_GL_SetAttribute(SDL_GL_DOUBLEBUFFER, 1); |