summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/bit_set.h244
-rw-r--r--src/common/thread.cpp35
-rw-r--r--src/common/thread.h20
-rw-r--r--src/core/CMakeLists.txt4
-rw-r--r--src/core/core.cpp119
-rw-r--r--src/core/cpu_core_manager.cpp142
-rw-r--r--src/core/cpu_core_manager.h59
-rw-r--r--src/core/file_sys/control_metadata.cpp24
-rw-r--r--src/core/file_sys/patch_manager.cpp49
-rw-r--r--src/core/file_sys/registered_cache.cpp44
-rw-r--r--src/core/file_sys/registered_cache.h10
-rw-r--r--src/core/gdbstub/gdbstub.cpp123
-rw-r--r--src/core/hle/kernel/handle_table.cpp11
-rw-r--r--src/core/hle/kernel/handle_table.h15
-rw-r--r--src/core/hle/kernel/resource_limit.h6
-rw-r--r--src/core/hle/kernel/svc.cpp354
-rw-r--r--src/core/hle/kernel/svc_wrap.h8
-rw-r--r--src/core/hle/service/acc/acc.cpp22
-rw-r--r--src/core/hle/service/acc/profile_manager.cpp5
-rw-r--r--src/core/hle/service/acc/profile_manager.h14
-rw-r--r--src/core/hle/service/am/am.cpp236
-rw-r--r--src/core/hle/service/am/applet_ae.cpp66
-rw-r--r--src/core/hle/service/am/applet_oe.cpp27
-rw-r--r--src/core/hle/service/am/applets/stub_applet.cpp70
-rw-r--r--src/core/hle/service/am/applets/stub_applet.h24
-rw-r--r--src/core/hle/service/aoc/aoc_u.cpp6
-rw-r--r--src/core/hle/service/apm/interface.cpp16
-rw-r--r--src/core/hle/service/arp/arp.cpp4
-rw-r--r--src/core/hle/service/audio/audout_u.cpp33
-rw-r--r--src/core/hle/service/audio/audout_u.h3
-rw-r--r--src/core/hle/service/audio/audren_u.cpp53
-rw-r--r--src/core/hle/service/audio/hwopus.cpp46
-rw-r--r--src/core/hle/service/bcat/module.cpp3
-rw-r--r--src/core/hle/service/btdrv/btdrv.cpp3
-rw-r--r--src/core/hle/service/btm/btm.cpp19
-rw-r--r--src/core/hle/service/fgm/fgm.cpp4
-rw-r--r--src/core/hle/service/filesystem/filesystem.cpp5
-rw-r--r--src/core/hle/service/filesystem/filesystem.h1
-rw-r--r--src/core/hle/service/filesystem/fsp_srv.cpp15
-rw-r--r--src/core/hle/service/hid/controllers/debug_pad.cpp5
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp7
-rw-r--r--src/core/hle/service/hid/controllers/npad.h6
-rw-r--r--src/core/hle/service/hid/hid.cpp116
-rw-r--r--src/core/hle/service/hid/irs.cpp54
-rw-r--r--src/core/hle/service/lbl/lbl.cpp12
-rw-r--r--src/core/hle/service/ldn/ldn.cpp12
-rw-r--r--src/core/hle/service/ldr/ldr.cpp12
-rw-r--r--src/core/hle/service/lm/lm.cpp4
-rw-r--r--src/core/hle/service/mm/mm_u.cpp14
-rw-r--r--src/core/hle/service/nfc/nfc.cpp24
-rw-r--r--src/core/hle/service/nfp/nfp.cpp16
-rw-r--r--src/core/hle/service/nifm/nifm.cpp29
-rw-r--r--src/core/hle/service/nim/nim.cpp27
-rw-r--r--src/core/hle/service/ns/ns.cpp8
-rw-r--r--src/core/hle/service/ns/pl_u.cpp10
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp20
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h6
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp25
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp1
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp16
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp24
-rw-r--r--src/core/hle/service/nvdrv/interface.h2
-rw-r--r--src/core/hle/service/nvflinger/buffer_queue.cpp5
-rw-r--r--src/core/hle/service/pctl/module.cpp8
-rw-r--r--src/core/hle/service/pm/pm.cpp4
-rw-r--r--src/core/hle/service/psc/psc.cpp4
-rw-r--r--src/core/hle/service/set/set.cpp33
-rw-r--r--src/core/hle/service/set/set_sys.cpp8
-rw-r--r--src/core/hle/service/sm/controller.cpp11
-rw-r--r--src/core/hle/service/sm/sm.cpp58
-rw-r--r--src/core/hle/service/sm/sm.h3
-rw-r--r--src/core/hle/service/spl/module.cpp3
-rw-r--r--src/core/hle/service/ssl/ssl.cpp2
-rw-r--r--src/core/hle/service/time/time.cpp25
-rw-r--r--src/core/hle/service/usb/usb.cpp4
-rw-r--r--src/core/hle/service/vi/vi.cpp70
-rw-r--r--src/core/settings.h1
-rw-r--r--src/video_core/CMakeLists.txt7
-rw-r--r--src/video_core/command_processor.cpp3
-rw-r--r--src/video_core/command_processor.h53
-rw-r--r--src/video_core/dma_pusher.cpp123
-rw-r--r--src/video_core/dma_pusher.h99
-rw-r--r--src/video_core/engines/fermi_2d.cpp17
-rw-r--r--src/video_core/engines/fermi_2d.h2
-rw-r--r--src/video_core/engines/kepler_memory.cpp13
-rw-r--r--src/video_core/engines/kepler_memory.h3
-rw-r--r--src/video_core/engines/maxwell_3d.cpp51
-rw-r--r--src/video_core/engines/maxwell_3d.h91
-rw-r--r--src/video_core/engines/maxwell_compute.cpp8
-rw-r--r--src/video_core/engines/maxwell_compute.h3
-rw-r--r--src/video_core/engines/maxwell_dma.cpp13
-rw-r--r--src/video_core/engines/maxwell_dma.h2
-rw-r--r--src/video_core/engines/shader_bytecode.h27
-rw-r--r--src/video_core/engines/shader_header.h11
-rw-r--r--src/video_core/gpu.cpp53
-rw-r--r--src/video_core/gpu.h27
-rw-r--r--src/video_core/macro_interpreter.cpp31
-rw-r--r--src/video_core/macro_interpreter.h4
-rw-r--r--src/video_core/memory_manager.cpp7
-rw-r--r--src/video_core/memory_manager.h3
-rw-r--r--src/video_core/morton.cpp355
-rw-r--r--src/video_core/morton.h21
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.cpp3
-rw-r--r--src/video_core/renderer_opengl/gl_buffer_cache.h2
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp127
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h38
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.cpp244
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer_cache.h14
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.cpp1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_cache.h3
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp656
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp14
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.h1
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp10
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h9
-rw-r--r--src/video_core/renderer_opengl/gl_state.cpp124
-rw-r--r--src/video_core/renderer_opengl/gl_state.h27
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h5
-rw-r--r--src/video_core/renderer_opengl/renderer_opengl.cpp4
-rw-r--r--src/video_core/textures/decoders.cpp22
-rw-r--r--src/video_core/textures/decoders.h7
-rw-r--r--src/video_core/textures/texture.h2
-rw-r--r--src/video_core/utils.h164
-rw-r--r--src/yuzu/applets/software_keyboard.cpp16
-rw-r--r--src/yuzu/applets/software_keyboard.h7
-rw-r--r--src/yuzu/bootmanager.cpp2
-rw-r--r--src/yuzu/configuration/config.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.cpp2
-rw-r--r--src/yuzu/configuration/configure_debug.ui10
-rw-r--r--src/yuzu/configuration/configure_graphics.ui94
-rw-r--r--src/yuzu/configuration/configure_input.cpp44
-rw-r--r--src/yuzu/configuration/configure_input.h11
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp18
-rw-r--r--src/yuzu/configuration/configure_input_player.h53
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.cpp4
-rw-r--r--src/yuzu/configuration/configure_mouse_advanced.h36
-rw-r--r--src/yuzu/main.cpp28
-rw-r--r--src/yuzu_cmd/config.cpp1
-rw-r--r--src/yuzu_cmd/default_ini.h2
-rw-r--r--src/yuzu_cmd/emu_window/emu_window_sdl2.cpp16
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
15namespace Common {
16
17// Helper functions:
18
19#ifdef _MSC_VER
20template <typename T>
21static 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}
30static inline int LeastSignificantSetBit(u8 val) {
31 unsigned long index;
32 _BitScanForward(&index, val);
33 return (int)index;
34}
35static inline int LeastSignificantSetBit(u16 val) {
36 unsigned long index;
37 _BitScanForward(&index, val);
38 return (int)index;
39}
40static inline int LeastSignificantSetBit(u32 val) {
41 unsigned long index;
42 _BitScanForward(&index, val);
43 return (int)index;
44}
45static inline int LeastSignificantSetBit(u64 val) {
46 unsigned long index;
47 _BitScanForward64(&index, val);
48 return (int)index;
49}
50#else
51static inline int CountSetBits(u8 val) {
52 return __builtin_popcount(val);
53}
54static inline int CountSetBits(u16 val) {
55 return __builtin_popcount(val);
56}
57static inline int CountSetBits(u32 val) {
58 return __builtin_popcount(val);
59}
60static inline int CountSetBits(u64 val) {
61 return __builtin_popcountll(val);
62}
63static inline int LeastSignificantSetBit(u8 val) {
64 return __builtin_ctz(val);
65}
66static inline int LeastSignificantSetBit(u16 val) {
67 return __builtin_ctz(val);
68}
69static inline int LeastSignificantSetBit(u32 val) {
70 return __builtin_ctz(val);
71}
72static 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
97template <typename IntTy>
98class BitSet {
99 static_assert(!std::is_signed_v<IntTy>, "BitSet should not be used with signed types");
100
101public:
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
241typedef Common::BitSet<u8> BitSet8;
242typedef Common::BitSet<u16> BitSet16;
243typedef Common::BitSet<u32> BitSet32;
244typedef 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
26namespace Common { 26namespace Common {
27 27
28int 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
40void SleepCurrentThread(int ms) {
41 Sleep(ms);
42}
43#endif
44
45#ifdef _MSC_VER 28#ifdef _MSC_VER
46 29
47void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask) { 30void 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
65void SetCurrentThreadName(const char* szThreadName) { 48void 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
110void SleepCurrentThread(int ms) {
111 usleep(1000 * ms);
112}
113
114void SwitchCurrentThread() { 93void 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)
121void SetCurrentThreadName(const char* szThreadName) { 100void 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
14namespace Common { 14namespace Common {
15 15
16int CurrentThreadId();
17
18void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
19void SetCurrentThreadAffinity(u32 mask);
20
21class Event { 16class Event {
22public: 17public:
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
55private: 48private:
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
61class Barrier { 54class Barrier {
62public: 55public:
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:
80private: 73private:
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
88void SleepCurrentThread(int ms); 81void SetThreadAffinity(std::thread::native_handle_type thread, u32 mask);
82void SetCurrentThreadAffinity(u32 mask);
89void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms 83void SwitchCurrentThread(); // On Linux, this is equal to sleep 1ms
90void SetCurrentThreadName(const char* name); 84void 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
76void 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
83struct System::Impl { 76struct 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
336void System::InvalidateCpuInstructionCaches() { 264void System::InvalidateCpuInstructionCaches() {
337 for (auto& cpu : impl->cpu_cores) { 265 impl->cpu_core_manager.InvalidateAllInstructionCaches();
338 cpu->ArmInterface().ClearInstructionCache();
339 }
340} 266}
341 267
342System::ResultStatus System::Load(Frontend::EmuWindow& emu_window, const std::string& filepath) { 268System::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
346bool System::IsPoweredOn() const { 272bool System::IsPoweredOn() const {
347 return impl->cpu_barrier && impl->cpu_barrier->IsAlive(); 273 return impl->is_powered_on;
348} 274}
349 275
350void System::PrepareReschedule() { 276void System::PrepareReschedule() {
@@ -408,21 +334,20 @@ const ARM_Interface& System::ArmInterface(std::size_t core_index) const {
408} 334}
409 335
410Cpu& System::CpuCore(std::size_t core_index) { 336Cpu& 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
415const Cpu& System::CpuCore(std::size_t core_index) const { 340const 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
420ExclusiveMonitor& System::Monitor() { 345ExclusiveMonitor& System::Monitor() {
421 return *impl->cpu_exclusive_monitor; 346 return impl->cpu_core_manager.GetExclusiveMonitor();
422} 347}
423 348
424const ExclusiveMonitor& System::Monitor() const { 349const ExclusiveMonitor& System::Monitor() const {
425 return *impl->cpu_exclusive_monitor; 350 return impl->cpu_core_manager.GetExclusiveMonitor();
426} 351}
427 352
428Tegra::GPU& System::GPU() { 353Tegra::GPU& System::GPU() {
@@ -506,7 +431,7 @@ const Core::Frontend::SoftwareKeyboardApplet& System::GetSoftwareKeyboard() cons
506} 431}
507 432
508System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) { 433System::ResultStatus System::Init(Frontend::EmuWindow& emu_window) {
509 return impl->Init(emu_window); 434 return impl->Init(*this, emu_window);
510} 435}
511 436
512void System::Shutdown() { 437void 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
13namespace Core {
14namespace {
15void RunCpuCore(const System& system, Cpu& cpu_state) {
16 while (system.IsPoweredOn()) {
17 cpu_state.RunLoop(true);
18 }
19}
20} // Anonymous namespace
21
22CpuCoreManager::CpuCoreManager() = default;
23CpuCoreManager::~CpuCoreManager() = default;
24
25void 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
47void 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
65Cpu& CpuCoreManager::GetCore(std::size_t index) {
66 return *cores.at(index);
67}
68
69const Cpu& CpuCoreManager::GetCore(std::size_t index) const {
70 return *cores.at(index);
71}
72
73ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() {
74 return *exclusive_monitor;
75}
76
77const ExclusiveMonitor& CpuCoreManager::GetExclusiveMonitor() const {
78 return *exclusive_monitor;
79}
80
81Cpu& 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
93const 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
105void 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
136void 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
12namespace Core {
13
14class Cpu;
15class CpuBarrier;
16class ExclusiveMonitor;
17class System;
18
19class CpuCoreManager {
20public:
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
46private:
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
9namespace FileSys { 9namespace FileSys {
10 10
11const std::array<const char*, 15> LANGUAGE_NAMES = { 11const 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
19std::string LanguageEntry::GetApplicationName() const { 29std::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 {
26constexpr u64 SINGLE_BYTE_MODULUS = 0x100; 26constexpr u64 SINGLE_BYTE_MODULUS = 0x100;
27constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000; 27constexpr u64 DLC_BASE_TITLE_ID_MASK = 0xFFFFFFFFFFFFE000;
28 28
29constexpr 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
29struct NSOBuildHeader { 34struct 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
384static std::shared_ptr<NCA> GetNCAFromNSPForID(std::shared_ptr<NSP> nsp, const NcaID& id) { 384static 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
391InstallResult RegisteredCache::InstallEntry(std::shared_ptr<XCI> xci, bool overwrite_if_exists, 391InstallResult 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
396InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NSP> nsp, bool overwrite_if_exists, 396InstallResult 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
434InstallResult RegisteredCache::InstallEntry(std::shared_ptr<NCA> nca, TitleType type, 434InstallResult 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
457InstallResult RegisteredCache::RawInstallNCA(std::shared_ptr<NCA> nca, const VfsCopyFunction& copy, 457InstallResult 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
120private: 118private:
@@ -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;
71constexpr u32 UC_ARM64_REG_Q0 = 34; 71constexpr u32 UC_ARM64_REG_Q0 = 34;
72constexpr u32 FPCR_REGISTER = 66; 72constexpr u32 FPCR_REGISTER = 66;
73 73
74// TODO/WiP - Used while working on support for FPU
75constexpr u32 TODO_DUMMY_REG_997 = 997;
76constexpr 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
259static 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
275static 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 */
443static 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.
413static u8 ReadByte() { 460static 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) {
967static void Step() { 1014static 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
1323void SendTrap(Kernel::Thread* thread, int trap) { 1370void 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
14namespace Kernel { 14namespace Kernel {
15namespace {
16constexpr u16 GetSlot(Handle handle) {
17 return handle >> 15;
18}
19
20constexpr u16 GetGeneration(Handle handle) {
21 return handle & 0x7FFF;
22}
23} // Anonymous namespace
15 24
16HandleTable::HandleTable() { 25HandleTable::HandleTable() {
17 next_generation = 1; 26 next_generation = 1;
18 Clear(); 27 Clear();
19} 28}
20 29
30HandleTable::~HandleTable() = default;
31
21ResultVal<Handle> HandleTable::Create(SharedPtr<Object> obj) { 32ResultVal<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 {
43class HandleTable final : NonCopyable { 43class HandleTable final : NonCopyable {
44public: 44public:
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
91private: 92private:
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
15class KernelCore; 15class KernelCore;
16 16
17enum class ResourceType { 17enum 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
28constexpr bool IsValidResourceType(ResourceType type) {
29 return type < ResourceType::ResourceTypeCount;
30}
31
28class ResourceLimit final : public Object { 32class ResourceLimit final : public Object {
29public: 33public:
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
67constexpr 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.
69ResultCode MapUnmapMemorySanityChecks(const VMManager& vm_manager, VAddr dst_addr, VAddr src_addr, 72ResultCode 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
143enum class ResourceLimitValueType {
144 CurrentValue,
145 LimitValue,
146};
147
148ResultVal<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.
111static ResultCode SetHeapSize(VAddr* heap_addr, u64 heap_size) { 177static 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
208static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address) { 296static 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
720static ResultCode GetThreadPriority(u32* priority, Handle handle) { 850static 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
732static ResultCode SetThreadPriority(Handle handle, u32 priority) { 865static 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
826static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, 993static 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
874static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, 1042static 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
1154static u64 GetSystemTick() { 1340static 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
1237static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) { 1427static 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
1563static 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
1581static 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
1595static 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
1609static 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
1348namespace { 1644namespace {
1349struct FunctionDef { 1645struct 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
46template <ResultCode func(u32*)>
47void SvcWrap() {
48 u32 param = 0;
49 const u32 retval = func(&param).raw;
50 Core::CurrentArmInterface().SetReg(1, param);
51 FuncReturn(retval);
52}
53
46template <ResultCode func(u32*, u32)> 54template <ResultCode func(u32*, u32)>
47void SvcWrap() { 55void 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
22namespace Service::Account { 22namespace Service::Account {
23 23
24// TODO: RE this structure
25struct 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};
33static_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
37constexpr u32 backup_jpeg_size = 107; 26constexpr 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) {
216void Module::Interface::GetProfile(Kernel::HLERequestContext& ctx) { 207void 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
225void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) { 217void Module::Interface::IsUserRegistrationRequestPermitted(Kernel::HLERequestContext& ctx) {
@@ -236,10 +228,10 @@ void Module::Interface::InitializeApplicationInfo(Kernel::HLERequestContext& ctx
236} 228}
237 229
238void Module::Interface::GetBaasAccountManagerForApplication(Kernel::HLERequestContext& ctx) { 230void 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
245void Module::Interface::TrySelectUserWithoutInteraction(Kernel::HLERequestContext& ctx) { 237void 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};
23static_assert(sizeof(UserRaw) == 0xC8, "UserRaw has incorrect size."); 23static_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
14namespace Service::Account { 14namespace Service::Account {
15constexpr std::size_t MAX_USERS = 8; 15constexpr std::size_t MAX_USERS = 8;
16constexpr std::size_t MAX_DATA = 128;
17constexpr u128 INVALID_UUID{{0, 0}}; 16constexpr u128 INVALID_UUID{{0, 0}};
18 17
19struct UUID { 18struct UUID {
@@ -50,9 +49,20 @@ static_assert(sizeof(UUID) == 16, "UUID is an invalid size!");
50 49
51constexpr std::size_t profile_username_size = 32; 50constexpr std::size_t profile_username_size = 32;
52using ProfileUsername = std::array<u8, profile_username_size>; 51using ProfileUsername = std::array<u8, profile_username_size>;
53using ProfileData = std::array<u8, MAX_DATA>;
54using UserIDArray = std::array<UUID, MAX_USERS>; 52using UserIDArray = std::array<UUID, MAX_USERS>;
55 53
54/// Contains extra data related to a user.
55/// TODO: RE this structure
56struct 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};
64static_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
58struct ProfileInfo { 68struct 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;
216void ISelfController::SetFocusHandlingMode(Kernel::HLERequestContext& ctx) { 217void 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
235void ISelfController::SetRestartMessageEnabled(Kernel::HLERequestContext& ctx) { 235void 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
242void ISelfController::SetPerformanceModeChangedNotification(Kernel::HLERequestContext& ctx) { 242void 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
253void ISelfController::SetScreenShotPermission(Kernel::HLERequestContext& ctx) { 252void 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
260void ISelfController::SetOperationModeChangedNotification(Kernel::HLERequestContext& ctx) { 259void 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
271void ISelfController::SetOutOfFocusSuspendingEnabled(Kernel::HLERequestContext& ctx) { 269void 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
284void ISelfController::LockExit(Kernel::HLERequestContext& ctx) { 281void 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
291void ISelfController::UnlockExit(Kernel::HLERequestContext& ctx) { 288void 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
298void ISelfController::GetLibraryAppletLaunchableEvent(Kernel::HLERequestContext& ctx) { 295void 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
308void ISelfController::SetScreenShotImageOrientation(Kernel::HLERequestContext& ctx) { 305void 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
315void ISelfController::CreateManagedDisplayLayer(Kernel::HLERequestContext& ctx) { 312void 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
328void ISelfController::SetHandlesRequestToDisplay(Kernel::HLERequestContext& ctx) { 324void 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
335void ISelfController::SetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { 331void 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
344void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& ctx) { 341void 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
352AppletMessageQueue::AppletMessageQueue() { 349AppletMessageQueue::AppletMessageQueue() {
@@ -437,59 +434,63 @@ ICommonStateGetter::ICommonStateGetter(std::shared_ptr<AppletMessageQueue> msg_q
437ICommonStateGetter::~ICommonStateGetter() = default; 434ICommonStateGetter::~ICommonStateGetter() = default;
438 435
439void ICommonStateGetter::GetBootMode(Kernel::HLERequestContext& ctx) { 436void 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
448void ICommonStateGetter::GetEventHandle(Kernel::HLERequestContext& ctx) { 445void 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
456void ICommonStateGetter::ReceiveMessage(Kernel::HLERequestContext& ctx) { 453void 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
464void ICommonStateGetter::GetCurrentFocusState(Kernel::HLERequestContext& ctx) { 461void 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
472void ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent(Kernel::HLERequestContext& ctx) { 469void 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
480void ICommonStateGetter::GetDefaultDisplayResolution(Kernel::HLERequestContext& ctx) { 477void 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
495IStorage::IStorage(std::vector<u8> buffer) 496IStorage::IStorage(std::vector<u8> buffer)
@@ -512,21 +513,21 @@ const std::vector<u8>& IStorage::GetData() const {
512 513
513void ICommonStateGetter::GetOperationMode(Kernel::HLERequestContext& ctx) { 514void 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
522void ICommonStateGetter::GetPerformanceMode(Kernel::HLERequestContext& ctx) { 523void 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
532class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { 533class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
@@ -561,32 +562,34 @@ public:
561 562
562private: 563private:
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
674void IStorage::Open(Kernel::HLERequestContext& ctx) { 681void 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
683IStorageAccessor::IStorageAccessor(IStorage& storage) 690IStorageAccessor::IStorageAccessor(IStorage& storage)
@@ -696,21 +703,27 @@ IStorageAccessor::IStorageAccessor(IStorage& storage)
696IStorageAccessor::~IStorageAccessor() = default; 703IStorageAccessor::~IStorageAccessor() = default;
697 704
698void IStorageAccessor::GetSize(Kernel::HLERequestContext& ctx) { 705void 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
707void IStorageAccessor::Write(Kernel::HLERequestContext& ctx) { 714void 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
726void IStorageAccessor::Read(Kernel::HLERequestContext& ctx) { 737void 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
745ILibraryAppletCreator::ILibraryAppletCreator() : ServiceFramework("ILibraryAppletCreator") { 759ILibraryAppletCreator::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
793void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) { 808void 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
805void ILibraryAppletCreator::CreateTransferMemoryStorage(Kernel::HLERequestContext& ctx) { 820void 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
876IApplicationFunctions::~IApplicationFunctions() = default; 894IApplicationFunctions::~IApplicationFunctions() = default;
877 895
878void IApplicationFunctions::EnableApplicationCrashReport(Kernel::HLERequestContext& ctx) { 896void 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
884void IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed( 903void 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
891void IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed( 911void 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
898void IApplicationFunctions::BeginBlockingHomeButton(Kernel::HLERequestContext& ctx) { 919void 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
904void IApplicationFunctions::EndBlockingHomeButton(Kernel::HLERequestContext& ctx) { 926void 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
910void IApplicationFunctions::PopLaunchParameter(Kernel::HLERequestContext& ctx) { 933void 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(), &params, buffer.size()); 951 std::memcpy(buffer.data(), &params, 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
933void IApplicationFunctions::CreateApplicationAndRequestToStartForQuest( 956void 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
940void IApplicationFunctions::EnsureSaveData(Kernel::HLERequestContext& ctx) { 964void 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
965void IApplicationFunctions::GetDisplayVersion(Kernel::HLERequestContext& ctx) { 987void 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
973void IApplicationFunctions::GetDesiredLanguage(Kernel::HLERequestContext& ctx) { 996void 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
982void IApplicationFunctions::InitializeGamePlayRecording(Kernel::HLERequestContext& ctx) { 1006void 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
988void IApplicationFunctions::SetGamePlayRecordingState(Kernel::HLERequestContext& ctx) { 1013void 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
995void IApplicationFunctions::NotifyRunning(Kernel::HLERequestContext& ctx) { 1020void 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
1003void IApplicationFunctions::GetPseudoDeviceId(Kernel::HLERequestContext& ctx) { 1028void 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
1014void InstallInterfaces(SM::ServiceManager& service_manager, 1039void InstallInterfaces(SM::ServiceManager& service_manager,
@@ -1045,9 +1070,10 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions"
1045IHomeMenuFunctions::~IHomeMenuFunctions() = default; 1070IHomeMenuFunctions::~IHomeMenuFunctions() = default;
1046 1071
1047void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx) { 1072void 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
1053IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { 1079IGlobalStateController::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
33private: 33private:
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
123private: 132private:
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
197void AppletAE::OpenSystemAppletProxy(Kernel::HLERequestContext& ctx) { 216void 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
204void AppletAE::OpenLibraryAppletProxy(Kernel::HLERequestContext& ctx) { 224void 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
211void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) { 232void 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
218AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 240AppletAE::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
36private: 36private:
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
97void AppletOE::OpenApplicationProxy(Kernel::HLERequestContext& ctx) { 105void 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
104AppletOE::AppletOE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger, 113AppletOE::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
13namespace Service::AM::Applets {
14
15static 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
33StubApplet::StubApplet() = default;
34
35StubApplet::~StubApplet() = default;
36
37void StubApplet::Initialize() {
38 LOG_WARNING(Service_AM, "called (STUBBED)");
39 Applet::Initialize();
40 LogCurrentStorage(broker, "Initialize");
41}
42
43bool StubApplet::TransactionComplete() const {
44 LOG_WARNING(Service_AM, "called (STUBBED)");
45 return true;
46}
47
48ResultCode StubApplet::GetStatus() const {
49 LOG_WARNING(Service_AM, "called (STUBBED)");
50 return RESULT_SUCCESS;
51}
52
53void 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
62void 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
9namespace Service::AM::Applets {
10
11class StubApplet final : public Applet {
12public:
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
68AOC_U::~AOC_U() = default; 68AOC_U::~AOC_U() = default;
69 69
70void AOC_U::CountAddOnContent(Kernel::HLERequestContext& ctx) { 70void 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
112void AOC_U::GetAddOnContentBaseId(Kernel::HLERequestContext& ctx) { 115void 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)
73APM::~APM() = default; 71APM::~APM() = default;
74 72
75void APM::OpenSession(Kernel::HLERequestContext& ctx) { 73void 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
83APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} { 81APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
@@ -98,11 +96,11 @@ APM_Sys::APM_Sys() : ServiceFramework{"apm:sys"} {
98APM_Sys::~APM_Sys() = default; 96APM_Sys::~APM_Sys() = default;
99 97
100void APM_Sys::GetPerformanceEvent(Kernel::HLERequestContext& ctx) { 98void 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
60private: 60private:
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
45class IAudioOut final : public ServiceFramework<IAudioOut> { 45class IAudioOut final : public ServiceFramework<IAudioOut> {
46public: 46public:
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
75private: 77private:
@@ -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
187void AudOutU::ListAudioOutsImpl(Kernel::HLERequestContext& ctx) { 194void 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) {
199void AudOutU::OpenAudioOutImpl(Kernel::HLERequestContext& ctx) { 207void 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
229AudOutU::AudOutU() : ServiceFramework("audout:u") { 246AudOutU::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
9namespace AudioCore { 10namespace AudioCore {
@@ -24,7 +25,7 @@ public:
24 ~AudOutU() override; 25 ~AudOutU() override;
25 26
26private: 27private:
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") {
235AudRenU::~AudRenU() = default; 241AudRenU::~AudRenU() = default;
236 242
237void AudRenU::OpenAudioRenderer(Kernel::HLERequestContext& ctx) { 243void 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
248void AudRenU::GetAudioRendererWorkBufferSize(Kernel::HLERequestContext& ctx) { 254void 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
307void AudRenU::GetAudioDevice(Kernel::HLERequestContext& ctx) { 314void 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
316void AudRenU::GetAudioDeviceServiceWithRevisionInfo(Kernel::HLERequestContext& ctx) { 323void 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
326bool AudRenU::IsFeatureSupported(AudioFeatures feature, u32_le revision) const { 333bool 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
47private: 47private:
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
135void HwOpus::GetWorkBufferSize(Kernel::HLERequestContext& ctx) { 156void 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
35void Module::Interface::CreateBcatService(Kernel::HLERequestContext& ctx) { 35void 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
42Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 43Module::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
35private: 35private:
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
58private: 58private:
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
112private: 116private:
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
210private: 215private:
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
43private: 43private:
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
344void ClearUnionContents() {
345 registered_cache_union = nullptr;
346}
347
344FileSys::RegisteredCache* GetSystemNANDContents() { 348FileSys::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)
49ResultVal<FileSys::VirtualDir> OpenSDMC(); 49ResultVal<FileSys::VirtualDir> OpenSDMC();
50 50
51std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents(); 51std::shared_ptr<FileSys::RegisteredCacheUnion> GetUnionContents();
52void ClearUnionContents();
52 53
53FileSys::RegisteredCache* GetSystemNANDContents(); 54FileSys::RegisteredCache* GetSystemNANDContents();
54FileSys::RegisteredCache* GetUserNANDContents(); 55FileSys::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) {
763void FSP_SRV::OpenSaveDataInfoReaderBySaveDataSpaceId(Kernel::HLERequestContext& ctx) { 775void 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
72void Controller_DebugPad::OnLoadInputDevices() { 72void 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
525void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids, 525void 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
582void Controller_NPad::ConnectNPad(u32 npad_id) { 583void 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
125private: 125private:
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
164private: 165private:
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
46void IRS::ActivateIrsensor(Kernel::HLERequestContext& ctx) { 46void 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
52void IRS::DeactivateIrsensor(Kernel::HLERequestContext& ctx) { 53void 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
58void IRS::GetIrsensorSharedMemoryHandle(Kernel::HLERequestContext& ctx) { 60void 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
65void IRS::StopImageProcessor(Kernel::HLERequestContext& ctx) { 68void 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
71void IRS::RunMomentProcessor(Kernel::HLERequestContext& ctx) { 75void 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
77void IRS::RunClusteringProcessor(Kernel::HLERequestContext& ctx) { 82void 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
83void IRS::RunImageTransferProcessor(Kernel::HLERequestContext& ctx) { 89void 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
89void IRS::GetImageTransferProcessorState(Kernel::HLERequestContext& ctx) { 96void 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
97void IRS::RunTeraPluginProcessor(Kernel::HLERequestContext& ctx) { 105void 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
103void IRS::GetNpadIrCameraHandle(Kernel::HLERequestContext& ctx) { 112void 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
110void IRS::RunPointingProcessor(Kernel::HLERequestContext& ctx) { 120void 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
116void IRS::SuspendImageProcessor(Kernel::HLERequestContext& ctx) { 127void 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
122void IRS::CheckFirmwareVersion(Kernel::HLERequestContext& ctx) { 134void 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
128void IRS::SetFunctionLevel(Kernel::HLERequestContext& ctx) { 141void 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
134void IRS::RunImageTransferExProcessor(Kernel::HLERequestContext& ctx) { 148void 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
140void IRS::RunIrLedProcessor(Kernel::HLERequestContext& ctx) { 155void 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
146void IRS::StopImageProcessorAsync(Kernel::HLERequestContext& ctx) { 162void 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
152void IRS::ActivateIrsensorWithFunctionLevel(Kernel::HLERequestContext& ctx) { 169void 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
158IRS::~IRS() = default; 176IRS::~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
56private: 56private:
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
403private: 413private:
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:
31private: 31private:
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
44private: 44private:
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
92private: 92private:
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
184private: 184private:
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
242private: 242private:
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
324void Module::Interface::CreateUserInterface(Kernel::HLERequestContext& ctx) { 327void 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:
63private: 63private:
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
209private: 215private:
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:
433private: 433private:
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
527private: 527private:
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) {
288void PL_U::GetLoadState(Kernel::HLERequestContext& ctx) { 289void 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) {
298void PL_U::GetSize(Kernel::HLERequestContext& ctx) { 299void 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) {
308void PL_U::GetSharedMemoryAddressOffset(Kernel::HLERequestContext& ctx) { 309void 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
318void PL_U::GetSharedMemoryNativeHandle(Kernel::HLERequestContext& ctx) { 319void 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(&params, input.data(), input.size()); 55 std::memcpy(&params, 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(&params, input.data(), input.size()); 193 std::memcpy(&params, 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
10namespace Service::Nvidia::Devices { 12namespace 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
100u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { 104u32 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(&params, input.data(), input.size()); 109 std::memcpy(&params, input.data(), input.size());
@@ -111,6 +116,7 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector
111 116
112u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { 117u32 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(&params, input.data(), input.size()); 122 std::memcpy(&params, input.data(), input.size());
@@ -122,6 +128,7 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
122 128
123u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { 129u32 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
145u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { 152u32 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(&params, input.data(), input.size()); 156 std::memcpy(&params, 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
154u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { 162u32 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(&params, input.data(), input.size()); 166 std::memcpy(&params, 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
163u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { 172u32 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(&params, input.data(), input.size()); 176 std::memcpy(&params, 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
182u32 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(&params, input.data(), input.size());
187 params.gpu_time = CoreTiming::cyclesToNs(CoreTiming::GetTicks());
188 std::memcpy(output.data(), &params, 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(&params, input.data(), input.size()); 61 std::memcpy(&params, 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
68u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { 68u32 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(&params, input.data(), input.size()); 72 std::memcpy(&params, 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
76u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { 77u32 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(&params, input.data(), input.size()); 81 std::memcpy(&params, 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(&params, input.data(), input.size()); 98 std::memcpy(&params, 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(), &params, output.size()); 102 std::memcpy(output.data(), &params, 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>&
102u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { 106u32 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(), &params, output.size()); 124 std::memcpy(output.data(), &params, output.size());
@@ -124,11 +130,18 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<
124 std::memcpy(&params, input.data(), input.size()); 130 std::memcpy(&params, 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(), &params, output.size()); 135 std::memcpy(output.data(), &params, output.size());
129 return 0; 136 return 0;
130} 137}
131 138
139static 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
132u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { 145u32 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(&params, input.data(), sizeof(IoctlGetWaitbase)); 193 std::memcpy(&params, 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(), &params, output.size()); 197 std::memcpy(output.data(), &params, 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(&params, input.data(), sizeof(IoctlChannelSetTimeout)); 203 std::memcpy(&params, 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(&params, input.data(), input.size()); 31 std::memcpy(&params, 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(&params, input.data(), input.size()); 31 std::memcpy(&params, 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(&params, input.data(), input.size()); 31 std::memcpy(&params, 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
56void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { 56void 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) {
75void NVDRV::SetClientPID(Kernel::HLERequestContext& ctx) { 76void 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
85void NVDRV::FinishInitialize(Kernel::HLERequestContext& ctx) { 86void 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
93void 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
100void 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) {
20BufferQueue::~BufferQueue() = default; 20BufferQueue::~BufferQueue() = default;
21 21
22void BufferQueue::SetPreallocatedBuffer(u32 slot, const IGBPBuffer& igbp_buffer) { 22void 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
93u32 BufferQueue::Query(QueryType type) { 93u32 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:
114private: 114private:
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
128void Module::Interface::CreateService(Kernel::HLERequestContext& ctx) { 130void 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
135void Module::Interface::CreateServiceWithoutInitialize(Kernel::HLERequestContext& ctx) { 138void 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
142Module::Interface::Interface(std::shared_ptr<Module> module, const char* name) 146Module::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
21private: 21private:
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
62private: 62private:
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() {
49static void PushResponseLanguageCode(Kernel::HLERequestContext& ctx, std::size_t max_size) { 49static 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
58void SET::GetAvailableLanguageCodes(Kernel::HLERequestContext& ctx) { 59void 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
69void SET::GetAvailableLanguageCodes2(Kernel::HLERequestContext& ctx) { 70void 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
80void SET::GetAvailableLanguageCodeCount(Kernel::HLERequestContext& ctx) { 81void 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
86void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) { 87void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
@@ -90,11 +91,11 @@ void SET::GetAvailableLanguageCodeCount2(Kernel::HLERequestContext& ctx) {
90} 91}
91 92
92void SET::GetLanguageCode(Kernel::HLERequestContext& ctx) { 93void 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
100SET::SET() : ServiceFramework("set") { 101SET::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 @@
10namespace Service::Set { 10namespace Service::Set {
11 11
12void SET_SYS::GetColorSetId(Kernel::HLERequestContext& ctx) { 12void 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
21void SET_SYS::SetColorSetId(Kernel::HLERequestContext& ctx) { 21void 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
31SET_SYS::SET_SYS() : ServiceFramework("set:sys") { 31SET_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
15void Controller::ConvertSessionToDomain(Kernel::HLERequestContext& ctx) { 15void 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
26void Controller::DuplicateSession(Kernel::HLERequestContext& ctx) { 25void 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
38void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) { 39void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
@@ -42,11 +43,11 @@ void Controller::DuplicateSessionEx(Kernel::HLERequestContext& ctx) {
42} 43}
43 44
44void Controller::QueryPointerBufferSize(Kernel::HLERequestContext& ctx) { 45void 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
52Controller::Controller() : ServiceFramework("IpcController") { 53Controller::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
66ResultCode 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
66ResultVal<Kernel::SharedPtr<Kernel::ClientPort>> ServiceManager::GetServicePort( 77ResultVal<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 */
94void SM::Initialize(Kernel::HLERequestContext& ctx) { 105void 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
100void SM::GetService(Kernel::HLERequestContext& ctx) { 112void SM::GetService(Kernel::HLERequestContext& ctx) {
@@ -127,13 +139,53 @@ void SM::GetService(Kernel::HLERequestContext& ctx) {
127 } 139 }
128} 140}
129 141
142void 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
169void 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
130SM::SM(std::shared_ptr<ServiceManager> service_manager) 182SM::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:
35private: 35private:
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)
24Module::Interface::~Interface() = default; 24Module::Interface::~Interface() = default;
25 25
26void Module::Interface::GetRandomBytes(Kernel::HLERequestContext& ctx) { 26void 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
42void InstallInterfaces(SM::ServiceManager& service_manager) { 43void 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:
69private: 69private:
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:
98private: 100private:
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
218void Module::Interface::GetStandardUserSystemClock(Kernel::HLERequestContext& ctx) { 223void 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
225void Module::Interface::GetStandardNetworkSystemClock(Kernel::HLERequestContext& ctx) { 231void 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
232void Module::Interface::GetStandardSteadyClock(Kernel::HLERequestContext& ctx) { 239void 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
239void Module::Interface::GetTimeZoneService(Kernel::HLERequestContext& ctx) { 247void 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
246void Module::Interface::GetStandardLocalSystemClock(Kernel::HLERequestContext& ctx) { 255void 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
253void Module::Interface::GetClockSnapshot(Kernel::HLERequestContext& ctx) { 263void 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
160private: 160private:
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:
669private: 672private:
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:
785private: 794private:
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 @@
1add_library(video_core STATIC 1add_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
34void GPU::ProcessCommandLists(const std::vector<CommandListHeader>& commands) { 34void 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
12namespace Tegra {
13
14enum class SubmissionMode : u32 {
15 IncreasingOld = 0,
16 Increasing = 1,
17 NonIncreasingOld = 2,
18 NonIncreasing = 3,
19 Inline = 4,
20 IncreaseOnce = 5
21};
22
23struct 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};
37static_assert(sizeof(CommandListHeader) == 8, "CommandListHeader is incorrect size");
38
39union 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};
50static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout");
51static_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
12namespace Tegra {
13
14DmaPusher::DmaPusher(GPU& gpu) : gpu(gpu) {}
15
16DmaPusher::~DmaPusher() = default;
17
18MICROPROFILE_DEFINE(DispatchCalls, "GPU", "Execute command buffer", MP_RGB(128, 128, 192));
19
20void 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
35bool 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
113void 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
119void 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
14namespace Tegra {
15
16enum class SubmissionMode : u32 {
17 IncreasingOld = 0,
18 Increasing = 1,
19 NonIncreasingOld = 2,
20 NonIncreasing = 3,
21 Inline = 4,
22 IncreaseOnce = 5
23};
24
25struct 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};
33static_assert(sizeof(CommandListHeader) == sizeof(u64), "CommandListHeader is incorrect size");
34
35union 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};
44static_assert(std::is_standard_layout_v<CommandHeader>, "CommandHeader is not standard layout");
45static_assert(sizeof(CommandHeader) == sizeof(u32), "CommandHeader has incorrect size!");
46
47class GPU;
48
49using 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 */
58class DmaPusher {
59public:
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
69private:
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 {
12Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) 14Fermi2D::Fermi2D(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager)
13 : memory_manager(memory_manager), rasterizer{rasterizer} {} 15 : memory_manager(memory_manager), rasterizer{rasterizer} {}
14 16
15void Fermi2D::WriteReg(u32 method, u32 value) { 17void 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
10namespace Tegra::Engines { 12namespace Tegra::Engines {
@@ -15,19 +17,19 @@ KeplerMemory::KeplerMemory(VideoCore::RasterizerInterface& rasterizer,
15 17
16KeplerMemory::~KeplerMemory() = default; 18KeplerMemory::~KeplerMemory() = default;
17 19
18void KeplerMemory::WriteReg(u32 method, u32 value) { 20void 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
14namespace VideoCore { 15namespace 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
100void Maxwell3D::WriteReg(u32 method, u32 value, u32 remaining_params) { 100void 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);
1120ASSERT_REG_POSITION(clear_color[0], 0x360); 1184ASSERT_REG_POSITION(clear_color[0], 0x360);
1121ASSERT_REG_POSITION(clear_depth, 0x364); 1185ASSERT_REG_POSITION(clear_depth, 0x364);
1122ASSERT_REG_POSITION(clear_stencil, 0x368); 1186ASSERT_REG_POSITION(clear_stencil, 0x368);
1187ASSERT_REG_POSITION(polygon_offset_point_enable, 0x370);
1188ASSERT_REG_POSITION(polygon_offset_line_enable, 0x371);
1189ASSERT_REG_POSITION(polygon_offset_fill_enable, 0x372);
1123ASSERT_REG_POSITION(scissor_test, 0x380); 1190ASSERT_REG_POSITION(scissor_test, 0x380);
1124ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5); 1191ASSERT_REG_POSITION(stencil_back_func_ref, 0x3D5);
1125ASSERT_REG_POSITION(stencil_back_mask, 0x3D6); 1192ASSERT_REG_POSITION(stencil_back_mask, 0x3D6);
@@ -1127,6 +1194,7 @@ ASSERT_REG_POSITION(stencil_back_func_mask, 0x3D7);
1127ASSERT_REG_POSITION(color_mask_common, 0x3E4); 1194ASSERT_REG_POSITION(color_mask_common, 0x3E4);
1128ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB); 1195ASSERT_REG_POSITION(rt_separate_frag_data, 0x3EB);
1129ASSERT_REG_POSITION(zeta, 0x3F8); 1196ASSERT_REG_POSITION(zeta, 0x3F8);
1197ASSERT_REG_POSITION(clear_flags, 0x43E);
1130ASSERT_REG_POSITION(vertex_attrib_format, 0x458); 1198ASSERT_REG_POSITION(vertex_attrib_format, 0x458);
1131ASSERT_REG_POSITION(rt_control, 0x487); 1199ASSERT_REG_POSITION(rt_control, 0x487);
1132ASSERT_REG_POSITION(zeta_width, 0x48a); 1200ASSERT_REG_POSITION(zeta_width, 0x48a);
@@ -1153,10 +1221,12 @@ ASSERT_REG_POSITION(stencil_front_mask, 0x4E7);
1153ASSERT_REG_POSITION(frag_color_clamp, 0x4EA); 1221ASSERT_REG_POSITION(frag_color_clamp, 0x4EA);
1154ASSERT_REG_POSITION(screen_y_control, 0x4EB); 1222ASSERT_REG_POSITION(screen_y_control, 0x4EB);
1155ASSERT_REG_POSITION(vb_element_base, 0x50D); 1223ASSERT_REG_POSITION(vb_element_base, 0x50D);
1224ASSERT_REG_POSITION(clip_distance_enabled, 0x544);
1156ASSERT_REG_POSITION(point_size, 0x546); 1225ASSERT_REG_POSITION(point_size, 0x546);
1157ASSERT_REG_POSITION(zeta_enable, 0x54E); 1226ASSERT_REG_POSITION(zeta_enable, 0x54E);
1158ASSERT_REG_POSITION(multisample_control, 0x54F); 1227ASSERT_REG_POSITION(multisample_control, 0x54F);
1159ASSERT_REG_POSITION(tsc, 0x557); 1228ASSERT_REG_POSITION(tsc, 0x557);
1229ASSERT_REG_POSITION(polygon_offset_factor, 0x55b);
1160ASSERT_REG_POSITION(tic, 0x55D); 1230ASSERT_REG_POSITION(tic, 0x55D);
1161ASSERT_REG_POSITION(stencil_two_side_enable, 0x565); 1231ASSERT_REG_POSITION(stencil_two_side_enable, 0x565);
1162ASSERT_REG_POSITION(stencil_back_op_fail, 0x566); 1232ASSERT_REG_POSITION(stencil_back_op_fail, 0x566);
@@ -1164,13 +1234,18 @@ ASSERT_REG_POSITION(stencil_back_op_zfail, 0x567);
1164ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568); 1234ASSERT_REG_POSITION(stencil_back_op_zpass, 0x568);
1165ASSERT_REG_POSITION(stencil_back_func_func, 0x569); 1235ASSERT_REG_POSITION(stencil_back_func_func, 0x569);
1166ASSERT_REG_POSITION(framebuffer_srgb, 0x56E); 1236ASSERT_REG_POSITION(framebuffer_srgb, 0x56E);
1237ASSERT_REG_POSITION(polygon_offset_units, 0x56F);
1167ASSERT_REG_POSITION(point_coord_replace, 0x581); 1238ASSERT_REG_POSITION(point_coord_replace, 0x581);
1168ASSERT_REG_POSITION(code_address, 0x582); 1239ASSERT_REG_POSITION(code_address, 0x582);
1169ASSERT_REG_POSITION(draw, 0x585); 1240ASSERT_REG_POSITION(draw, 0x585);
1170ASSERT_REG_POSITION(primitive_restart, 0x591); 1241ASSERT_REG_POSITION(primitive_restart, 0x591);
1171ASSERT_REG_POSITION(index_array, 0x5F2); 1242ASSERT_REG_POSITION(index_array, 0x5F2);
1243ASSERT_REG_POSITION(polygon_offset_clamp, 0x61F);
1172ASSERT_REG_POSITION(instanced_arrays, 0x620); 1244ASSERT_REG_POSITION(instanced_arrays, 0x620);
1173ASSERT_REG_POSITION(cull, 0x646); 1245ASSERT_REG_POSITION(cull, 0x646);
1246ASSERT_REG_POSITION(pixel_center_integer, 0x649);
1247ASSERT_REG_POSITION(viewport_transform_enabled, 0x64B);
1248ASSERT_REG_POSITION(view_volume_clip_control, 0x64F);
1174ASSERT_REG_POSITION(logic_op, 0x671); 1249ASSERT_REG_POSITION(logic_op, 0x671);
1175ASSERT_REG_POSITION(clear_buffers, 0x674); 1250ASSERT_REG_POSITION(clear_buffers, 0x674);
1176ASSERT_REG_POSITION(color_mask, 0x680); 1251ASSERT_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
9namespace Tegra::Engines { 9namespace Tegra::Engines {
10 10
11void MaxwellCompute::WriteReg(u32 method, u32 value) { 11void 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
13namespace Tegra::Engines { 14namespace 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 {
12MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) 14MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager)
13 : memory_manager(memory_manager), rasterizer{rasterizer} {} 15 : memory_manager(memory_manager), rasterizer{rasterizer} {}
14 16
15void MaxwellDMA::WriteReg(u32 method, u32 value) { 17void 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
264enum class ControlCode : u64 { 267enum 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
371enum class R2pMode : u64 {
372 Pr = 0,
373 Cc = 1,
374};
375
368enum class IpaInterpMode : u64 { 376enum 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
27GPU::GPU(VideoCore::RasterizerInterface& rasterizer) { 27GPU::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
55DmaPusher& GPU::DmaPusher() {
56 return *dma_pusher;
57}
58
59const DmaPusher& GPU::DmaPusher() const {
60 return *dma_pusher;
61}
62
54u32 RenderTargetBytesPerPixel(RenderTargetFormat format) { 63u32 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
125enum class BufferMethods {
126 BindObject = 0,
127 CountBufferMethods = 0x40,
128};
129
130void 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
14namespace VideoCore { 15namespace 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
137private: 159private:
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
40bool MacroInterpreter::Step(u32 offset, bool is_delay_slot) { 41bool 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
138u32 MacroInterpreter::GetALUResult(ALUOperation operation, u32 src_a, u32 src_b) const { 139u32 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
237void MacroInterpreter::Send(u32 value) { 252void 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
10namespace Tegra { 10namespace Tegra {
11 11
12MemoryManager::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
12GPUVAddr MemoryManager::AllocateSpace(u64 size, u64 align) { 19GPUVAddr 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
19class MemoryManager final { 19class MemoryManager final {
20public: 20public:
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
14namespace VideoCore {
15
16using Surface::GetBytesPerPixel;
17using Surface::PixelFormat;
18
19using MortonCopyFn = void (*)(u32, u32, u32, u32, u32, u32, u8*, std::size_t, VAddr);
20using ConversionArray = std::array<MortonCopyFn, Surface::MaxPixelFormat>;
21
22template <bool morton_to_linear, PixelFormat format>
23static 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
44static 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
115static 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
187static 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
198static 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
205static 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
236static 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
315static 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
329void 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
337void 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
10namespace VideoCore {
11
12enum class MortonSwizzleMode { MortonToLinear, LinearToMorton };
13
14void 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
18void 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
79void OGLBufferCache::Map(std::size_t max_size) { 79bool 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
90void OGLBufferCache::Unmap() { 91void 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
123RasterizerOpenGL::~RasterizerOpenGL() {} 119RasterizerOpenGL::~RasterizerOpenGL() {}
124 120
121void 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
125void RasterizerOpenGL::SetupVertexFormat() { 134void 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
186void RasterizerOpenGL::SetupVertexBuffer() { 198void 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
221DrawParameters RasterizerOpenGL::SetupDraw() { 242DrawParameters 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
943void RasterizerOpenGL::SyncViewport(OpenGLState& current_state) { 1001void 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
957void RasterizerOpenGL::SyncClipEnabled() { 1022void 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
961void RasterizerOpenGL::SyncClipCoef() { 1034void 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
1123void RasterizerOpenGL::SyncScissorTest() { 1196void 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
1232void 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
1155void RasterizerOpenGL::CheckAlphaTests() { 1242void 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
27namespace OpenGL { 27namespace OpenGL {
28 28
29using VideoCore::MortonSwizzle;
30using VideoCore::MortonSwizzleMode;
29using VideoCore::Surface::ComponentTypeFromDepthFormat; 31using VideoCore::Surface::ComponentTypeFromDepthFormat;
30using VideoCore::Surface::ComponentTypeFromRenderTarget; 32using VideoCore::Surface::ComponentTypeFromRenderTarget;
31using VideoCore::Surface::ComponentTypeFromTexture; 33using 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
373template <bool morton_to_gl, PixelFormat format> 379void SwizzleFunc(const MortonSwizzleMode& mode, const SurfaceParams& params,
374void 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
394using GLConversionArray = std::array<void (*)(u32, u32, u32, u32, u32, u8*, std::size_t, VAddr),
395 VideoCore::Surface::MaxPixelFormat>;
396
397static 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
468static 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
540void 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
1117void 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
1278void RasterizerCacheOpenGL::FermiCopySurface( 1142void 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);
34constexpr u32 MAX_GEOMETRY_BUFFERS = 6; 34constexpr u32 MAX_GEOMETRY_BUFFERS = 6;
35constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested 35constexpr u32 MAX_ATTRIBUTES = 0x100; // Size in vec4s, this value is untested
36 36
37static const char* INTERNAL_FLAG_NAMES[] = {"zero_flag", "sign_flag", "carry_flag",
38 "overflow_flag"};
39
40enum class InternalFlag : u64 {
41 ZeroFlag = 0,
42 SignFlag = 1,
43 CarryFlag = 2,
44 OverflowFlag = 3,
45 Amount
46};
47
37class DecompileFail : public std::runtime_error { 48class DecompileFail : public std::runtime_error {
38public: 49public:
39 using std::runtime_error::runtime_error; 50 using std::runtime_error::runtime_error;
@@ -84,7 +95,8 @@ struct Subroutine {
84class ControlFlowAnalyzer { 95class ControlFlowAnalyzer {
85public: 96public:
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
99private: 115private:
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
260enum 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:
939class GLSLGenerator { 981class GLSLGenerator {
940public: 982public:
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
960private: 1003private:
@@ -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
25layout(std140) uniform vs_config { 25layout(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
102layout (std140) uniform gs_config { 102layout (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
140layout (std140) uniform fs_config { 139layout (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:
163struct ShaderEntries { 163struct 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
168using ProgramResult = std::pair<std::string, ShaderEntries>; 169using 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;
21struct MaxwellUniformData { 21struct 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};
33static_assert(sizeof(MaxwellUniformData) == 64, "MaxwellUniformData structure size is incorrect"); 36static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect");
34static_assert(sizeof(MaxwellUniformData) < 16384, 37static_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
97void OpenGLState::ApplyDefaultState() { 105void OpenGLState::ApplyDefaultState() {
@@ -140,7 +148,7 @@ void OpenGLState::ApplyCulling() const {
140} 148}
141 149
142void OpenGLState::ApplyColorMask() const { 150void 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
245void 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
237void OpenGLState::ApplyViewport() const { 267void 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
417void 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
386void OpenGLState::ApplyTextures() const { 466void 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
529void 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
449void OpenGLState::Apply() const { 544void 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
210private: 225private:
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) {
218inline GLenum BlendEquation(Maxwell::Blend::Equation equation) { 218inline 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
26namespace OpenGL { 26namespace 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
127template <bool fast> 127template <bool fast>
128void SwizzledData(u8* const swizzled_data, u8* const unswizzled_data, const bool unswizzle, 128void 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
170void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel, 172void 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
229void UnswizzleTexture(u8* const unswizzled_data, VAddr address, u32 tile_size_x, u32 tile_size_y, 233void 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
238std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y, 242std::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() {
22void UnswizzleTexture(u8* unswizzled_data, VAddr address, u32 tile_size_x, u32 tile_size_y, 22void 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 */
29std::vector<u8> UnswizzleTexture(VAddr address, u32 tile_size_x, u32 tile_size_y, 29std::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.
35void CopySwizzledData(u32 width, u32 height, u32 depth, u32 bytes_per_pixel, 36void 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
9namespace VideoCore {
10
11// 8x8 Z-Order coordinate from 2D coordinates
12static 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 */
21static 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
52static 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
131static 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
145static 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
97QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default; 97QtSoftwareKeyboardDialog::~QtSoftwareKeyboardDialog() = default;
98 98
99void QtSoftwareKeyboardDialog::Submit() { 99void 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
105void QtSoftwareKeyboardDialog::Reject() { 105void QtSoftwareKeyboardDialog::reject() {
106 ok = false; 106 ok = false;
107 text.clear(); 107 text.clear();
108 accept(); 108 QDialog::reject();
109} 109}
110 110
111std::u16string QtSoftwareKeyboardDialog::GetText() const { 111std::u16string QtSoftwareKeyboardDialog::GetText() const {
@@ -129,13 +129,13 @@ QtSoftwareKeyboard::~QtSoftwareKeyboard() = default;
129 129
130void QtSoftwareKeyboard::RequestText(std::function<void(std::optional<std::u16string>)> out, 130void 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
136void QtSoftwareKeyboard::SendTextCheckDialog(std::u16string error_message, 136void 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
73public slots: 73private:
74 void MainWindowFinishedText(std::optional<std::u16string> text); 74 void MainWindowFinishedText(std::optional<std::u16string> text);
75 void MainWindowFinishedCheckDialog(); 75 void MainWindowFinishedCheckDialog();
76 76
77private:
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
23namespace {
24template <typename Dialog, typename... Args>
25void 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
29ConfigureInput::ConfigureInput(QWidget* parent) 36ConfigureInput::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
84template <typename Dialog, typename... Args>
85void 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
95void ConfigureInput::OnDockedModeChanged(bool last_state, bool new_state) { 91void 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
23class QPushButton; 15class QPushButton;
24class QString; 16class QString;
@@ -40,9 +32,6 @@ public:
40private: 32private:
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
28static 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
35static void LayerGridElements(QGridLayout* grid, QWidget* item, QWidget* onTopOf) { 28static 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
114ConfigureInputPlayer::ConfigureInputPlayer(QWidget* parent, u8 player_index, bool debug) 107ConfigureInputPlayer::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
31public: 32public:
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
38private: 39private:
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
13class QCheckBox; 13class QCheckBox;
@@ -28,23 +28,6 @@ public:
28 void applyConfiguration(); 28 void applyConfiguration();
29 29
30private: 30private:
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) {
518QStringList GMainWindow::GetUnsupportedGLExtensions() { 518QStringList 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.
207use_gdbstub=false 207use_gdbstub=false
208gdbstub_port=24689 208gdbstub_port=24689
209# Determines whether or not yuzu will dump the ExeFS of all games it attempts to load while loading them
210dump_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
210dump_nso=false 212dump_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() {
111bool EmuWindow_SDL2::SupportsRequiredGLExtensions() { 111bool 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);