summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/CMakeLists.txt2
-rw-r--r--src/common/file_util.cpp13
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/common/memory_util.cpp177
-rw-r--r--src/common/memory_util.h21
-rw-r--r--src/core/CMakeLists.txt6
-rw-r--r--src/core/hle/kernel/hle_ipc.cpp25
-rw-r--r--src/core/hle/kernel/hle_ipc.h13
-rw-r--r--src/core/hle/kernel/kernel.cpp10
-rw-r--r--src/core/hle/kernel/kernel.h6
-rw-r--r--src/core/hle/kernel/process.h14
-rw-r--r--src/core/hle/kernel/server_session.cpp3
-rw-r--r--src/core/hle/kernel/svc.cpp122
-rw-r--r--src/core/hle/kernel/thread.cpp2
-rw-r--r--src/core/hle/service/am/am.cpp64
-rw-r--r--src/core/hle/service/am/applet_ae.cpp4
-rw-r--r--src/core/hle/service/am/applet_oe.cpp3
-rw-r--r--src/core/hle/service/am/idle.cpp6
-rw-r--r--src/core/hle/service/am/tcap.cpp23
-rw-r--r--src/core/hle/service/am/tcap.h17
-rw-r--r--src/core/hle/service/hid/controllers/npad.cpp191
-rw-r--r--src/core/hle/service/hid/controllers/npad.h2
-rw-r--r--src/core/hle/service/hid/hid.cpp1
-rw-r--r--src/core/hle/service/lbl/lbl.cpp56
-rw-r--r--src/core/hle/service/npns/npns.cpp88
-rw-r--r--src/core/hle/service/npns/npns.h15
-rw-r--r--src/core/hle/service/prepo/prepo.cpp21
-rw-r--r--src/core/hle/service/ptm/psm.cpp71
-rw-r--r--src/core/hle/service/ptm/psm.h15
-rw-r--r--src/core/hle/service/service.cpp8
-rw-r--r--src/video_core/engines/maxwell_3d.cpp6
-rw-r--r--src/video_core/engines/maxwell_3d.h4
-rw-r--r--src/video_core/engines/maxwell_compute.cpp6
-rw-r--r--src/video_core/engines/maxwell_dma.cpp17
-rw-r--r--src/video_core/engines/shader_bytecode.h34
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp25
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.h6
-rw-r--r--src/video_core/renderer_opengl/gl_shader_decompiler.cpp300
-rw-r--r--src/video_core/renderer_opengl/gl_shader_gen.cpp29
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.cpp11
-rw-r--r--src/video_core/renderer_opengl/gl_shader_manager.h8
-rw-r--r--src/video_core/renderer_opengl/maxwell_to_gl.h16
-rw-r--r--src/web_service/CMakeLists.txt2
-rw-r--r--src/yuzu/CMakeLists.txt2
-rw-r--r--src/yuzu/debugger/wait_tree.cpp4
-rw-r--r--src/yuzu/main.ui8
46 files changed, 937 insertions, 541 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index d0e506689..eccd8f64a 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -64,8 +64,6 @@ add_library(common STATIC
64 logging/text_formatter.cpp 64 logging/text_formatter.cpp
65 logging/text_formatter.h 65 logging/text_formatter.h
66 math_util.h 66 math_util.h
67 memory_util.cpp
68 memory_util.h
69 microprofile.cpp 67 microprofile.cpp
70 microprofile.h 68 microprofile.h
71 microprofileui.h 69 microprofileui.h
diff --git a/src/common/file_util.cpp b/src/common/file_util.cpp
index 548463787..b52492da6 100644
--- a/src/common/file_util.cpp
+++ b/src/common/file_util.cpp
@@ -15,21 +15,24 @@
15#ifdef _WIN32 15#ifdef _WIN32
16#include <windows.h> 16#include <windows.h>
17// windows.h needs to be included before other windows headers 17// windows.h needs to be included before other windows headers
18#include <commdlg.h> // for GetSaveFileName 18#include <direct.h> // getcwd
19#include <direct.h> // getcwd
20#include <io.h> 19#include <io.h>
21#include <shellapi.h> 20#include <shellapi.h>
22#include <shlobj.h> // for SHGetFolderPath 21#include <shlobj.h> // for SHGetFolderPath
23#include <tchar.h> 22#include <tchar.h>
24#include "common/string_util.h" 23#include "common/string_util.h"
25 24
26// 64 bit offsets for windows 25#ifdef _MSC_VER
26// 64 bit offsets for MSVC
27#define fseeko _fseeki64 27#define fseeko _fseeki64
28#define ftello _ftelli64 28#define ftello _ftelli64
29#define atoll _atoi64 29#define fileno _fileno
30#endif
31
32// 64 bit offsets for MSVC and MinGW. MinGW also needs this for using _wstat64
30#define stat _stat64 33#define stat _stat64
31#define fstat _fstat64 34#define fstat _fstat64
32#define fileno _fileno 35
33#else 36#else
34#ifdef __APPLE__ 37#ifdef __APPLE__
35#include <sys/param.h> 38#include <sys/param.h>
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index abbd056ee..c9161155a 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -91,6 +91,7 @@ enum class Class : ClassType {
91 Service_PM, ///< The PM service 91 Service_PM, ///< The PM service
92 Service_PREPO, ///< The PREPO (Play report) service 92 Service_PREPO, ///< The PREPO (Play report) service
93 Service_PSC, ///< The PSC service 93 Service_PSC, ///< The PSC service
94 Service_PSM, ///< The PSM service
94 Service_SET, ///< The SET (Settings) service 95 Service_SET, ///< The SET (Settings) service
95 Service_SM, ///< The SM (Service manager) service 96 Service_SM, ///< The SM (Service manager) service
96 Service_SPL, ///< The SPL service 97 Service_SPL, ///< The SPL service
diff --git a/src/common/memory_util.cpp b/src/common/memory_util.cpp
deleted file mode 100644
index 9736fb12a..000000000
--- a/src/common/memory_util.cpp
+++ /dev/null
@@ -1,177 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project / 2014 Citra Emulator Project
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "common/logging/log.h"
6#include "common/memory_util.h"
7
8#ifdef _WIN32
9#include <windows.h>
10// Windows.h needs to be included before psapi.h
11#include <psapi.h>
12#include "common/common_funcs.h"
13#include "common/string_util.h"
14#else
15#include <cstdlib>
16#include <sys/mman.h>
17#endif
18
19#if !defined(_WIN32) && defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT)
20#include <unistd.h>
21#define PAGE_MASK (getpagesize() - 1)
22#define round_page(x) ((((unsigned long)(x)) + PAGE_MASK) & ~(PAGE_MASK))
23#endif
24
25// This is purposely not a full wrapper for virtualalloc/mmap, but it
26// provides exactly the primitive operations that Dolphin needs.
27
28void* AllocateExecutableMemory(std::size_t size, bool low) {
29#if defined(_WIN32)
30 void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_EXECUTE_READWRITE);
31#else
32 static char* map_hint = nullptr;
33#if defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT)
34 // This OS has no flag to enforce allocation below the 4 GB boundary,
35 // but if we hint that we want a low address it is very likely we will
36 // get one.
37 // An older version of this code used MAP_FIXED, but that has the side
38 // effect of discarding already mapped pages that happen to be in the
39 // requested virtual memory range (such as the emulated RAM, sometimes).
40 if (low && (!map_hint))
41 map_hint = (char*)round_page(512 * 1024 * 1024); /* 0.5 GB rounded up to the next page */
42#endif
43 void* ptr = mmap(map_hint, size, PROT_READ | PROT_WRITE | PROT_EXEC,
44 MAP_ANON | MAP_PRIVATE
45#if defined(ARCHITECTURE_x86_64) && defined(MAP_32BIT)
46 | (low ? MAP_32BIT : 0)
47#endif
48 ,
49 -1, 0);
50#endif /* defined(_WIN32) */
51
52#ifdef _WIN32
53 if (ptr == nullptr) {
54#else
55 if (ptr == MAP_FAILED) {
56 ptr = nullptr;
57#endif
58 LOG_ERROR(Common_Memory, "Failed to allocate executable memory");
59 }
60#if !defined(_WIN32) && defined(ARCHITECTURE_x86_64) && !defined(MAP_32BIT)
61 else {
62 if (low) {
63 map_hint += size;
64 map_hint = (char*)round_page(map_hint); /* round up to the next page */
65 }
66 }
67#endif
68
69#if EMU_ARCH_BITS == 64
70 if ((u64)ptr >= 0x80000000 && low == true)
71 LOG_ERROR(Common_Memory, "Executable memory ended up above 2GB!");
72#endif
73
74 return ptr;
75}
76
77void* AllocateMemoryPages(std::size_t size) {
78#ifdef _WIN32
79 void* ptr = VirtualAlloc(nullptr, size, MEM_COMMIT, PAGE_READWRITE);
80#else
81 void* ptr = mmap(nullptr, size, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);
82
83 if (ptr == MAP_FAILED)
84 ptr = nullptr;
85#endif
86
87 if (ptr == nullptr)
88 LOG_ERROR(Common_Memory, "Failed to allocate raw memory");
89
90 return ptr;
91}
92
93void* AllocateAlignedMemory(std::size_t size, std::size_t alignment) {
94#ifdef _WIN32
95 void* ptr = _aligned_malloc(size, alignment);
96#else
97 void* ptr = nullptr;
98#ifdef ANDROID
99 ptr = memalign(alignment, size);
100#else
101 if (posix_memalign(&ptr, alignment, size) != 0)
102 LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
103#endif
104#endif
105
106 if (ptr == nullptr)
107 LOG_ERROR(Common_Memory, "Failed to allocate aligned memory");
108
109 return ptr;
110}
111
112void FreeMemoryPages(void* ptr, std::size_t size) {
113 if (ptr) {
114#ifdef _WIN32
115 if (!VirtualFree(ptr, 0, MEM_RELEASE))
116 LOG_ERROR(Common_Memory, "FreeMemoryPages failed!\n{}", GetLastErrorMsg());
117#else
118 munmap(ptr, size);
119#endif
120 }
121}
122
123void FreeAlignedMemory(void* ptr) {
124 if (ptr) {
125#ifdef _WIN32
126 _aligned_free(ptr);
127#else
128 free(ptr);
129#endif
130 }
131}
132
133void WriteProtectMemory(void* ptr, std::size_t size, bool allowExecute) {
134#ifdef _WIN32
135 DWORD oldValue;
136 if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READ : PAGE_READONLY, &oldValue))
137 LOG_ERROR(Common_Memory, "WriteProtectMemory failed!\n{}", GetLastErrorMsg());
138#else
139 mprotect(ptr, size, allowExecute ? (PROT_READ | PROT_EXEC) : PROT_READ);
140#endif
141}
142
143void UnWriteProtectMemory(void* ptr, std::size_t size, bool allowExecute) {
144#ifdef _WIN32
145 DWORD oldValue;
146 if (!VirtualProtect(ptr, size, allowExecute ? PAGE_EXECUTE_READWRITE : PAGE_READWRITE,
147 &oldValue))
148 LOG_ERROR(Common_Memory, "UnWriteProtectMemory failed!\n{}", GetLastErrorMsg());
149#else
150 mprotect(ptr, size,
151 allowExecute ? (PROT_READ | PROT_WRITE | PROT_EXEC) : PROT_WRITE | PROT_READ);
152#endif
153}
154
155std::string MemUsage() {
156#ifdef _WIN32
157#pragma comment(lib, "psapi")
158 DWORD processID = GetCurrentProcessId();
159 HANDLE hProcess;
160 PROCESS_MEMORY_COUNTERS pmc;
161 std::string Ret;
162
163 // Print information about the memory usage of the process.
164
165 hProcess = OpenProcess(PROCESS_QUERY_INFORMATION | PROCESS_VM_READ, FALSE, processID);
166 if (nullptr == hProcess)
167 return "MemUsage Error";
168
169 if (GetProcessMemoryInfo(hProcess, &pmc, sizeof(pmc)))
170 Ret = fmt::format("{} K", Common::ThousandSeparate(pmc.WorkingSetSize / 1024, 7));
171
172 CloseHandle(hProcess);
173 return Ret;
174#else
175 return "";
176#endif
177}
diff --git a/src/common/memory_util.h b/src/common/memory_util.h
deleted file mode 100644
index aad071979..000000000
--- a/src/common/memory_util.h
+++ /dev/null
@@ -1,21 +0,0 @@
1// Copyright 2013 Dolphin Emulator Project / 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 <cstddef>
8#include <string>
9
10void* AllocateExecutableMemory(std::size_t size, bool low = true);
11void* AllocateMemoryPages(std::size_t size);
12void FreeMemoryPages(void* ptr, std::size_t size);
13void* AllocateAlignedMemory(std::size_t size, std::size_t alignment);
14void FreeAlignedMemory(void* ptr);
15void WriteProtectMemory(void* ptr, std::size_t size, bool executable = false);
16void UnWriteProtectMemory(void* ptr, std::size_t size, bool allowExecute = false);
17std::string MemUsage();
18
19inline int GetPageSize() {
20 return 4096;
21}
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index 4755ec822..64fdf38cd 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -156,6 +156,8 @@ add_library(core STATIC
156 hle/service/am/omm.h 156 hle/service/am/omm.h
157 hle/service/am/spsm.cpp 157 hle/service/am/spsm.cpp
158 hle/service/am/spsm.h 158 hle/service/am/spsm.h
159 hle/service/am/tcap.cpp
160 hle/service/am/tcap.h
159 hle/service/aoc/aoc_u.cpp 161 hle/service/aoc/aoc_u.cpp
160 hle/service/aoc/aoc_u.h 162 hle/service/aoc/aoc_u.h
161 hle/service/apm/apm.cpp 163 hle/service/apm/apm.cpp
@@ -280,6 +282,8 @@ add_library(core STATIC
280 hle/service/nifm/nifm.h 282 hle/service/nifm/nifm.h
281 hle/service/nim/nim.cpp 283 hle/service/nim/nim.cpp
282 hle/service/nim/nim.h 284 hle/service/nim/nim.h
285 hle/service/npns/npns.cpp
286 hle/service/npns/npns.h
283 hle/service/ns/ns.cpp 287 hle/service/ns/ns.cpp
284 hle/service/ns/ns.h 288 hle/service/ns/ns.h
285 hle/service/ns/pl_u.cpp 289 hle/service/ns/pl_u.cpp
@@ -327,6 +331,8 @@ add_library(core STATIC
327 hle/service/prepo/prepo.h 331 hle/service/prepo/prepo.h
328 hle/service/psc/psc.cpp 332 hle/service/psc/psc.cpp
329 hle/service/psc/psc.h 333 hle/service/psc/psc.h
334 hle/service/ptm/psm.cpp
335 hle/service/ptm/psm.h
330 hle/service/service.cpp 336 hle/service/service.cpp
331 hle/service/service.h 337 hle/service/service.h
332 hle/service/set/set.cpp 338 hle/service/set/set.cpp
diff --git a/src/core/hle/kernel/hle_ipc.cpp b/src/core/hle/kernel/hle_ipc.cpp
index edad5f1b1..68d5376cb 100644
--- a/src/core/hle/kernel/hle_ipc.cpp
+++ b/src/core/hle/kernel/hle_ipc.cpp
@@ -77,7 +77,8 @@ HLERequestContext::HLERequestContext(SharedPtr<Kernel::ServerSession> server_ses
77 77
78HLERequestContext::~HLERequestContext() = default; 78HLERequestContext::~HLERequestContext() = default;
79 79
80void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) { 80void HLERequestContext::ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf,
81 bool incoming) {
81 IPC::RequestParser rp(src_cmdbuf); 82 IPC::RequestParser rp(src_cmdbuf);
82 command_header = std::make_shared<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>()); 83 command_header = std::make_shared<IPC::CommandHeader>(rp.PopRaw<IPC::CommandHeader>());
83 84
@@ -94,8 +95,6 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
94 rp.Skip(2, false); 95 rp.Skip(2, false);
95 } 96 }
96 if (incoming) { 97 if (incoming) {
97 auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
98
99 // Populate the object lists with the data in the IPC request. 98 // Populate the object lists with the data in the IPC request.
100 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) { 99 for (u32 handle = 0; handle < handle_descriptor_header->num_handles_to_copy; ++handle) {
101 copy_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>())); 100 copy_objects.push_back(handle_table.GetGeneric(rp.Pop<Handle>()));
@@ -189,10 +188,9 @@ void HLERequestContext::ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming) {
189 rp.Skip(1, false); // The command is actually an u64, but we don't use the high part. 188 rp.Skip(1, false); // The command is actually an u64, but we don't use the high part.
190} 189}
191 190
192ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, 191ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
193 Process& src_process, 192 u32_le* src_cmdbuf) {
194 HandleTable& src_table) { 193 ParseCommandBuffer(handle_table, src_cmdbuf, true);
195 ParseCommandBuffer(src_cmdbuf, true);
196 if (command_header->type == IPC::CommandType::Close) { 194 if (command_header->type == IPC::CommandType::Close) {
197 // Close does not populate the rest of the IPC header 195 // Close does not populate the rest of the IPC header
198 return RESULT_SUCCESS; 196 return RESULT_SUCCESS;
@@ -207,14 +205,17 @@ ResultCode HLERequestContext::PopulateFromIncomingCommandBuffer(u32_le* src_cmdb
207 return RESULT_SUCCESS; 205 return RESULT_SUCCESS;
208} 206}
209 207
210ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread) { 208ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(Thread& thread) {
209 auto& owner_process = *thread.GetOwnerProcess();
210 auto& handle_table = owner_process.GetHandleTable();
211
211 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf; 212 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> dst_cmdbuf;
212 Memory::ReadBlock(*thread.GetOwnerProcess(), thread.GetTLSAddress(), dst_cmdbuf.data(), 213 Memory::ReadBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
213 dst_cmdbuf.size() * sizeof(u32)); 214 dst_cmdbuf.size() * sizeof(u32));
214 215
215 // The header was already built in the internal command buffer. Attempt to parse it to verify 216 // The header was already built in the internal command buffer. Attempt to parse it to verify
216 // the integrity and then copy it over to the target command buffer. 217 // the integrity and then copy it over to the target command buffer.
217 ParseCommandBuffer(cmd_buf.data(), false); 218 ParseCommandBuffer(handle_table, cmd_buf.data(), false);
218 219
219 // The data_size already includes the payload header, the padding and the domain header. 220 // The data_size already includes the payload header, the padding and the domain header.
220 std::size_t size = data_payload_offset + command_header->data_size - 221 std::size_t size = data_payload_offset + command_header->data_size -
@@ -236,8 +237,6 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread)
236 ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy); 237 ASSERT(copy_objects.size() == handle_descriptor_header->num_handles_to_copy);
237 ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move); 238 ASSERT(move_objects.size() == handle_descriptor_header->num_handles_to_move);
238 239
239 auto& handle_table = Core::System::GetInstance().Kernel().HandleTable();
240
241 // We don't make a distinction between copy and move handles when translating since HLE 240 // We don't make a distinction between copy and move handles when translating since HLE
242 // services don't deal with handles directly. However, the guest applications might check 241 // services don't deal with handles directly. However, the guest applications might check
243 // for specific values in each of these descriptors. 242 // for specific values in each of these descriptors.
@@ -268,7 +267,7 @@ ResultCode HLERequestContext::WriteToOutgoingCommandBuffer(const Thread& thread)
268 } 267 }
269 268
270 // Copy the translated command buffer back into the thread's command buffer area. 269 // Copy the translated command buffer back into the thread's command buffer area.
271 Memory::WriteBlock(*thread.GetOwnerProcess(), thread.GetTLSAddress(), dst_cmdbuf.data(), 270 Memory::WriteBlock(owner_process, thread.GetTLSAddress(), dst_cmdbuf.data(),
272 dst_cmdbuf.size() * sizeof(u32)); 271 dst_cmdbuf.size() * sizeof(u32));
273 272
274 return RESULT_SUCCESS; 273 return RESULT_SUCCESS;
diff --git a/src/core/hle/kernel/hle_ipc.h b/src/core/hle/kernel/hle_ipc.h
index 894479ee0..f01491daa 100644
--- a/src/core/hle/kernel/hle_ipc.h
+++ b/src/core/hle/kernel/hle_ipc.h
@@ -24,10 +24,10 @@ class ServiceFrameworkBase;
24namespace Kernel { 24namespace Kernel {
25 25
26class Domain; 26class Domain;
27class Event;
27class HandleTable; 28class HandleTable;
28class HLERequestContext; 29class HLERequestContext;
29class Process; 30class Process;
30class Event;
31 31
32/** 32/**
33 * Interface implemented by HLE Session handlers. 33 * Interface implemented by HLE Session handlers.
@@ -126,13 +126,12 @@ public:
126 u64 timeout, WakeupCallback&& callback, 126 u64 timeout, WakeupCallback&& callback,
127 Kernel::SharedPtr<Kernel::Event> event = nullptr); 127 Kernel::SharedPtr<Kernel::Event> event = nullptr);
128 128
129 void ParseCommandBuffer(u32_le* src_cmdbuf, bool incoming);
130
131 /// Populates this context with data from the requesting process/thread. 129 /// Populates this context with data from the requesting process/thread.
132 ResultCode PopulateFromIncomingCommandBuffer(u32_le* src_cmdbuf, Process& src_process, 130 ResultCode PopulateFromIncomingCommandBuffer(const HandleTable& handle_table,
133 HandleTable& src_table); 131 u32_le* src_cmdbuf);
132
134 /// Writes data from this context back to the requesting process/thread. 133 /// Writes data from this context back to the requesting process/thread.
135 ResultCode WriteToOutgoingCommandBuffer(const Thread& thread); 134 ResultCode WriteToOutgoingCommandBuffer(Thread& thread);
136 135
137 u32_le GetCommand() const { 136 u32_le GetCommand() const {
138 return command; 137 return command;
@@ -255,6 +254,8 @@ public:
255 std::string Description() const; 254 std::string Description() const;
256 255
257private: 256private:
257 void ParseCommandBuffer(const HandleTable& handle_table, u32_le* src_cmdbuf, bool incoming);
258
258 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf; 259 std::array<u32, IPC::COMMAND_BUFFER_LENGTH> cmd_buf;
259 SharedPtr<Kernel::ServerSession> server_session; 260 SharedPtr<Kernel::ServerSession> server_session;
260 // TODO(yuriks): Check common usage of this and optimize size accordingly 261 // TODO(yuriks): Check common usage of this and optimize size accordingly
diff --git a/src/core/hle/kernel/kernel.cpp b/src/core/hle/kernel/kernel.cpp
index bd680adfe..4b6b32dd5 100644
--- a/src/core/hle/kernel/kernel.cpp
+++ b/src/core/hle/kernel/kernel.cpp
@@ -118,7 +118,6 @@ struct KernelCore::Impl {
118 process_list.clear(); 118 process_list.clear();
119 current_process = nullptr; 119 current_process = nullptr;
120 120
121 handle_table.Clear();
122 resource_limits.fill(nullptr); 121 resource_limits.fill(nullptr);
123 122
124 thread_wakeup_callback_handle_table.Clear(); 123 thread_wakeup_callback_handle_table.Clear();
@@ -209,7 +208,6 @@ struct KernelCore::Impl {
209 std::vector<SharedPtr<Process>> process_list; 208 std::vector<SharedPtr<Process>> process_list;
210 Process* current_process = nullptr; 209 Process* current_process = nullptr;
211 210
212 Kernel::HandleTable handle_table;
213 std::array<SharedPtr<ResourceLimit>, 4> resource_limits; 211 std::array<SharedPtr<ResourceLimit>, 4> resource_limits;
214 212
215 /// The event type of the generic timer callback event 213 /// The event type of the generic timer callback event
@@ -241,14 +239,6 @@ void KernelCore::Shutdown() {
241 impl->Shutdown(); 239 impl->Shutdown();
242} 240}
243 241
244Kernel::HandleTable& KernelCore::HandleTable() {
245 return impl->handle_table;
246}
247
248const Kernel::HandleTable& KernelCore::HandleTable() const {
249 return impl->handle_table;
250}
251
252SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory( 242SharedPtr<ResourceLimit> KernelCore::ResourceLimitForCategory(
253 ResourceLimitCategory category) const { 243 ResourceLimitCategory category) const {
254 return impl->resource_limits.at(static_cast<std::size_t>(category)); 244 return impl->resource_limits.at(static_cast<std::size_t>(category));
diff --git a/src/core/hle/kernel/kernel.h b/src/core/hle/kernel/kernel.h
index 41554821f..7f822d524 100644
--- a/src/core/hle/kernel/kernel.h
+++ b/src/core/hle/kernel/kernel.h
@@ -47,12 +47,6 @@ public:
47 /// Clears all resources in use by the kernel instance. 47 /// Clears all resources in use by the kernel instance.
48 void Shutdown(); 48 void Shutdown();
49 49
50 /// Provides a reference to the handle table.
51 Kernel::HandleTable& HandleTable();
52
53 /// Provides a const reference to the handle table.
54 const Kernel::HandleTable& HandleTable() const;
55
56 /// Retrieves a shared pointer to a ResourceLimit identified by the given category. 50 /// Retrieves a shared pointer to a ResourceLimit identified by the given category.
57 SharedPtr<ResourceLimit> ResourceLimitForCategory(ResourceLimitCategory category) const; 51 SharedPtr<ResourceLimit> ResourceLimitForCategory(ResourceLimitCategory category) const;
58 52
diff --git a/src/core/hle/kernel/process.h b/src/core/hle/kernel/process.h
index f2816943a..148478488 100644
--- a/src/core/hle/kernel/process.h
+++ b/src/core/hle/kernel/process.h
@@ -13,6 +13,7 @@
13#include <boost/container/static_vector.hpp> 13#include <boost/container/static_vector.hpp>
14#include "common/bit_field.h" 14#include "common/bit_field.h"
15#include "common/common_types.h" 15#include "common/common_types.h"
16#include "core/hle/kernel/handle_table.h"
16#include "core/hle/kernel/object.h" 17#include "core/hle/kernel/object.h"
17#include "core/hle/kernel/thread.h" 18#include "core/hle/kernel/thread.h"
18#include "core/hle/kernel/vm_manager.h" 19#include "core/hle/kernel/vm_manager.h"
@@ -142,6 +143,16 @@ public:
142 return vm_manager; 143 return vm_manager;
143 } 144 }
144 145
146 /// Gets a reference to the process' handle table.
147 HandleTable& GetHandleTable() {
148 return handle_table;
149 }
150
151 /// Gets a const reference to the process' handle table.
152 const HandleTable& GetHandleTable() const {
153 return handle_table;
154 }
155
145 /// Gets the current status of the process 156 /// Gets the current status of the process
146 ProcessStatus GetStatus() const { 157 ProcessStatus GetStatus() const {
147 return status; 158 return status;
@@ -294,6 +305,9 @@ private:
294 /// specified by metadata provided to the process during loading. 305 /// specified by metadata provided to the process during loading.
295 bool is_64bit_process = true; 306 bool is_64bit_process = true;
296 307
308 /// Per-process handle table for storing created object handles in.
309 HandleTable handle_table;
310
297 std::string name; 311 std::string name;
298}; 312};
299 313
diff --git a/src/core/hle/kernel/server_session.cpp b/src/core/hle/kernel/server_session.cpp
index 1ece691c7..5fc320403 100644
--- a/src/core/hle/kernel/server_session.cpp
+++ b/src/core/hle/kernel/server_session.cpp
@@ -107,8 +107,7 @@ ResultCode ServerSession::HandleSyncRequest(SharedPtr<Thread> thread) {
107 // similar. 107 // similar.
108 Kernel::HLERequestContext context(this); 108 Kernel::HLERequestContext context(this);
109 u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress()); 109 u32* cmd_buf = (u32*)Memory::GetPointer(thread->GetTLSAddress());
110 context.PopulateFromIncomingCommandBuffer(cmd_buf, *Core::CurrentProcess(), 110 context.PopulateFromIncomingCommandBuffer(kernel.CurrentProcess()->GetHandleTable(), cmd_buf);
111 kernel.HandleTable());
112 111
113 ResultCode result = RESULT_SUCCESS; 112 ResultCode result = RESULT_SUCCESS;
114 // If the session has been converted to a domain, handle the domain request 113 // If the session has been converted to a domain, handle the domain request
diff --git a/src/core/hle/kernel/svc.cpp b/src/core/hle/kernel/svc.cpp
index 3b8a2e230..67ea67666 100644
--- a/src/core/hle/kernel/svc.cpp
+++ b/src/core/hle/kernel/svc.cpp
@@ -189,14 +189,15 @@ static ResultCode ConnectToNamedPort(Handle* out_handle, VAddr port_name_address
189 CASCADE_RESULT(client_session, client_port->Connect()); 189 CASCADE_RESULT(client_session, client_port->Connect());
190 190
191 // Return the client session 191 // Return the client session
192 CASCADE_RESULT(*out_handle, kernel.HandleTable().Create(client_session)); 192 auto& handle_table = Core::CurrentProcess()->GetHandleTable();
193 CASCADE_RESULT(*out_handle, handle_table.Create(client_session));
193 return RESULT_SUCCESS; 194 return RESULT_SUCCESS;
194} 195}
195 196
196/// Makes a blocking IPC call to an OS service. 197/// Makes a blocking IPC call to an OS service.
197static ResultCode SendSyncRequest(Handle handle) { 198static ResultCode SendSyncRequest(Handle handle) {
198 auto& kernel = Core::System::GetInstance().Kernel(); 199 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
199 SharedPtr<ClientSession> session = kernel.HandleTable().Get<ClientSession>(handle); 200 SharedPtr<ClientSession> session = handle_table.Get<ClientSession>(handle);
200 if (!session) { 201 if (!session) {
201 LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle); 202 LOG_ERROR(Kernel_SVC, "called with invalid handle=0x{:08X}", handle);
202 return ERR_INVALID_HANDLE; 203 return ERR_INVALID_HANDLE;
@@ -215,8 +216,8 @@ static ResultCode SendSyncRequest(Handle handle) {
215static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) { 216static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
216 LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); 217 LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
217 218
218 auto& kernel = Core::System::GetInstance().Kernel(); 219 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
219 const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle); 220 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
220 if (!thread) { 221 if (!thread) {
221 return ERR_INVALID_HANDLE; 222 return ERR_INVALID_HANDLE;
222 } 223 }
@@ -229,8 +230,8 @@ static ResultCode GetThreadId(u32* thread_id, Handle thread_handle) {
229static ResultCode GetProcessId(u32* process_id, Handle process_handle) { 230static ResultCode GetProcessId(u32* process_id, Handle process_handle) {
230 LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle); 231 LOG_TRACE(Kernel_SVC, "called process=0x{:08X}", process_handle);
231 232
232 auto& kernel = Core::System::GetInstance().Kernel(); 233 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
233 const SharedPtr<Process> process = kernel.HandleTable().Get<Process>(process_handle); 234 const SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
234 if (!process) { 235 if (!process) {
235 return ERR_INVALID_HANDLE; 236 return ERR_INVALID_HANDLE;
236 } 237 }
@@ -273,11 +274,11 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
273 274
274 using ObjectPtr = Thread::ThreadWaitObjects::value_type; 275 using ObjectPtr = Thread::ThreadWaitObjects::value_type;
275 Thread::ThreadWaitObjects objects(handle_count); 276 Thread::ThreadWaitObjects objects(handle_count);
276 auto& kernel = Core::System::GetInstance().Kernel(); 277 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
277 278
278 for (u64 i = 0; i < handle_count; ++i) { 279 for (u64 i = 0; i < handle_count; ++i) {
279 const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle)); 280 const Handle handle = Memory::Read32(handles_address + i * sizeof(Handle));
280 const auto object = kernel.HandleTable().Get<WaitObject>(handle); 281 const auto object = handle_table.Get<WaitObject>(handle);
281 282
282 if (object == nullptr) { 283 if (object == nullptr) {
283 return ERR_INVALID_HANDLE; 284 return ERR_INVALID_HANDLE;
@@ -325,8 +326,8 @@ static ResultCode WaitSynchronization(Handle* index, VAddr handles_address, u64
325static ResultCode CancelSynchronization(Handle thread_handle) { 326static ResultCode CancelSynchronization(Handle thread_handle) {
326 LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle); 327 LOG_TRACE(Kernel_SVC, "called thread=0x{:X}", thread_handle);
327 328
328 auto& kernel = Core::System::GetInstance().Kernel(); 329 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
329 const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle); 330 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
330 if (!thread) { 331 if (!thread) {
331 return ERR_INVALID_HANDLE; 332 return ERR_INVALID_HANDLE;
332 } 333 }
@@ -354,7 +355,7 @@ static ResultCode ArbitrateLock(Handle holding_thread_handle, VAddr mutex_addr,
354 return ERR_INVALID_ADDRESS; 355 return ERR_INVALID_ADDRESS;
355 } 356 }
356 357
357 auto& handle_table = Core::System::GetInstance().Kernel().HandleTable(); 358 auto& handle_table = Core::CurrentProcess()->GetHandleTable();
358 return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle, 359 return Mutex::TryAcquire(handle_table, mutex_addr, holding_thread_handle,
359 requesting_thread_handle); 360 requesting_thread_handle);
360} 361}
@@ -499,13 +500,12 @@ static ResultCode SetThreadActivity(Handle handle, u32 unknown) {
499static ResultCode GetThreadContext(VAddr thread_context, Handle handle) { 500static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
500 LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle); 501 LOG_DEBUG(Kernel_SVC, "called, context=0x{:08X}, thread=0x{:X}", thread_context, handle);
501 502
502 auto& kernel = Core::System::GetInstance().Kernel(); 503 const auto* current_process = Core::CurrentProcess();
503 const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle); 504 const SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
504 if (!thread) { 505 if (!thread) {
505 return ERR_INVALID_HANDLE; 506 return ERR_INVALID_HANDLE;
506 } 507 }
507 508
508 const auto* current_process = Core::CurrentProcess();
509 if (thread->GetOwnerProcess() != current_process) { 509 if (thread->GetOwnerProcess() != current_process) {
510 return ERR_INVALID_HANDLE; 510 return ERR_INVALID_HANDLE;
511 } 511 }
@@ -531,10 +531,11 @@ static ResultCode GetThreadContext(VAddr thread_context, Handle handle) {
531 531
532/// Gets the priority for the specified thread 532/// Gets the priority for the specified thread
533static ResultCode GetThreadPriority(u32* priority, Handle handle) { 533static ResultCode GetThreadPriority(u32* priority, Handle handle) {
534 auto& kernel = Core::System::GetInstance().Kernel(); 534 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
535 const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle); 535 const SharedPtr<Thread> thread = handle_table.Get<Thread>(handle);
536 if (!thread) 536 if (!thread) {
537 return ERR_INVALID_HANDLE; 537 return ERR_INVALID_HANDLE;
538 }
538 539
539 *priority = thread->GetPriority(); 540 *priority = thread->GetPriority();
540 return RESULT_SUCCESS; 541 return RESULT_SUCCESS;
@@ -546,14 +547,15 @@ static ResultCode SetThreadPriority(Handle handle, u32 priority) {
546 return ERR_INVALID_THREAD_PRIORITY; 547 return ERR_INVALID_THREAD_PRIORITY;
547 } 548 }
548 549
549 auto& kernel = Core::System::GetInstance().Kernel(); 550 const auto* const current_process = Core::CurrentProcess();
550 SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(handle); 551 SharedPtr<Thread> thread = current_process->GetHandleTable().Get<Thread>(handle);
551 if (!thread) 552 if (!thread) {
552 return ERR_INVALID_HANDLE; 553 return ERR_INVALID_HANDLE;
554 }
553 555
554 // Note: The kernel uses the current process's resource limit instead of 556 // Note: The kernel uses the current process's resource limit instead of
555 // the one from the thread owner's resource limit. 557 // the one from the thread owner's resource limit.
556 const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit(); 558 const ResourceLimit& resource_limit = current_process->GetResourceLimit();
557 if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { 559 if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
558 return ERR_NOT_AUTHORIZED; 560 return ERR_NOT_AUTHORIZED;
559 } 561 }
@@ -595,15 +597,13 @@ static ResultCode MapSharedMemory(Handle shared_memory_handle, VAddr addr, u64 s
595 return ERR_INVALID_MEMORY_PERMISSIONS; 597 return ERR_INVALID_MEMORY_PERMISSIONS;
596 } 598 }
597 599
598 auto& kernel = Core::System::GetInstance().Kernel(); 600 auto* const current_process = Core::CurrentProcess();
599 auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); 601 auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
600 if (!shared_memory) { 602 if (!shared_memory) {
601 return ERR_INVALID_HANDLE; 603 return ERR_INVALID_HANDLE;
602 } 604 }
603 605
604 auto* const current_process = Core::CurrentProcess();
605 const auto& vm_manager = current_process->VMManager(); 606 const auto& vm_manager = current_process->VMManager();
606
607 if (!vm_manager.IsWithinASLRRegion(addr, size)) { 607 if (!vm_manager.IsWithinASLRRegion(addr, size)) {
608 return ERR_INVALID_MEMORY_RANGE; 608 return ERR_INVALID_MEMORY_RANGE;
609 } 609 }
@@ -627,15 +627,13 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
627 return ERR_INVALID_ADDRESS_STATE; 627 return ERR_INVALID_ADDRESS_STATE;
628 } 628 }
629 629
630 auto& kernel = Core::System::GetInstance().Kernel(); 630 auto* const current_process = Core::CurrentProcess();
631 auto shared_memory = kernel.HandleTable().Get<SharedMemory>(shared_memory_handle); 631 auto shared_memory = current_process->GetHandleTable().Get<SharedMemory>(shared_memory_handle);
632 if (!shared_memory) { 632 if (!shared_memory) {
633 return ERR_INVALID_HANDLE; 633 return ERR_INVALID_HANDLE;
634 } 634 }
635 635
636 auto* const current_process = Core::CurrentProcess();
637 const auto& vm_manager = current_process->VMManager(); 636 const auto& vm_manager = current_process->VMManager();
638
639 if (!vm_manager.IsWithinASLRRegion(addr, size)) { 637 if (!vm_manager.IsWithinASLRRegion(addr, size)) {
640 return ERR_INVALID_MEMORY_RANGE; 638 return ERR_INVALID_MEMORY_RANGE;
641 } 639 }
@@ -646,15 +644,14 @@ static ResultCode UnmapSharedMemory(Handle shared_memory_handle, VAddr addr, u64
646/// Query process memory 644/// Query process memory
647static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/, 645static ResultCode QueryProcessMemory(MemoryInfo* memory_info, PageInfo* /*page_info*/,
648 Handle process_handle, u64 addr) { 646 Handle process_handle, u64 addr) {
649 647 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
650 auto& kernel = Core::System::GetInstance().Kernel(); 648 SharedPtr<Process> process = handle_table.Get<Process>(process_handle);
651 SharedPtr<Process> process = kernel.HandleTable().Get<Process>(process_handle);
652 if (!process) { 649 if (!process) {
653 return ERR_INVALID_HANDLE; 650 return ERR_INVALID_HANDLE;
654 } 651 }
655 auto vma = process->VMManager().FindVMA(addr); 652 auto vma = process->VMManager().FindVMA(addr);
656 memory_info->attributes = 0; 653 memory_info->attributes = 0;
657 if (vma == Core::CurrentProcess()->VMManager().vma_map.end()) { 654 if (vma == process->VMManager().vma_map.end()) {
658 memory_info->base_address = 0; 655 memory_info->base_address = 0;
659 memory_info->permission = static_cast<u32>(VMAPermission::None); 656 memory_info->permission = static_cast<u32>(VMAPermission::None);
660 memory_info->size = 0; 657 memory_info->size = 0;
@@ -695,20 +692,19 @@ static void ExitProcess() {
695/// Creates a new thread 692/// Creates a new thread
696static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top, 693static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, VAddr stack_top,
697 u32 priority, s32 processor_id) { 694 u32 priority, s32 processor_id) {
698 std::string name = fmt::format("thread-{:X}", entry_point);
699
700 if (priority > THREADPRIO_LOWEST) { 695 if (priority > THREADPRIO_LOWEST) {
701 return ERR_INVALID_THREAD_PRIORITY; 696 return ERR_INVALID_THREAD_PRIORITY;
702 } 697 }
703 698
704 const ResourceLimit& resource_limit = Core::CurrentProcess()->GetResourceLimit(); 699 auto* const current_process = Core::CurrentProcess();
700 const ResourceLimit& resource_limit = current_process->GetResourceLimit();
705 if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) { 701 if (resource_limit.GetMaxResourceValue(ResourceType::Priority) > priority) {
706 return ERR_NOT_AUTHORIZED; 702 return ERR_NOT_AUTHORIZED;
707 } 703 }
708 704
709 if (processor_id == THREADPROCESSORID_DEFAULT) { 705 if (processor_id == THREADPROCESSORID_DEFAULT) {
710 // Set the target CPU to the one specified in the process' exheader. 706 // Set the target CPU to the one specified in the process' exheader.
711 processor_id = Core::CurrentProcess()->GetDefaultProcessorID(); 707 processor_id = current_process->GetDefaultProcessorID();
712 ASSERT(processor_id != THREADPROCESSORID_DEFAULT); 708 ASSERT(processor_id != THREADPROCESSORID_DEFAULT);
713 } 709 }
714 710
@@ -723,11 +719,13 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
723 return ERR_INVALID_PROCESSOR_ID; 719 return ERR_INVALID_PROCESSOR_ID;
724 } 720 }
725 721
722 const std::string name = fmt::format("thread-{:X}", entry_point);
726 auto& kernel = Core::System::GetInstance().Kernel(); 723 auto& kernel = Core::System::GetInstance().Kernel();
727 CASCADE_RESULT(SharedPtr<Thread> thread, 724 CASCADE_RESULT(SharedPtr<Thread> thread,
728 Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top, 725 Thread::Create(kernel, name, entry_point, priority, arg, processor_id, stack_top,
729 *Core::CurrentProcess())); 726 *current_process));
730 const auto new_guest_handle = kernel.HandleTable().Create(thread); 727
728 const auto new_guest_handle = current_process->GetHandleTable().Create(thread);
731 if (new_guest_handle.Failed()) { 729 if (new_guest_handle.Failed()) {
732 return new_guest_handle.Code(); 730 return new_guest_handle.Code();
733 } 731 }
@@ -748,8 +746,8 @@ static ResultCode CreateThread(Handle* out_handle, VAddr entry_point, u64 arg, V
748static ResultCode StartThread(Handle thread_handle) { 746static ResultCode StartThread(Handle thread_handle) {
749 LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle); 747 LOG_TRACE(Kernel_SVC, "called thread=0x{:08X}", thread_handle);
750 748
751 auto& kernel = Core::System::GetInstance().Kernel(); 749 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
752 const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle); 750 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
753 if (!thread) { 751 if (!thread) {
754 return ERR_INVALID_HANDLE; 752 return ERR_INVALID_HANDLE;
755 } 753 }
@@ -796,8 +794,8 @@ static ResultCode WaitProcessWideKeyAtomic(VAddr mutex_addr, VAddr condition_var
796 "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}", 794 "called mutex_addr={:X}, condition_variable_addr={:X}, thread_handle=0x{:08X}, timeout={}",
797 mutex_addr, condition_variable_addr, thread_handle, nano_seconds); 795 mutex_addr, condition_variable_addr, thread_handle, nano_seconds);
798 796
799 auto& kernel = Core::System::GetInstance().Kernel(); 797 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
800 SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle); 798 SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
801 ASSERT(thread); 799 ASSERT(thread);
802 800
803 CASCADE_CODE(Mutex::Release(mutex_addr)); 801 CASCADE_CODE(Mutex::Release(mutex_addr));
@@ -908,9 +906,9 @@ static ResultCode SignalProcessWideKey(VAddr condition_variable_addr, s32 target
908 mutex_val | Mutex::MutexHasWaitersFlag)); 906 mutex_val | Mutex::MutexHasWaitersFlag));
909 907
910 // The mutex is already owned by some other thread, make this thread wait on it. 908 // The mutex is already owned by some other thread, make this thread wait on it.
911 auto& kernel = Core::System::GetInstance().Kernel(); 909 const Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask);
912 Handle owner_handle = static_cast<Handle>(mutex_val & Mutex::MutexOwnerMask); 910 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
913 auto owner = kernel.HandleTable().Get<Thread>(owner_handle); 911 auto owner = handle_table.Get<Thread>(owner_handle);
914 ASSERT(owner); 912 ASSERT(owner);
915 ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex); 913 ASSERT(thread->GetStatus() == ThreadStatus::WaitMutex);
916 thread->InvalidateWakeupCallback(); 914 thread->InvalidateWakeupCallback();
@@ -989,16 +987,16 @@ static u64 GetSystemTick() {
989static ResultCode CloseHandle(Handle handle) { 987static ResultCode CloseHandle(Handle handle) {
990 LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle); 988 LOG_TRACE(Kernel_SVC, "Closing handle 0x{:08X}", handle);
991 989
992 auto& kernel = Core::System::GetInstance().Kernel(); 990 auto& handle_table = Core::CurrentProcess()->GetHandleTable();
993 return kernel.HandleTable().Close(handle); 991 return handle_table.Close(handle);
994} 992}
995 993
996/// Reset an event 994/// Reset an event
997static ResultCode ResetSignal(Handle handle) { 995static ResultCode ResetSignal(Handle handle) {
998 LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle); 996 LOG_WARNING(Kernel_SVC, "(STUBBED) called handle 0x{:08X}", handle);
999 997
1000 auto& kernel = Core::System::GetInstance().Kernel(); 998 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1001 auto event = kernel.HandleTable().Get<Event>(handle); 999 auto event = handle_table.Get<Event>(handle);
1002 1000
1003 ASSERT(event != nullptr); 1001 ASSERT(event != nullptr);
1004 1002
@@ -1017,8 +1015,8 @@ static ResultCode CreateTransferMemory(Handle* handle, VAddr addr, u64 size, u32
1017static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) { 1015static ResultCode GetThreadCoreMask(Handle thread_handle, u32* core, u64* mask) {
1018 LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle); 1016 LOG_TRACE(Kernel_SVC, "called, handle=0x{:08X}", thread_handle);
1019 1017
1020 auto& kernel = Core::System::GetInstance().Kernel(); 1018 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1021 const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle); 1019 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
1022 if (!thread) { 1020 if (!thread) {
1023 return ERR_INVALID_HANDLE; 1021 return ERR_INVALID_HANDLE;
1024 } 1022 }
@@ -1033,8 +1031,8 @@ static ResultCode SetThreadCoreMask(Handle thread_handle, u32 core, u64 mask) {
1033 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle, 1031 LOG_DEBUG(Kernel_SVC, "called, handle=0x{:08X}, mask=0x{:16X}, core=0x{:X}", thread_handle,
1034 mask, core); 1032 mask, core);
1035 1033
1036 auto& kernel = Core::System::GetInstance().Kernel(); 1034 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1037 const SharedPtr<Thread> thread = kernel.HandleTable().Get<Thread>(thread_handle); 1035 const SharedPtr<Thread> thread = handle_table.Get<Thread>(thread_handle);
1038 if (!thread) { 1036 if (!thread) {
1039 return ERR_INVALID_HANDLE; 1037 return ERR_INVALID_HANDLE;
1040 } 1038 }
@@ -1095,7 +1093,7 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
1095 } 1093 }
1096 1094
1097 auto& kernel = Core::System::GetInstance().Kernel(); 1095 auto& kernel = Core::System::GetInstance().Kernel();
1098 auto& handle_table = kernel.HandleTable(); 1096 auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1099 auto shared_mem_handle = 1097 auto shared_mem_handle =
1100 SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size, 1098 SharedMemory::Create(kernel, handle_table.Get<Process>(KernelHandle::CurrentProcess), size,
1101 local_perms, remote_perms); 1099 local_perms, remote_perms);
@@ -1107,10 +1105,12 @@ static ResultCode CreateSharedMemory(Handle* handle, u64 size, u32 local_permiss
1107static ResultCode ClearEvent(Handle handle) { 1105static ResultCode ClearEvent(Handle handle) {
1108 LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle); 1106 LOG_TRACE(Kernel_SVC, "called, event=0x{:08X}", handle);
1109 1107
1110 auto& kernel = Core::System::GetInstance().Kernel(); 1108 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1111 SharedPtr<Event> evt = kernel.HandleTable().Get<Event>(handle); 1109 SharedPtr<Event> evt = handle_table.Get<Event>(handle);
1112 if (evt == nullptr) 1110 if (evt == nullptr) {
1113 return ERR_INVALID_HANDLE; 1111 return ERR_INVALID_HANDLE;
1112 }
1113
1114 evt->Clear(); 1114 evt->Clear();
1115 return RESULT_SUCCESS; 1115 return RESULT_SUCCESS;
1116} 1116}
@@ -1123,8 +1123,8 @@ static ResultCode GetProcessInfo(u64* out, Handle process_handle, u32 type) {
1123 Status, 1123 Status,
1124 }; 1124 };
1125 1125
1126 const auto& kernel = Core::System::GetInstance().Kernel(); 1126 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
1127 const auto process = kernel.HandleTable().Get<Process>(process_handle); 1127 const auto process = handle_table.Get<Process>(process_handle);
1128 if (!process) { 1128 if (!process) {
1129 return ERR_INVALID_HANDLE; 1129 return ERR_INVALID_HANDLE;
1130 } 1130 }
diff --git a/src/core/hle/kernel/thread.cpp b/src/core/hle/kernel/thread.cpp
index 35ec98c1a..59bc9e0af 100644
--- a/src/core/hle/kernel/thread.cpp
+++ b/src/core/hle/kernel/thread.cpp
@@ -266,7 +266,7 @@ SharedPtr<Thread> SetupMainThread(KernelCore& kernel, VAddr entry_point, u32 pri
266 SharedPtr<Thread> thread = std::move(thread_res).Unwrap(); 266 SharedPtr<Thread> thread = std::move(thread_res).Unwrap();
267 267
268 // Register 1 must be a handle to the main thread 268 // Register 1 must be a handle to the main thread
269 const Handle guest_handle = kernel.HandleTable().Create(thread).Unwrap(); 269 const Handle guest_handle = owner_process.GetHandleTable().Create(thread).Unwrap();
270 thread->SetGuestHandle(guest_handle); 270 thread->SetGuestHandle(guest_handle);
271 thread->GetContext().cpu_registers[1] = guest_handle; 271 thread->GetContext().cpu_registers[1] = guest_handle;
272 272
diff --git a/src/core/hle/service/am/am.cpp b/src/core/hle/service/am/am.cpp
index 4d1f83170..ecf72ae24 100644
--- a/src/core/hle/service/am/am.cpp
+++ b/src/core/hle/service/am/am.cpp
@@ -15,6 +15,7 @@
15#include "core/hle/service/am/idle.h" 15#include "core/hle/service/am/idle.h"
16#include "core/hle/service/am/omm.h" 16#include "core/hle/service/am/omm.h"
17#include "core/hle/service/am/spsm.h" 17#include "core/hle/service/am/spsm.h"
18#include "core/hle/service/am/tcap.h"
18#include "core/hle/service/apm/apm.h" 19#include "core/hle/service/apm/apm.h"
19#include "core/hle/service/filesystem/filesystem.h" 20#include "core/hle/service/filesystem/filesystem.h"
20#include "core/hle/service/nvflinger/nvflinger.h" 21#include "core/hle/service/nvflinger/nvflinger.h"
@@ -26,13 +27,18 @@
26namespace Service::AM { 27namespace Service::AM {
27 28
28IWindowController::IWindowController() : ServiceFramework("IWindowController") { 29IWindowController::IWindowController() : ServiceFramework("IWindowController") {
30 // clang-format off
29 static const FunctionInfo functions[] = { 31 static const FunctionInfo functions[] = {
30 {0, nullptr, "CreateWindow"}, 32 {0, nullptr, "CreateWindow"},
31 {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"}, 33 {1, &IWindowController::GetAppletResourceUserId, "GetAppletResourceUserId"},
32 {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"}, 34 {10, &IWindowController::AcquireForegroundRights, "AcquireForegroundRights"},
33 {11, nullptr, "ReleaseForegroundRights"}, 35 {11, nullptr, "ReleaseForegroundRights"},
34 {12, nullptr, "RejectToChangeIntoBackground"}, 36 {12, nullptr, "RejectToChangeIntoBackground"},
37 {20, nullptr, "SetAppletWindowVisibility"},
38 {21, nullptr, "SetAppletGpuTimeSlice"},
35 }; 39 };
40 // clang-format on
41
36 RegisterHandlers(functions); 42 RegisterHandlers(functions);
37} 43}
38 44
@@ -87,6 +93,7 @@ void IAudioController::GetLibraryAppletExpectedMasterVolume(Kernel::HLERequestCo
87} 93}
88 94
89IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") { 95IDisplayController::IDisplayController() : ServiceFramework("IDisplayController") {
96 // clang-format off
90 static const FunctionInfo functions[] = { 97 static const FunctionInfo functions[] = {
91 {0, nullptr, "GetLastForegroundCaptureImage"}, 98 {0, nullptr, "GetLastForegroundCaptureImage"},
92 {1, nullptr, "UpdateLastForegroundCaptureImage"}, 99 {1, nullptr, "UpdateLastForegroundCaptureImage"},
@@ -117,7 +124,11 @@ IDisplayController::IDisplayController() : ServiceFramework("IDisplayController"
117 {25, nullptr, "ReleaseLastForegroundCaptureSharedBuffer"}, 124 {25, nullptr, "ReleaseLastForegroundCaptureSharedBuffer"},
118 {26, nullptr, "AcquireCallerAppletCaptureSharedBuffer"}, 125 {26, nullptr, "AcquireCallerAppletCaptureSharedBuffer"},
119 {27, nullptr, "ReleaseCallerAppletCaptureSharedBuffer"}, 126 {27, nullptr, "ReleaseCallerAppletCaptureSharedBuffer"},
127 // 6.0.0+
128 {28, nullptr, "TakeScreenShotOfOwnLayerEx"},
120 }; 129 };
130 // clang-format on
131
121 RegisterHandlers(functions); 132 RegisterHandlers(functions);
122} 133}
123 134
@@ -128,6 +139,7 @@ IDebugFunctions::~IDebugFunctions() = default;
128 139
129ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) 140ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
130 : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) { 141 : ServiceFramework("ISelfController"), nvflinger(std::move(nvflinger)) {
142 // clang-format off
131 static const FunctionInfo functions[] = { 143 static const FunctionInfo functions[] = {
132 {0, nullptr, "Exit"}, 144 {0, nullptr, "Exit"},
133 {1, &ISelfController::LockExit, "LockExit"}, 145 {1, &ISelfController::LockExit, "LockExit"},
@@ -136,10 +148,8 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
136 {4, nullptr, "LeaveFatalSection"}, 148 {4, nullptr, "LeaveFatalSection"},
137 {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"}, 149 {9, &ISelfController::GetLibraryAppletLaunchableEvent, "GetLibraryAppletLaunchableEvent"},
138 {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"}, 150 {10, &ISelfController::SetScreenShotPermission, "SetScreenShotPermission"},
139 {11, &ISelfController::SetOperationModeChangedNotification, 151 {11, &ISelfController::SetOperationModeChangedNotification, "SetOperationModeChangedNotification"},
140 "SetOperationModeChangedNotification"}, 152 {12, &ISelfController::SetPerformanceModeChangedNotification, "SetPerformanceModeChangedNotification"},
141 {12, &ISelfController::SetPerformanceModeChangedNotification,
142 "SetPerformanceModeChangedNotification"},
143 {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"}, 153 {13, &ISelfController::SetFocusHandlingMode, "SetFocusHandlingMode"},
144 {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"}, 154 {14, &ISelfController::SetRestartMessageEnabled, "SetRestartMessageEnabled"},
145 {15, nullptr, "SetScreenShotAppletIdentityInfo"}, 155 {15, nullptr, "SetScreenShotAppletIdentityInfo"},
@@ -165,7 +175,12 @@ ISelfController::ISelfController(std::shared_ptr<NVFlinger::NVFlinger> nvflinger
165 {69, nullptr, "IsAutoSleepDisabled"}, 175 {69, nullptr, "IsAutoSleepDisabled"},
166 {70, nullptr, "ReportMultimediaError"}, 176 {70, nullptr, "ReportMultimediaError"},
167 {80, nullptr, "SetWirelessPriorityMode"}, 177 {80, nullptr, "SetWirelessPriorityMode"},
178 {90, nullptr, "GetAccumulatedSuspendedTickValue"},
179 {91, nullptr, "GetAccumulatedSuspendedTickChangedEvent"},
180 {1000, nullptr, "GetDebugStorageChannel"},
168 }; 181 };
182 // clang-format on
183
169 RegisterHandlers(functions); 184 RegisterHandlers(functions);
170 185
171 auto& kernel = Core::System::GetInstance().Kernel(); 186 auto& kernel = Core::System::GetInstance().Kernel();
@@ -312,6 +327,7 @@ void ISelfController::GetIdleTimeDetectionExtension(Kernel::HLERequestContext& c
312} 327}
313 328
314ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") { 329ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter") {
330 // clang-format off
315 static const FunctionInfo functions[] = { 331 static const FunctionInfo functions[] = {
316 {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"}, 332 {0, &ICommonStateGetter::GetEventHandle, "GetEventHandle"},
317 {1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"}, 333 {1, &ICommonStateGetter::ReceiveMessage, "ReceiveMessage"},
@@ -336,11 +352,12 @@ ICommonStateGetter::ICommonStateGetter() : ServiceFramework("ICommonStateGetter"
336 {52, nullptr, "SwitchLcdBacklight"}, 352 {52, nullptr, "SwitchLcdBacklight"},
337 {55, nullptr, "IsInControllerFirmwareUpdateSection"}, 353 {55, nullptr, "IsInControllerFirmwareUpdateSection"},
338 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"}, 354 {60, &ICommonStateGetter::GetDefaultDisplayResolution, "GetDefaultDisplayResolution"},
339 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, 355 {61, &ICommonStateGetter::GetDefaultDisplayResolutionChangeEvent, "GetDefaultDisplayResolutionChangeEvent"},
340 "GetDefaultDisplayResolutionChangeEvent"},
341 {62, nullptr, "GetHdcpAuthenticationState"}, 356 {62, nullptr, "GetHdcpAuthenticationState"},
342 {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"}, 357 {63, nullptr, "GetHdcpAuthenticationStateChangeEvent"},
343 }; 358 };
359 // clang-format on
360
344 RegisterHandlers(functions); 361 RegisterHandlers(functions);
345 362
346 auto& kernel = Core::System::GetInstance().Kernel(); 363 auto& kernel = Core::System::GetInstance().Kernel();
@@ -432,11 +449,14 @@ class IStorageAccessor final : public ServiceFramework<IStorageAccessor> {
432public: 449public:
433 explicit IStorageAccessor(std::vector<u8> buffer) 450 explicit IStorageAccessor(std::vector<u8> buffer)
434 : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) { 451 : ServiceFramework("IStorageAccessor"), buffer(std::move(buffer)) {
452 // clang-format off
435 static const FunctionInfo functions[] = { 453 static const FunctionInfo functions[] = {
436 {0, &IStorageAccessor::GetSize, "GetSize"}, 454 {0, &IStorageAccessor::GetSize, "GetSize"},
437 {10, &IStorageAccessor::Write, "Write"}, 455 {10, &IStorageAccessor::Write, "Write"},
438 {11, &IStorageAccessor::Read, "Read"}, 456 {11, &IStorageAccessor::Read, "Read"},
439 }; 457 };
458 // clang-format on
459
440 RegisterHandlers(functions); 460 RegisterHandlers(functions);
441 } 461 }
442 462
@@ -489,10 +509,13 @@ class IStorage final : public ServiceFramework<IStorage> {
489public: 509public:
490 explicit IStorage(std::vector<u8> buffer) 510 explicit IStorage(std::vector<u8> buffer)
491 : ServiceFramework("IStorage"), buffer(std::move(buffer)) { 511 : ServiceFramework("IStorage"), buffer(std::move(buffer)) {
512 // clang-format off
492 static const FunctionInfo functions[] = { 513 static const FunctionInfo functions[] = {
493 {0, &IStorage::Open, "Open"}, 514 {0, &IStorage::Open, "Open"},
494 {1, nullptr, "OpenTransferStorage"}, 515 {1, nullptr, "OpenTransferStorage"},
495 }; 516 };
517 // clang-format on
518
496 RegisterHandlers(functions); 519 RegisterHandlers(functions);
497 } 520 }
498 521
@@ -512,6 +535,7 @@ private:
512class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> { 535class ILibraryAppletAccessor final : public ServiceFramework<ILibraryAppletAccessor> {
513public: 536public:
514 explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") { 537 explicit ILibraryAppletAccessor() : ServiceFramework("ILibraryAppletAccessor") {
538 // clang-format off
515 static const FunctionInfo functions[] = { 539 static const FunctionInfo functions[] = {
516 {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"}, 540 {0, &ILibraryAppletAccessor::GetAppletStateChangedEvent, "GetAppletStateChangedEvent"},
517 {1, nullptr, "IsCompleted"}, 541 {1, nullptr, "IsCompleted"},
@@ -532,6 +556,8 @@ public:
532 {150, nullptr, "RequestForAppletToGetForeground"}, 556 {150, nullptr, "RequestForAppletToGetForeground"},
533 {160, nullptr, "GetIndirectLayerConsumerHandle"}, 557 {160, nullptr, "GetIndirectLayerConsumerHandle"},
534 }; 558 };
559 // clang-format on
560
535 RegisterHandlers(functions); 561 RegisterHandlers(functions);
536 562
537 auto& kernel = Core::System::GetInstance().Kernel(); 563 auto& kernel = Core::System::GetInstance().Kernel();
@@ -624,13 +650,13 @@ void ILibraryAppletCreator::CreateStorage(Kernel::HLERequestContext& ctx) {
624} 650}
625 651
626IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") { 652IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationFunctions") {
653 // clang-format off
627 static const FunctionInfo functions[] = { 654 static const FunctionInfo functions[] = {
628 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"}, 655 {1, &IApplicationFunctions::PopLaunchParameter, "PopLaunchParameter"},
629 {10, nullptr, "CreateApplicationAndPushAndRequestToStart"}, 656 {10, nullptr, "CreateApplicationAndPushAndRequestToStart"},
630 {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"}, 657 {11, nullptr, "CreateApplicationAndPushAndRequestToStartForQuest"},
631 {12, nullptr, "CreateApplicationAndRequestToStart"}, 658 {12, nullptr, "CreateApplicationAndRequestToStart"},
632 {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, 659 {13, &IApplicationFunctions::CreateApplicationAndRequestToStartForQuest, "CreateApplicationAndRequestToStartForQuest"},
633 "CreateApplicationAndRequestToStartForQuest"},
634 {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"}, 660 {20, &IApplicationFunctions::EnsureSaveData, "EnsureSaveData"},
635 {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"}, 661 {21, &IApplicationFunctions::GetDesiredLanguage, "GetDesiredLanguage"},
636 {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"}, 662 {22, &IApplicationFunctions::SetTerminateResult, "SetTerminateResult"},
@@ -638,10 +664,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
638 {24, nullptr, "GetLaunchStorageInfoForDebug"}, 664 {24, nullptr, "GetLaunchStorageInfoForDebug"},
639 {25, nullptr, "ExtendSaveData"}, 665 {25, nullptr, "ExtendSaveData"},
640 {26, nullptr, "GetSaveDataSize"}, 666 {26, nullptr, "GetSaveDataSize"},
641 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, 667 {30, &IApplicationFunctions::BeginBlockingHomeButtonShortAndLongPressed, "BeginBlockingHomeButtonShortAndLongPressed"},
642 "BeginBlockingHomeButtonShortAndLongPressed"}, 668 {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed, "EndBlockingHomeButtonShortAndLongPressed"},
643 {31, &IApplicationFunctions::EndBlockingHomeButtonShortAndLongPressed,
644 "EndBlockingHomeButtonShortAndLongPressed"},
645 {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"}, 669 {32, &IApplicationFunctions::BeginBlockingHomeButton, "BeginBlockingHomeButton"},
646 {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"}, 670 {33, &IApplicationFunctions::EndBlockingHomeButton, "EndBlockingHomeButton"},
647 {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"}, 671 {40, &IApplicationFunctions::NotifyRunning, "NotifyRunning"},
@@ -666,6 +690,8 @@ IApplicationFunctions::IApplicationFunctions() : ServiceFramework("IApplicationF
666 {1000, nullptr, "CreateMovieMaker"}, 690 {1000, nullptr, "CreateMovieMaker"},
667 {1001, nullptr, "PrepareForJit"}, 691 {1001, nullptr, "PrepareForJit"},
668 }; 692 };
693 // clang-format on
694
669 RegisterHandlers(functions); 695 RegisterHandlers(functions);
670} 696}
671 697
@@ -804,9 +830,11 @@ void InstallInterfaces(SM::ServiceManager& service_manager,
804 std::make_shared<IdleSys>()->InstallAsService(service_manager); 830 std::make_shared<IdleSys>()->InstallAsService(service_manager);
805 std::make_shared<OMM>()->InstallAsService(service_manager); 831 std::make_shared<OMM>()->InstallAsService(service_manager);
806 std::make_shared<SPSM>()->InstallAsService(service_manager); 832 std::make_shared<SPSM>()->InstallAsService(service_manager);
833 std::make_shared<TCAP>()->InstallAsService(service_manager);
807} 834}
808 835
809IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions") { 836IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions") {
837 // clang-format off
810 static const FunctionInfo functions[] = { 838 static const FunctionInfo functions[] = {
811 {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"}, 839 {10, &IHomeMenuFunctions::RequestToGetForeground, "RequestToGetForeground"},
812 {11, nullptr, "LockForeground"}, 840 {11, nullptr, "LockForeground"},
@@ -815,7 +843,10 @@ IHomeMenuFunctions::IHomeMenuFunctions() : ServiceFramework("IHomeMenuFunctions"
815 {21, nullptr, "GetPopFromGeneralChannelEvent"}, 843 {21, nullptr, "GetPopFromGeneralChannelEvent"},
816 {30, nullptr, "GetHomeButtonWriterLockAccessor"}, 844 {30, nullptr, "GetHomeButtonWriterLockAccessor"},
817 {31, nullptr, "GetWriterLockAccessorEx"}, 845 {31, nullptr, "GetWriterLockAccessorEx"},
846 {100, nullptr, "PopRequestLaunchApplicationForDebug"},
818 }; 847 };
848 // clang-format on
849
819 RegisterHandlers(functions); 850 RegisterHandlers(functions);
820} 851}
821 852
@@ -828,6 +859,7 @@ void IHomeMenuFunctions::RequestToGetForeground(Kernel::HLERequestContext& ctx)
828} 859}
829 860
830IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") { 861IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStateController") {
862 // clang-format off
831 static const FunctionInfo functions[] = { 863 static const FunctionInfo functions[] = {
832 {0, nullptr, "RequestToEnterSleep"}, 864 {0, nullptr, "RequestToEnterSleep"},
833 {1, nullptr, "EnterSleep"}, 865 {1, nullptr, "EnterSleep"},
@@ -841,18 +873,23 @@ IGlobalStateController::IGlobalStateController() : ServiceFramework("IGlobalStat
841 {14, nullptr, "ShouldSleepOnBoot"}, 873 {14, nullptr, "ShouldSleepOnBoot"},
842 {15, nullptr, "GetHdcpAuthenticationFailedEvent"}, 874 {15, nullptr, "GetHdcpAuthenticationFailedEvent"},
843 }; 875 };
876 // clang-format on
877
844 RegisterHandlers(functions); 878 RegisterHandlers(functions);
845} 879}
846 880
847IGlobalStateController::~IGlobalStateController() = default; 881IGlobalStateController::~IGlobalStateController() = default;
848 882
849IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreator") { 883IApplicationCreator::IApplicationCreator() : ServiceFramework("IApplicationCreator") {
884 // clang-format off
850 static const FunctionInfo functions[] = { 885 static const FunctionInfo functions[] = {
851 {0, nullptr, "CreateApplication"}, 886 {0, nullptr, "CreateApplication"},
852 {1, nullptr, "PopLaunchRequestedApplication"}, 887 {1, nullptr, "PopLaunchRequestedApplication"},
853 {10, nullptr, "CreateSystemApplication"}, 888 {10, nullptr, "CreateSystemApplication"},
854 {100, nullptr, "PopFloatingApplicationForDevelopment"}, 889 {100, nullptr, "PopFloatingApplicationForDevelopment"},
855 }; 890 };
891 // clang-format on
892
856 RegisterHandlers(functions); 893 RegisterHandlers(functions);
857} 894}
858 895
@@ -860,6 +897,7 @@ IApplicationCreator::~IApplicationCreator() = default;
860 897
861IProcessWindingController::IProcessWindingController() 898IProcessWindingController::IProcessWindingController()
862 : ServiceFramework("IProcessWindingController") { 899 : ServiceFramework("IProcessWindingController") {
900 // clang-format off
863 static const FunctionInfo functions[] = { 901 static const FunctionInfo functions[] = {
864 {0, nullptr, "GetLaunchReason"}, 902 {0, nullptr, "GetLaunchReason"},
865 {11, nullptr, "OpenCallingLibraryApplet"}, 903 {11, nullptr, "OpenCallingLibraryApplet"},
@@ -870,6 +908,8 @@ IProcessWindingController::IProcessWindingController()
870 {40, nullptr, "ReserveToStartAndWaitAndUnwindThis"}, 908 {40, nullptr, "ReserveToStartAndWaitAndUnwindThis"},
871 {41, nullptr, "ReserveToStartAndWait"}, 909 {41, nullptr, "ReserveToStartAndWait"},
872 }; 910 };
911 // clang-format on
912
873 RegisterHandlers(functions); 913 RegisterHandlers(functions);
874} 914}
875 915
diff --git a/src/core/hle/service/am/applet_ae.cpp b/src/core/hle/service/am/applet_ae.cpp
index 4296c255e..68ea778e8 100644
--- a/src/core/hle/service/am/applet_ae.cpp
+++ b/src/core/hle/service/am/applet_ae.cpp
@@ -211,6 +211,7 @@ void AppletAE::OpenLibraryAppletProxyOld(Kernel::HLERequestContext& ctx) {
211 211
212AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) 212AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
213 : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)) { 213 : ServiceFramework("appletAE"), nvflinger(std::move(nvflinger)) {
214 // clang-format off
214 static const FunctionInfo functions[] = { 215 static const FunctionInfo functions[] = {
215 {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"}, 216 {100, &AppletAE::OpenSystemAppletProxy, "OpenSystemAppletProxy"},
216 {200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"}, 217 {200, &AppletAE::OpenLibraryAppletProxyOld, "OpenLibraryAppletProxyOld"},
@@ -218,7 +219,10 @@ AppletAE::AppletAE(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
218 {300, nullptr, "OpenOverlayAppletProxy"}, 219 {300, nullptr, "OpenOverlayAppletProxy"},
219 {350, nullptr, "OpenSystemApplicationProxy"}, 220 {350, nullptr, "OpenSystemApplicationProxy"},
220 {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"}, 221 {400, nullptr, "CreateSelfLibraryAppletCreatorForDevelop"},
222 {401, nullptr, "GetSystemAppletControllerForDebug"},
221 }; 223 };
224 // clang-format on
225
222 RegisterHandlers(functions); 226 RegisterHandlers(functions);
223} 227}
224 228
diff --git a/src/core/hle/service/am/applet_oe.cpp b/src/core/hle/service/am/applet_oe.cpp
index e45cf6e20..60717afd9 100644
--- a/src/core/hle/service/am/applet_oe.cpp
+++ b/src/core/hle/service/am/applet_oe.cpp
@@ -14,6 +14,7 @@ class IApplicationProxy final : public ServiceFramework<IApplicationProxy> {
14public: 14public:
15 explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger) 15 explicit IApplicationProxy(std::shared_ptr<NVFlinger::NVFlinger> nvflinger)
16 : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)) { 16 : ServiceFramework("IApplicationProxy"), nvflinger(std::move(nvflinger)) {
17 // clang-format off
17 static const FunctionInfo functions[] = { 18 static const FunctionInfo functions[] = {
18 {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"}, 19 {0, &IApplicationProxy::GetCommonStateGetter, "GetCommonStateGetter"},
19 {1, &IApplicationProxy::GetSelfController, "GetSelfController"}, 20 {1, &IApplicationProxy::GetSelfController, "GetSelfController"},
@@ -25,6 +26,8 @@ public:
25 {20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"}, 26 {20, &IApplicationProxy::GetApplicationFunctions, "GetApplicationFunctions"},
26 {1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"}, 27 {1000, &IApplicationProxy::GetDebugFunctions, "GetDebugFunctions"},
27 }; 28 };
29 // clang-format on
30
28 RegisterHandlers(functions); 31 RegisterHandlers(functions);
29 } 32 }
30 33
diff --git a/src/core/hle/service/am/idle.cpp b/src/core/hle/service/am/idle.cpp
index 0e3088bc8..f814fe2c0 100644
--- a/src/core/hle/service/am/idle.cpp
+++ b/src/core/hle/service/am/idle.cpp
@@ -12,9 +12,9 @@ IdleSys::IdleSys() : ServiceFramework{"idle:sys"} {
12 {0, nullptr, "GetAutoPowerDownEvent"}, 12 {0, nullptr, "GetAutoPowerDownEvent"},
13 {1, nullptr, "Unknown1"}, 13 {1, nullptr, "Unknown1"},
14 {2, nullptr, "Unknown2"}, 14 {2, nullptr, "Unknown2"},
15 {3, nullptr, "Unknown3"}, 15 {3, nullptr, "SetHandlingContext"},
16 {4, nullptr, "Unknown4"}, 16 {4, nullptr, "LoadAndApplySettings"},
17 {5, nullptr, "Unknown5"}, 17 {5, nullptr, "ReportUserIsActive"},
18 }; 18 };
19 // clang-format on 19 // clang-format on
20 20
diff --git a/src/core/hle/service/am/tcap.cpp b/src/core/hle/service/am/tcap.cpp
new file mode 100644
index 000000000..a75cbdda8
--- /dev/null
+++ b/src/core/hle/service/am/tcap.cpp
@@ -0,0 +1,23 @@
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 "core/hle/service/am/tcap.h"
6
7namespace Service::AM {
8
9TCAP::TCAP() : ServiceFramework{"tcap"} {
10 // clang-format off
11 static const FunctionInfo functions[] = {
12 {0, nullptr, "GetContinuousHighSkinTemperatureEvent"},
13 {1, nullptr, "SetOperationMode"},
14 {2, nullptr, "LoadAndApplySettings"},
15 };
16 // clang-format on
17
18 RegisterHandlers(functions);
19}
20
21TCAP::~TCAP() = default;
22
23} // namespace Service::AM
diff --git a/src/core/hle/service/am/tcap.h b/src/core/hle/service/am/tcap.h
new file mode 100644
index 000000000..2021b55d1
--- /dev/null
+++ b/src/core/hle/service/am/tcap.h
@@ -0,0 +1,17 @@
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/service.h"
8
9namespace Service::AM {
10
11class TCAP final : public ServiceFramework<TCAP> {
12public:
13 explicit TCAP();
14 ~TCAP() override;
15};
16
17} // namespace Service::AM
diff --git a/src/core/hle/service/hid/controllers/npad.cpp b/src/core/hle/service/hid/controllers/npad.cpp
index b26593b4f..b06e65a77 100644
--- a/src/core/hle/service/hid/controllers/npad.cpp
+++ b/src/core/hle/service/hid/controllers/npad.cpp
@@ -26,7 +26,11 @@ constexpr s32 HID_JOYSTICK_MAX = 0x7fff;
26constexpr s32 HID_JOYSTICK_MIN = -0x7fff; 26constexpr s32 HID_JOYSTICK_MIN = -0x7fff;
27constexpr std::size_t NPAD_OFFSET = 0x9A00; 27constexpr std::size_t NPAD_OFFSET = 0x9A00;
28constexpr u32 BATTERY_FULL = 2; 28constexpr u32 BATTERY_FULL = 2;
29 29constexpr u32 NPAD_HANDHELD = 32;
30constexpr u32 NPAD_UNKNOWN = 16; // TODO(ogniK): What is this?
31constexpr u32 MAX_NPAD_ID = 7;
32constexpr Controller_NPad::NPadControllerType PREFERRED_CONTROLLER =
33 Controller_NPad::NPadControllerType::JoyDual;
30constexpr std::array<u32, 10> npad_id_list{ 34constexpr std::array<u32, 10> npad_id_list{
31 0, 1, 2, 3, 4, 5, 6, 7, 32, 16, 35 0, 1, 2, 3, 4, 5, 6, 7, 32, 16,
32}; 36};
@@ -121,7 +125,7 @@ void Controller_NPad::OnInit() {
121 supported_npad_id_types.resize(npad_id_list.size()); 125 supported_npad_id_types.resize(npad_id_list.size());
122 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(), 126 std::memcpy(supported_npad_id_types.data(), npad_id_list.data(),
123 npad_id_list.size() * sizeof(u32)); 127 npad_id_list.size() * sizeof(u32));
124 AddNewController(NPadControllerType::JoyDual); 128 AddNewController(PREFERRED_CONTROLLER);
125 } 129 }
126} 130}
127 131
@@ -218,6 +222,51 @@ void Controller_NPad::OnUpdate(u8* data, std::size_t data_len) {
218 rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX); 222 rstick_entry.x = static_cast<s32>(stick_r_x_f * HID_JOYSTICK_MAX);
219 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX); 223 rstick_entry.y = static_cast<s32>(stick_r_y_f * HID_JOYSTICK_MAX);
220 224
225 if (controller_type == NPadControllerType::JoyLeft ||
226 controller_type == NPadControllerType::JoyRight) {
227 if (npad.properties.is_horizontal) {
228 ControllerPadState state{};
229 AnalogPosition temp_lstick_entry{};
230 AnalogPosition temp_rstick_entry{};
231 if (controller_type == NPadControllerType::JoyLeft) {
232 state.d_down.Assign(pad_state.d_left.Value());
233 state.d_left.Assign(pad_state.d_up.Value());
234 state.d_right.Assign(pad_state.d_down.Value());
235 state.d_up.Assign(pad_state.d_right.Value());
236 state.l.Assign(pad_state.l.Value() | pad_state.sl.Value());
237 state.r.Assign(pad_state.r.Value() | pad_state.sr.Value());
238
239 state.zl.Assign(pad_state.zl.Value());
240 state.plus.Assign(pad_state.minus.Value());
241
242 temp_lstick_entry = lstick_entry;
243 temp_rstick_entry = rstick_entry;
244 std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
245 std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
246 temp_lstick_entry.y *= -1;
247 } else if (controller_type == NPadControllerType::JoyRight) {
248 state.x.Assign(pad_state.a.Value());
249 state.a.Assign(pad_state.b.Value());
250 state.b.Assign(pad_state.y.Value());
251 state.y.Assign(pad_state.b.Value());
252
253 state.l.Assign(pad_state.l.Value() | pad_state.sl.Value());
254 state.r.Assign(pad_state.r.Value() | pad_state.sr.Value());
255 state.zr.Assign(pad_state.zr.Value());
256 state.plus.Assign(pad_state.plus.Value());
257
258 temp_lstick_entry = lstick_entry;
259 temp_rstick_entry = rstick_entry;
260 std::swap(temp_lstick_entry.x, temp_lstick_entry.y);
261 std::swap(temp_rstick_entry.x, temp_rstick_entry.y);
262 temp_rstick_entry.x *= -1;
263 }
264 pad_state.raw = state.raw;
265 lstick_entry = temp_lstick_entry;
266 rstick_entry = temp_rstick_entry;
267 }
268 }
269
221 auto& main_controller = 270 auto& main_controller =
222 npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index]; 271 npad.main_controller_states.npad[npad.main_controller_states.common.last_entry_index];
223 auto& handheld_entry = 272 auto& handheld_entry =
@@ -320,6 +369,16 @@ void Controller_NPad::SetSupportedNPadIdTypes(u8* data, std::size_t length) {
320 supported_npad_id_types.clear(); 369 supported_npad_id_types.clear();
321 supported_npad_id_types.resize(length / sizeof(u32)); 370 supported_npad_id_types.resize(length / sizeof(u32));
322 std::memcpy(supported_npad_id_types.data(), data, length); 371 std::memcpy(supported_npad_id_types.data(), data, length);
372 for (std::size_t i = 0; i < connected_controllers.size(); i++) {
373 auto& controller = connected_controllers[i];
374 if (!controller.is_connected) {
375 continue;
376 }
377 if (!IsControllerSupported(PREFERRED_CONTROLLER)) {
378 controller.type = DecideBestController(PREFERRED_CONTROLLER);
379 InitNewlyAddedControler(i);
380 }
381 }
323} 382}
324 383
325void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) { 384void Controller_NPad::GetSupportedNpadIdTypes(u32* data, std::size_t max_length) {
@@ -351,11 +410,11 @@ void Controller_NPad::VibrateController(const std::vector<u32>& controller_ids,
351 for (std::size_t i = 0; i < controller_ids.size(); i++) { 410 for (std::size_t i = 0; i < controller_ids.size(); i++) {
352 std::size_t controller_pos = i; 411 std::size_t controller_pos = i;
353 // Handheld controller conversion 412 // Handheld controller conversion
354 if (controller_pos == 32) { 413 if (controller_pos == NPAD_HANDHELD) {
355 controller_pos = 8; 414 controller_pos = 8;
356 } 415 }
357 // Unknown controller conversion 416 // Unknown controller conversion
358 if (controller_pos == 16) { 417 if (controller_pos == NPAD_UNKNOWN) {
359 controller_pos = 9; 418 controller_pos = 9;
360 } 419 }
361 if (connected_controllers[controller_pos].is_connected) { 420 if (connected_controllers[controller_pos].is_connected) {
@@ -433,4 +492,128 @@ Controller_NPad::LedPattern Controller_NPad::GetLedPattern(u32 npad_id) {
433void Controller_NPad::SetVibrationEnabled(bool can_vibrate) { 492void Controller_NPad::SetVibrationEnabled(bool can_vibrate) {
434 can_controllers_vibrate = can_vibrate; 493 can_controllers_vibrate = can_vibrate;
435} 494}
495
496bool Controller_NPad::IsControllerSupported(NPadControllerType controller) const {
497 const bool support_handheld =
498 std::find(supported_npad_id_types.begin(), supported_npad_id_types.end(), NPAD_HANDHELD) !=
499 supported_npad_id_types.end();
500 if (controller == NPadControllerType::Handheld) {
501 // Handheld is not even a supported type, lets stop here
502 if (!support_handheld) {
503 return false;
504 }
505 // Handheld should not be supported in docked mode
506 if (Settings::values.use_docked_mode) {
507 return false;
508 }
509
510 return true;
511 }
512 if (std::any_of(supported_npad_id_types.begin(), supported_npad_id_types.end(),
513 [](u32 npad_id) { return npad_id <= MAX_NPAD_ID; })) {
514 switch (controller) {
515 case NPadControllerType::ProController:
516 return style.pro_controller;
517 case NPadControllerType::JoyDual:
518 return style.joycon_dual;
519 case NPadControllerType::JoyLeft:
520 return style.joycon_left;
521 case NPadControllerType::JoyRight:
522 return style.joycon_right;
523 case NPadControllerType::Pokeball:
524 return style.pokeball;
525 default:
526 return false;
527 }
528 }
529 return false;
530}
531
532Controller_NPad::NPadControllerType Controller_NPad::DecideBestController(
533 NPadControllerType priority) const {
534 if (IsControllerSupported(priority)) {
535 return priority;
536 }
537 const auto is_docked = Settings::values.use_docked_mode;
538 if (is_docked && priority == NPadControllerType::Handheld) {
539 priority = NPadControllerType::JoyDual;
540 if (IsControllerSupported(priority)) {
541 return priority;
542 }
543 }
544 std::vector<NPadControllerType> priority_list;
545 switch (priority) {
546 case NPadControllerType::ProController:
547 priority_list.push_back(NPadControllerType::JoyDual);
548 if (!is_docked) {
549 priority_list.push_back(NPadControllerType::Handheld);
550 }
551 priority_list.push_back(NPadControllerType::JoyLeft);
552 priority_list.push_back(NPadControllerType::JoyRight);
553 priority_list.push_back(NPadControllerType::Pokeball);
554 break;
555 case NPadControllerType::Handheld:
556 priority_list.push_back(NPadControllerType::JoyDual);
557 priority_list.push_back(NPadControllerType::ProController);
558 priority_list.push_back(NPadControllerType::JoyLeft);
559 priority_list.push_back(NPadControllerType::JoyRight);
560 priority_list.push_back(NPadControllerType::Pokeball);
561 break;
562 case NPadControllerType::JoyDual:
563 if (!is_docked) {
564 priority_list.push_back(NPadControllerType::Handheld);
565 }
566 priority_list.push_back(NPadControllerType::ProController);
567 priority_list.push_back(NPadControllerType::JoyLeft);
568 priority_list.push_back(NPadControllerType::JoyRight);
569 priority_list.push_back(NPadControllerType::Pokeball);
570 break;
571 case NPadControllerType::JoyLeft:
572 priority_list.push_back(NPadControllerType::JoyRight);
573 priority_list.push_back(NPadControllerType::JoyDual);
574 if (!is_docked) {
575 priority_list.push_back(NPadControllerType::Handheld);
576 }
577 priority_list.push_back(NPadControllerType::ProController);
578 priority_list.push_back(NPadControllerType::Pokeball);
579 break;
580 case NPadControllerType::JoyRight:
581 priority_list.push_back(NPadControllerType::JoyLeft);
582 priority_list.push_back(NPadControllerType::JoyDual);
583 if (!is_docked) {
584 priority_list.push_back(NPadControllerType::Handheld);
585 }
586 priority_list.push_back(NPadControllerType::ProController);
587 priority_list.push_back(NPadControllerType::Pokeball);
588 break;
589 case NPadControllerType::Pokeball:
590 priority_list.push_back(NPadControllerType::JoyLeft);
591 priority_list.push_back(NPadControllerType::JoyRight);
592 priority_list.push_back(NPadControllerType::JoyDual);
593 if (!is_docked) {
594 priority_list.push_back(NPadControllerType::Handheld);
595 }
596 priority_list.push_back(NPadControllerType::ProController);
597 break;
598 default:
599 priority_list.push_back(NPadControllerType::JoyDual);
600 if (!is_docked) {
601 priority_list.push_back(NPadControllerType::Handheld);
602 }
603 priority_list.push_back(NPadControllerType::ProController);
604 priority_list.push_back(NPadControllerType::JoyLeft);
605 priority_list.push_back(NPadControllerType::JoyRight);
606 priority_list.push_back(NPadControllerType::JoyDual);
607 }
608
609 const auto iter = std::find_if(priority_list.begin(), priority_list.end(),
610 [this](auto type) { return IsControllerSupported(type); });
611 if (iter == priority_list.end()) {
612 UNIMPLEMENTED_MSG("Could not find supported controller!");
613 return priority;
614 }
615
616 return *iter;
617}
618
436} // namespace Service::HID 619} // namespace Service::HID
diff --git a/src/core/hle/service/hid/controllers/npad.h b/src/core/hle/service/hid/controllers/npad.h
index 7c0f93acf..ac86985ff 100644
--- a/src/core/hle/service/hid/controllers/npad.h
+++ b/src/core/hle/service/hid/controllers/npad.h
@@ -283,5 +283,7 @@ private:
283 bool can_controllers_vibrate{true}; 283 bool can_controllers_vibrate{true};
284 284
285 void InitNewlyAddedControler(std::size_t controller_idx); 285 void InitNewlyAddedControler(std::size_t controller_idx);
286 bool IsControllerSupported(NPadControllerType controller) const;
287 NPadControllerType DecideBestController(NPadControllerType priority) const;
286}; 288};
287} // namespace Service::HID 289} // namespace Service::HID
diff --git a/src/core/hle/service/hid/hid.cpp b/src/core/hle/service/hid/hid.cpp
index beb89218a..a9aa9ec78 100644
--- a/src/core/hle/service/hid/hid.cpp
+++ b/src/core/hle/service/hid/hid.cpp
@@ -827,6 +827,7 @@ public:
827 {11, nullptr, "EnableJoyPollingReceiveMode"}, 827 {11, nullptr, "EnableJoyPollingReceiveMode"},
828 {12, nullptr, "DisableJoyPollingReceiveMode"}, 828 {12, nullptr, "DisableJoyPollingReceiveMode"},
829 {13, nullptr, "GetPollingData"}, 829 {13, nullptr, "GetPollingData"},
830 {14, nullptr, "SetStatusManagerType"},
830 }; 831 };
831 // clang-format on 832 // clang-format on
832 833
diff --git a/src/core/hle/service/lbl/lbl.cpp b/src/core/hle/service/lbl/lbl.cpp
index 7321584e1..164c57e18 100644
--- a/src/core/hle/service/lbl/lbl.cpp
+++ b/src/core/hle/service/lbl/lbl.cpp
@@ -18,35 +18,35 @@ public:
18 explicit LBL() : ServiceFramework{"lbl"} { 18 explicit LBL() : ServiceFramework{"lbl"} {
19 // clang-format off 19 // clang-format off
20 static const FunctionInfo functions[] = { 20 static const FunctionInfo functions[] = {
21 {0, nullptr, "Unknown1"}, 21 {0, nullptr, "SaveCurrentSetting"},
22 {1, nullptr, "Unknown2"}, 22 {1, nullptr, "LoadCurrentSetting"},
23 {2, nullptr, "Unknown3"}, 23 {2, nullptr, "SetCurrentBrightnessSetting"},
24 {3, nullptr, "GetCurrentBacklightLevel"}, 24 {3, nullptr, "GetCurrentBrightnessSetting"},
25 {4, nullptr, "Unknown4"}, 25 {4, nullptr, "ApplyCurrentBrightnessSettingToBacklight"},
26 {5, nullptr, "GetAlsComputedBacklightLevel"}, 26 {5, nullptr, "GetBrightnessSettingAppliedToBacklight"},
27 {6, nullptr, "TurnOffBacklight"}, 27 {6, nullptr, "SwitchBacklightOn"},
28 {7, nullptr, "TurnOnBacklight"}, 28 {7, nullptr, "SwitchBacklightOff"},
29 {8, nullptr, "GetBacklightStatus"}, 29 {8, nullptr, "GetBacklightSwitchStatus"},
30 {9, nullptr, "Unknown5"}, 30 {9, nullptr, "EnableDimming"},
31 {10, nullptr, "Unknown6"}, 31 {10, nullptr, "DisableDimming"},
32 {11, nullptr, "Unknown7"}, 32 {11, nullptr, "IsDimmingEnabled"},
33 {12, nullptr, "Unknown8"}, 33 {12, nullptr, "EnableAutoBrightnessControl"},
34 {13, nullptr, "Unknown9"}, 34 {13, nullptr, "DisableAutoBrightnessControl"},
35 {14, nullptr, "Unknown10"}, 35 {14, nullptr, "IsAutoBrightnessControlEnabled"},
36 {15, nullptr, "GetAutoBrightnessSetting"}, 36 {15, nullptr, "SetAmbientLightSensorValue"},
37 {16, nullptr, "ReadRawLightSensor"}, 37 {16, nullptr, "GetAmbientLightSensorValue"},
38 {17, nullptr, "Unknown11"}, 38 {17, nullptr, "SetBrightnessReflectionDelayLevel"},
39 {18, nullptr, "Unknown12"}, 39 {18, nullptr, "GetBrightnessReflectionDelayLevel"},
40 {19, nullptr, "Unknown13"}, 40 {19, nullptr, "SetCurrentBrightnessMapping"},
41 {20, nullptr, "Unknown14"}, 41 {20, nullptr, "GetCurrentBrightnessMapping"},
42 {21, nullptr, "Unknown15"}, 42 {21, nullptr, "SetCurrentAmbientLightSensorMapping"},
43 {22, nullptr, "Unknown16"}, 43 {22, nullptr, "GetCurrentAmbientLightSensorMapping"},
44 {23, nullptr, "Unknown17"}, 44 {23, nullptr, "IsAmbientLightSensorAvailable"},
45 {24, nullptr, "Unknown18"}, 45 {24, nullptr, "SetCurrentBrightnessSettingForVrMode"},
46 {25, nullptr, "Unknown19"}, 46 {25, nullptr, "GetCurrentBrightnessSettingForVrMode"},
47 {26, &LBL::EnableVrMode, "EnableVrMode"}, 47 {26, &LBL::EnableVrMode, "EnableVrMode"},
48 {27, &LBL::DisableVrMode, "DisableVrMode"}, 48 {27, &LBL::DisableVrMode, "DisableVrMode"},
49 {28, &LBL::GetVrMode, "GetVrMode"}, 49 {28, &LBL::IsVrModeEnabled, "IsVrModeEnabled"},
50 }; 50 };
51 // clang-format on 51 // clang-format on
52 52
@@ -72,7 +72,7 @@ private:
72 LOG_DEBUG(Service_LBL, "called"); 72 LOG_DEBUG(Service_LBL, "called");
73 } 73 }
74 74
75 void GetVrMode(Kernel::HLERequestContext& ctx) { 75 void IsVrModeEnabled(Kernel::HLERequestContext& ctx) {
76 IPC::ResponseBuilder rb{ctx, 3}; 76 IPC::ResponseBuilder rb{ctx, 3};
77 rb.Push(RESULT_SUCCESS); 77 rb.Push(RESULT_SUCCESS);
78 rb.Push(vr_mode_enabled); 78 rb.Push(vr_mode_enabled);
diff --git a/src/core/hle/service/npns/npns.cpp b/src/core/hle/service/npns/npns.cpp
new file mode 100644
index 000000000..ccb6f9da9
--- /dev/null
+++ b/src/core/hle/service/npns/npns.cpp
@@ -0,0 +1,88 @@
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 <memory>
6
7#include "core/hle/service/npns/npns.h"
8#include "core/hle/service/service.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Service::NPNS {
12
13class NPNS_S final : public ServiceFramework<NPNS_S> {
14public:
15 explicit NPNS_S() : ServiceFramework{"npns:s"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {1, nullptr, "ListenAll"},
19 {2, nullptr, "ListenTo"},
20 {3, nullptr, "Receive"},
21 {4, nullptr, "ReceiveRaw"},
22 {5, nullptr, "GetReceiveEvent"},
23 {6, nullptr, "ListenUndelivered"},
24 {7, nullptr, "GetStateChangeEVent"},
25 {11, nullptr, "SubscribeTopic"},
26 {12, nullptr, "UnsubscribeTopic"},
27 {13, nullptr, "QueryIsTopicExist"},
28 {21, nullptr, "CreateToken"},
29 {22, nullptr, "CreateTokenWithApplicationId"},
30 {23, nullptr, "DestroyToken"},
31 {24, nullptr, "DestroyTokenWithApplicationId"},
32 {25, nullptr, "QueryIsTokenValid"},
33 {31, nullptr, "UploadTokenToBaaS"},
34 {32, nullptr, "DestroyTokenForBaaS"},
35 {33, nullptr, "CreateTokenForBaaS"},
36 {34, nullptr, "SetBaaSDeviceAccountIdList"},
37 {101, nullptr, "Suspend"},
38 {102, nullptr, "Resume"},
39 {103, nullptr, "GetState"},
40 {104, nullptr, "GetStatistics"},
41 {105, nullptr, "GetPlayReportRequestEvent"},
42 {111, nullptr, "GetJid"},
43 {112, nullptr, "CreateJid"},
44 {113, nullptr, "DestroyJid"},
45 {114, nullptr, "AttachJid"},
46 {115, nullptr, "DetachJid"},
47 {201, nullptr, "RequestChangeStateForceTimed"},
48 {102, nullptr, "RequestChangeStateForceAsync"},
49 };
50 // clang-format on
51
52 RegisterHandlers(functions);
53 }
54};
55
56class NPNS_U final : public ServiceFramework<NPNS_U> {
57public:
58 explicit NPNS_U() : ServiceFramework{"npns:u"} {
59 // clang-format off
60 static const FunctionInfo functions[] = {
61 {1, nullptr, "ListenAll"},
62 {2, nullptr, "ListenTo"},
63 {3, nullptr, "Receive"},
64 {4, nullptr, "ReceiveRaw"},
65 {5, nullptr, "GetReceiveEvent"},
66 {7, nullptr, "GetStateChangeEVent"},
67 {21, nullptr, "CreateToken"},
68 {23, nullptr, "DestroyToken"},
69 {25, nullptr, "QueryIsTokenValid"},
70 {26, nullptr, "ListenToMyApplicationId"},
71 {101, nullptr, "Suspend"},
72 {102, nullptr, "Resume"},
73 {103, nullptr, "GetState"},
74 {104, nullptr, "GetStatistics"},
75 {111, nullptr, "GetJid"},
76 };
77 // clang-format on
78
79 RegisterHandlers(functions);
80 }
81};
82
83void InstallInterfaces(SM::ServiceManager& sm) {
84 std::make_shared<NPNS_S>()->InstallAsService(sm);
85 std::make_shared<NPNS_U>()->InstallAsService(sm);
86}
87
88} // namespace Service::NPNS
diff --git a/src/core/hle/service/npns/npns.h b/src/core/hle/service/npns/npns.h
new file mode 100644
index 000000000..861cd3e48
--- /dev/null
+++ b/src/core/hle/service/npns/npns.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::NPNS {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::NPNS
diff --git a/src/core/hle/service/prepo/prepo.cpp b/src/core/hle/service/prepo/prepo.cpp
index 6a9eccfb5..e4fcee9f8 100644
--- a/src/core/hle/service/prepo/prepo.cpp
+++ b/src/core/hle/service/prepo/prepo.cpp
@@ -14,20 +14,24 @@ public:
14 explicit PlayReport(const char* name) : ServiceFramework{name} { 14 explicit PlayReport(const char* name) : ServiceFramework{name} {
15 // clang-format off 15 // clang-format off
16 static const FunctionInfo functions[] = { 16 static const FunctionInfo functions[] = {
17 {10100, nullptr, "SaveReport"}, 17 {10100, nullptr, "SaveReportOld"},
18 {10101, &PlayReport::SaveReportWithUser, "SaveReportWithUser"}, 18 {10101, &PlayReport::SaveReportWithUserOld, "SaveReportWithUserOld"},
19 {10102, nullptr, "SaveReport"},
20 {10103, nullptr, "SaveReportWithUser"},
19 {10200, nullptr, "RequestImmediateTransmission"}, 21 {10200, nullptr, "RequestImmediateTransmission"},
20 {10300, nullptr, "GetTransmissionStatus"}, 22 {10300, nullptr, "GetTransmissionStatus"},
21 {20100, nullptr, "SaveSystemReport"}, 23 {20100, nullptr, "SaveSystemReport"},
22 {20200, nullptr, "SetOperationMode"},
23 {20101, nullptr, "SaveSystemReportWithUser"}, 24 {20101, nullptr, "SaveSystemReportWithUser"},
25 {20200, nullptr, "SetOperationMode"},
24 {30100, nullptr, "ClearStorage"}, 26 {30100, nullptr, "ClearStorage"},
27 {30200, nullptr, "ClearStatistics"},
28 {30300, nullptr, "GetStorageUsage"},
29 {30400, nullptr, "GetStatistics"},
30 {30401, nullptr, "GetThroughputHistory"},
31 {30500, nullptr, "GetLastUploadError"},
25 {40100, nullptr, "IsUserAgreementCheckEnabled"}, 32 {40100, nullptr, "IsUserAgreementCheckEnabled"},
26 {40101, nullptr, "SetUserAgreementCheckEnabled"}, 33 {40101, nullptr, "SetUserAgreementCheckEnabled"},
27 {90100, nullptr, "GetStorageUsage"}, 34 {90100, nullptr, "ReadAllReportFiles"},
28 {90200, nullptr, "GetStatistics"},
29 {90201, nullptr, "GetThroughputHistory"},
30 {90300, nullptr, "GetLastUploadError"},
31 }; 35 };
32 // clang-format on 36 // clang-format on
33 37
@@ -35,7 +39,7 @@ public:
35 } 39 }
36 40
37private: 41private:
38 void SaveReportWithUser(Kernel::HLERequestContext& ctx) { 42 void SaveReportWithUserOld(Kernel::HLERequestContext& ctx) {
39 // TODO(ogniK): Do we want to add play report? 43 // TODO(ogniK): Do we want to add play report?
40 LOG_WARNING(Service_PREPO, "(STUBBED) called"); 44 LOG_WARNING(Service_PREPO, "(STUBBED) called");
41 45
@@ -46,6 +50,7 @@ private:
46 50
47void InstallInterfaces(SM::ServiceManager& service_manager) { 51void InstallInterfaces(SM::ServiceManager& service_manager) {
48 std::make_shared<PlayReport>("prepo:a")->InstallAsService(service_manager); 52 std::make_shared<PlayReport>("prepo:a")->InstallAsService(service_manager);
53 std::make_shared<PlayReport>("prepo:a2")->InstallAsService(service_manager);
49 std::make_shared<PlayReport>("prepo:m")->InstallAsService(service_manager); 54 std::make_shared<PlayReport>("prepo:m")->InstallAsService(service_manager);
50 std::make_shared<PlayReport>("prepo:s")->InstallAsService(service_manager); 55 std::make_shared<PlayReport>("prepo:s")->InstallAsService(service_manager);
51 std::make_shared<PlayReport>("prepo:u")->InstallAsService(service_manager); 56 std::make_shared<PlayReport>("prepo:u")->InstallAsService(service_manager);
diff --git a/src/core/hle/service/ptm/psm.cpp b/src/core/hle/service/ptm/psm.cpp
new file mode 100644
index 000000000..c2d5fda94
--- /dev/null
+++ b/src/core/hle/service/ptm/psm.cpp
@@ -0,0 +1,71 @@
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 <memory>
6
7#include "common/logging/log.h"
8#include "core/hle/ipc_helpers.h"
9#include "core/hle/service/ptm/psm.h"
10#include "core/hle/service/service.h"
11#include "core/hle/service/sm/sm.h"
12
13namespace Service::PSM {
14
15constexpr u32 BATTERY_FULLY_CHARGED = 100; // 100% Full
16constexpr u32 BATTERY_CURRENTLY_CHARGING = 1; // Plugged into an official dock
17
18class PSM final : public ServiceFramework<PSM> {
19public:
20 explicit PSM() : ServiceFramework{"psm"} {
21 // clang-format off
22 static const FunctionInfo functions[] = {
23 {0, &PSM::GetBatteryChargePercentage, "GetBatteryChargePercentage"},
24 {1, &PSM::GetChargerType, "GetChargerType"},
25 {2, nullptr, "EnableBatteryCharging"},
26 {3, nullptr, "DisableBatteryCharging"},
27 {4, nullptr, "IsBatteryChargingEnabled"},
28 {5, nullptr, "AcquireControllerPowerSupply"},
29 {6, nullptr, "ReleaseControllerPowerSupply"},
30 {7, nullptr, "OpenSession"},
31 {8, nullptr, "EnableEnoughPowerChargeEmulation"},
32 {9, nullptr, "DisableEnoughPowerChargeEmulation"},
33 {10, nullptr, "EnableFastBatteryCharging"},
34 {11, nullptr, "DisableFastBatteryCharging"},
35 {12, nullptr, "GetBatteryVoltageState"},
36 {13, nullptr, "GetRawBatteryChargePercentage"},
37 {14, nullptr, "IsEnoughPowerSupplied"},
38 {15, nullptr, "GetBatteryAgePercentage"},
39 {16, nullptr, "GetBatteryChargeInfoEvent"},
40 {17, nullptr, "GetBatteryChargeInfoFields"},
41 };
42 // clang-format on
43
44 RegisterHandlers(functions);
45 }
46
47 ~PSM() override = default;
48
49private:
50 void GetBatteryChargePercentage(Kernel::HLERequestContext& ctx) {
51 LOG_WARNING(Service_PSM, "(STUBBED) called");
52
53 IPC::ResponseBuilder rb{ctx, 3};
54 rb.Push(RESULT_SUCCESS);
55 rb.Push<u32>(BATTERY_FULLY_CHARGED);
56 }
57
58 void GetChargerType(Kernel::HLERequestContext& ctx) {
59 LOG_WARNING(Service_PSM, "(STUBBED) called");
60
61 IPC::ResponseBuilder rb{ctx, 3};
62 rb.Push(RESULT_SUCCESS);
63 rb.Push<u32>(BATTERY_CURRENTLY_CHARGING);
64 }
65};
66
67void InstallInterfaces(SM::ServiceManager& sm) {
68 std::make_shared<PSM>()->InstallAsService(sm);
69}
70
71} // namespace Service::PSM
diff --git a/src/core/hle/service/ptm/psm.h b/src/core/hle/service/ptm/psm.h
new file mode 100644
index 000000000..a286793ae
--- /dev/null
+++ b/src/core/hle/service/ptm/psm.h
@@ -0,0 +1,15 @@
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
7namespace Service::SM {
8class ServiceManager;
9}
10
11namespace Service::PSM {
12
13void InstallInterfaces(SM::ServiceManager& sm);
14
15} // namespace Service::PSM
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index a225cb4cb..a4cf45267 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -22,7 +22,7 @@
22#include "core/hle/service/apm/apm.h" 22#include "core/hle/service/apm/apm.h"
23#include "core/hle/service/arp/arp.h" 23#include "core/hle/service/arp/arp.h"
24#include "core/hle/service/audio/audio.h" 24#include "core/hle/service/audio/audio.h"
25#include "core/hle/service/bcat/bcat.h" 25#include "core/hle/service/bcat/module.h"
26#include "core/hle/service/bpc/bpc.h" 26#include "core/hle/service/bpc/bpc.h"
27#include "core/hle/service/btdrv/btdrv.h" 27#include "core/hle/service/btdrv/btdrv.h"
28#include "core/hle/service/btm/btm.h" 28#include "core/hle/service/btm/btm.h"
@@ -48,15 +48,17 @@
48#include "core/hle/service/nfp/nfp.h" 48#include "core/hle/service/nfp/nfp.h"
49#include "core/hle/service/nifm/nifm.h" 49#include "core/hle/service/nifm/nifm.h"
50#include "core/hle/service/nim/nim.h" 50#include "core/hle/service/nim/nim.h"
51#include "core/hle/service/npns/npns.h"
51#include "core/hle/service/ns/ns.h" 52#include "core/hle/service/ns/ns.h"
52#include "core/hle/service/nvdrv/nvdrv.h" 53#include "core/hle/service/nvdrv/nvdrv.h"
53#include "core/hle/service/nvflinger/nvflinger.h" 54#include "core/hle/service/nvflinger/nvflinger.h"
54#include "core/hle/service/pcie/pcie.h" 55#include "core/hle/service/pcie/pcie.h"
55#include "core/hle/service/pctl/pctl.h" 56#include "core/hle/service/pctl/module.h"
56#include "core/hle/service/pcv/pcv.h" 57#include "core/hle/service/pcv/pcv.h"
57#include "core/hle/service/pm/pm.h" 58#include "core/hle/service/pm/pm.h"
58#include "core/hle/service/prepo/prepo.h" 59#include "core/hle/service/prepo/prepo.h"
59#include "core/hle/service/psc/psc.h" 60#include "core/hle/service/psc/psc.h"
61#include "core/hle/service/ptm/psm.h"
60#include "core/hle/service/service.h" 62#include "core/hle/service/service.h"
61#include "core/hle/service/set/settings.h" 63#include "core/hle/service/set/settings.h"
62#include "core/hle/service/sm/sm.h" 64#include "core/hle/service/sm/sm.h"
@@ -236,6 +238,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs)
236 NFP::InstallInterfaces(*sm); 238 NFP::InstallInterfaces(*sm);
237 NIFM::InstallInterfaces(*sm); 239 NIFM::InstallInterfaces(*sm);
238 NIM::InstallInterfaces(*sm); 240 NIM::InstallInterfaces(*sm);
241 NPNS::InstallInterfaces(*sm);
239 NS::InstallInterfaces(*sm); 242 NS::InstallInterfaces(*sm);
240 Nvidia::InstallInterfaces(*sm, *nv_flinger); 243 Nvidia::InstallInterfaces(*sm, *nv_flinger);
241 PCIe::InstallInterfaces(*sm); 244 PCIe::InstallInterfaces(*sm);
@@ -244,6 +247,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, FileSys::VfsFilesystem& vfs)
244 PlayReport::InstallInterfaces(*sm); 247 PlayReport::InstallInterfaces(*sm);
245 PM::InstallInterfaces(*sm); 248 PM::InstallInterfaces(*sm);
246 PSC::InstallInterfaces(*sm); 249 PSC::InstallInterfaces(*sm);
250 PSM::InstallInterfaces(*sm);
247 Set::InstallInterfaces(*sm); 251 Set::InstallInterfaces(*sm);
248 Sockets::InstallInterfaces(*sm); 252 Sockets::InstallInterfaces(*sm);
249 SPL::InstallInterfaces(*sm); 253 SPL::InstallInterfaces(*sm);
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 8afd26fe9..bca014a4a 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -13,8 +13,7 @@
13#include "video_core/renderer_base.h" 13#include "video_core/renderer_base.h"
14#include "video_core/textures/texture.h" 14#include "video_core/textures/texture.h"
15 15
16namespace Tegra { 16namespace Tegra::Engines {
17namespace Engines {
18 17
19/// First register id that is actually a Macro call. 18/// First register id that is actually a Macro call.
20constexpr u32 MacroRegistersStart = 0xE00; 19constexpr u32 MacroRegistersStart = 0xE00;
@@ -408,5 +407,4 @@ void Maxwell3D::ProcessClearBuffers() {
408 rasterizer.Clear(); 407 rasterizer.Clear();
409} 408}
410 409
411} // namespace Engines 410} // namespace Tegra::Engines
412} // namespace Tegra
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index c8af1c6b6..0e09a7ee5 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -643,8 +643,10 @@ public:
643 u32 d3d_cull_mode; 643 u32 d3d_cull_mode;
644 644
645 ComparisonOp depth_test_func; 645 ComparisonOp depth_test_func;
646 float alpha_test_ref;
647 ComparisonOp alpha_test_func;
646 648
647 INSERT_PADDING_WORDS(0xB); 649 INSERT_PADDING_WORDS(0x9);
648 650
649 struct { 651 struct {
650 u32 separate_alpha; 652 u32 separate_alpha;
diff --git a/src/video_core/engines/maxwell_compute.cpp b/src/video_core/engines/maxwell_compute.cpp
index 59e28b22d..8b5f08351 100644
--- a/src/video_core/engines/maxwell_compute.cpp
+++ b/src/video_core/engines/maxwell_compute.cpp
@@ -6,8 +6,7 @@
6#include "core/core.h" 6#include "core/core.h"
7#include "video_core/engines/maxwell_compute.h" 7#include "video_core/engines/maxwell_compute.h"
8 8
9namespace Tegra { 9namespace Tegra::Engines {
10namespace Engines {
11 10
12void MaxwellCompute::WriteReg(u32 method, u32 value) { 11void MaxwellCompute::WriteReg(u32 method, u32 value) {
13 ASSERT_MSG(method < Regs::NUM_REGS, 12 ASSERT_MSG(method < Regs::NUM_REGS,
@@ -26,5 +25,4 @@ void MaxwellCompute::WriteReg(u32 method, u32 value) {
26 } 25 }
27} 26}
28 27
29} // namespace Engines 28} // namespace Tegra::Engines
30} // namespace Tegra
diff --git a/src/video_core/engines/maxwell_dma.cpp b/src/video_core/engines/maxwell_dma.cpp
index 103cd110e..b8a78cf82 100644
--- a/src/video_core/engines/maxwell_dma.cpp
+++ b/src/video_core/engines/maxwell_dma.cpp
@@ -7,8 +7,7 @@
7#include "video_core/rasterizer_interface.h" 7#include "video_core/rasterizer_interface.h"
8#include "video_core/textures/decoders.h" 8#include "video_core/textures/decoders.h"
9 9
10namespace Tegra { 10namespace Tegra::Engines {
11namespace Engines {
12 11
13MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager) 12MaxwellDMA::MaxwellDMA(VideoCore::RasterizerInterface& rasterizer, MemoryManager& memory_manager)
14 : memory_manager(memory_manager), rasterizer{rasterizer} {} 13 : memory_manager(memory_manager), rasterizer{rasterizer} {}
@@ -78,9 +77,9 @@ void MaxwellDMA::HandleCopy() {
78 77
79 ASSERT(regs.exec.enable_2d == 1); 78 ASSERT(regs.exec.enable_2d == 1);
80 79
81 std::size_t copy_size = regs.x_count * regs.y_count; 80 const std::size_t copy_size = regs.x_count * regs.y_count;
82 81
83 const auto FlushAndInvalidate = [&](u32 src_size, u32 dst_size) { 82 const auto FlushAndInvalidate = [&](u32 src_size, u64 dst_size) {
84 // TODO(Subv): For now, manually flush the regions until we implement GPU-accelerated 83 // TODO(Subv): For now, manually flush the regions until we implement GPU-accelerated
85 // copying. 84 // copying.
86 rasterizer.FlushRegion(source_cpu, src_size); 85 rasterizer.FlushRegion(source_cpu, src_size);
@@ -91,14 +90,11 @@ void MaxwellDMA::HandleCopy() {
91 rasterizer.InvalidateRegion(dest_cpu, dst_size); 90 rasterizer.InvalidateRegion(dest_cpu, dst_size);
92 }; 91 };
93 92
94 u8* src_buffer = Memory::GetPointer(source_cpu);
95 u8* dst_buffer = Memory::GetPointer(dest_cpu);
96
97 if (regs.exec.is_dst_linear && !regs.exec.is_src_linear) { 93 if (regs.exec.is_dst_linear && !regs.exec.is_src_linear) {
98 ASSERT(regs.src_params.size_z == 1); 94 ASSERT(regs.src_params.size_z == 1);
99 // If the input is tiled and the output is linear, deswizzle the input and copy it over. 95 // If the input is tiled and the output is linear, deswizzle the input and copy it over.
100 96
101 u32 src_bytes_per_pixel = regs.src_pitch / regs.src_params.size_x; 97 const u32 src_bytes_per_pixel = regs.src_pitch / regs.src_params.size_x;
102 98
103 FlushAndInvalidate(regs.src_pitch * regs.src_params.size_y, 99 FlushAndInvalidate(regs.src_pitch * regs.src_params.size_y,
104 copy_size * src_bytes_per_pixel); 100 copy_size * src_bytes_per_pixel);
@@ -111,7 +107,7 @@ void MaxwellDMA::HandleCopy() {
111 ASSERT(regs.dst_params.size_z == 1); 107 ASSERT(regs.dst_params.size_z == 1);
112 ASSERT(regs.src_pitch == regs.x_count); 108 ASSERT(regs.src_pitch == regs.x_count);
113 109
114 u32 src_bpp = regs.src_pitch / regs.x_count; 110 const u32 src_bpp = regs.src_pitch / regs.x_count;
115 111
116 FlushAndInvalidate(regs.src_pitch * regs.y_count, 112 FlushAndInvalidate(regs.src_pitch * regs.y_count,
117 regs.dst_params.size_x * regs.dst_params.size_y * src_bpp); 113 regs.dst_params.size_x * regs.dst_params.size_y * src_bpp);
@@ -122,5 +118,4 @@ void MaxwellDMA::HandleCopy() {
122 } 118 }
123} 119}
124 120
125} // namespace Engines 121} // namespace Tegra::Engines
126} // namespace Tegra
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index e3d67ff87..6cd08d28b 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -214,7 +214,7 @@ enum class IMinMaxExchange : u64 {
214 XHi = 3, 214 XHi = 3,
215}; 215};
216 216
217enum class VmadType : u64 { 217enum class VideoType : u64 {
218 Size16_Low = 0, 218 Size16_Low = 0,
219 Size16_High = 1, 219 Size16_High = 1,
220 Size32 = 2, 220 Size32 = 2,
@@ -564,6 +564,10 @@ union Instruction {
564 } fmul; 564 } fmul;
565 565
566 union { 566 union {
567 BitField<55, 1, u64> saturate;
568 } fmul32;
569
570 union {
567 BitField<48, 1, u64> is_signed; 571 BitField<48, 1, u64> is_signed;
568 } shift; 572 } shift;
569 573
@@ -753,7 +757,6 @@ union Instruction {
753 BitField<45, 2, PredOperation> op; 757 BitField<45, 2, PredOperation> op;
754 BitField<47, 1, u64> ftz; 758 BitField<47, 1, u64> ftz;
755 BitField<48, 4, PredCondition> cond; 759 BitField<48, 4, PredCondition> cond;
756 BitField<56, 1, u64> neg_b;
757 } fsetp; 760 } fsetp;
758 761
759 union { 762 union {
@@ -780,6 +783,14 @@ union Instruction {
780 } psetp; 783 } psetp;
781 784
782 union { 785 union {
786 BitField<43, 4, PredCondition> cond;
787 BitField<45, 2, PredOperation> op;
788 BitField<3, 3, u64> pred3;
789 BitField<0, 3, u64> pred0;
790 BitField<39, 3, u64> pred39;
791 } vsetp;
792
793 union {
783 BitField<12, 3, u64> pred12; 794 BitField<12, 3, u64> pred12;
784 BitField<15, 1, u64> neg_pred12; 795 BitField<15, 1, u64> neg_pred12;
785 BitField<24, 2, PredOperation> cond; 796 BitField<24, 2, PredOperation> cond;
@@ -828,7 +839,6 @@ union Instruction {
828 BitField<53, 1, u64> neg_b; 839 BitField<53, 1, u64> neg_b;
829 BitField<54, 1, u64> abs_a; 840 BitField<54, 1, u64> abs_a;
830 BitField<55, 1, u64> ftz; 841 BitField<55, 1, u64> ftz;
831 BitField<56, 1, u64> neg_imm;
832 } fset; 842 } fset;
833 843
834 union { 844 union {
@@ -1152,15 +1162,17 @@ union Instruction {
1152 union { 1162 union {
1153 BitField<48, 1, u64> signed_a; 1163 BitField<48, 1, u64> signed_a;
1154 BitField<38, 1, u64> is_byte_chunk_a; 1164 BitField<38, 1, u64> is_byte_chunk_a;
1155 BitField<36, 2, VmadType> type_a; 1165 BitField<36, 2, VideoType> type_a;
1156 BitField<36, 2, u64> byte_height_a; 1166 BitField<36, 2, u64> byte_height_a;
1157 1167
1158 BitField<49, 1, u64> signed_b; 1168 BitField<49, 1, u64> signed_b;
1159 BitField<50, 1, u64> use_register_b; 1169 BitField<50, 1, u64> use_register_b;
1160 BitField<30, 1, u64> is_byte_chunk_b; 1170 BitField<30, 1, u64> is_byte_chunk_b;
1161 BitField<28, 2, VmadType> type_b; 1171 BitField<28, 2, VideoType> type_b;
1162 BitField<28, 2, u64> byte_height_b; 1172 BitField<28, 2, u64> byte_height_b;
1173 } video;
1163 1174
1175 union {
1164 BitField<51, 2, VmadShr> shr; 1176 BitField<51, 2, VmadShr> shr;
1165 BitField<55, 1, u64> saturate; // Saturates the result (a * b + c) 1177 BitField<55, 1, u64> saturate; // Saturates the result (a * b + c)
1166 BitField<47, 1, u64> cc; 1178 BitField<47, 1, u64> cc;
@@ -1211,11 +1223,13 @@ public:
1211 KIL, 1223 KIL,
1212 SSY, 1224 SSY,
1213 SYNC, 1225 SYNC,
1226 BRK,
1214 DEPBAR, 1227 DEPBAR,
1215 BFE_C, 1228 BFE_C,
1216 BFE_R, 1229 BFE_R,
1217 BFE_IMM, 1230 BFE_IMM,
1218 BRA, 1231 BRA,
1232 PBK,
1219 LD_A, 1233 LD_A,
1220 LD_C, 1234 LD_C,
1221 ST_A, 1235 ST_A,
@@ -1234,6 +1248,7 @@ public:
1234 OUT_R, // Emit vertex/primitive 1248 OUT_R, // Emit vertex/primitive
1235 ISBERD, 1249 ISBERD,
1236 VMAD, 1250 VMAD,
1251 VSETP,
1237 FFMA_IMM, // Fused Multiply and Add 1252 FFMA_IMM, // Fused Multiply and Add
1238 FFMA_CR, 1253 FFMA_CR,
1239 FFMA_RC, 1254 FFMA_RC,
@@ -1372,7 +1387,7 @@ public:
1372 /// conditionally executed). 1387 /// conditionally executed).
1373 static bool IsPredicatedInstruction(Id opcode) { 1388 static bool IsPredicatedInstruction(Id opcode) {
1374 // TODO(Subv): Add the rest of unpredicated instructions. 1389 // TODO(Subv): Add the rest of unpredicated instructions.
1375 return opcode != Id::SSY; 1390 return opcode != Id::SSY && opcode != Id::PBK;
1376 } 1391 }
1377 1392
1378 class Matcher { 1393 class Matcher {
@@ -1468,9 +1483,11 @@ private:
1468#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name) 1483#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)
1469 INST("111000110011----", Id::KIL, Type::Flow, "KIL"), 1484 INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
1470 INST("111000101001----", Id::SSY, Type::Flow, "SSY"), 1485 INST("111000101001----", Id::SSY, Type::Flow, "SSY"),
1486 INST("111000101010----", Id::PBK, Type::Flow, "PBK"),
1471 INST("111000100100----", Id::BRA, Type::Flow, "BRA"), 1487 INST("111000100100----", Id::BRA, Type::Flow, "BRA"),
1488 INST("1111000011111---", Id::SYNC, Type::Flow, "SYNC"),
1489 INST("111000110100---", Id::BRK, Type::Flow, "BRK"),
1472 INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"), 1490 INST("1111000011110---", Id::DEPBAR, Type::Synch, "DEPBAR"),
1473 INST("1111000011111---", Id::SYNC, Type::Synch, "SYNC"),
1474 INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"), 1491 INST("1110111111011---", Id::LD_A, Type::Memory, "LD_A"),
1475 INST("1110111110010---", Id::LD_C, Type::Memory, "LD_C"), 1492 INST("1110111110010---", Id::LD_C, Type::Memory, "LD_C"),
1476 INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"), 1493 INST("1110111111110---", Id::ST_A, Type::Memory, "ST_A"),
@@ -1489,6 +1506,7 @@ private:
1489 INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"), 1506 INST("1111101111100---", Id::OUT_R, Type::Trivial, "OUT_R"),
1490 INST("1110111111010---", Id::ISBERD, Type::Trivial, "ISBERD"), 1507 INST("1110111111010---", Id::ISBERD, Type::Trivial, "ISBERD"),
1491 INST("01011111--------", Id::VMAD, Type::Trivial, "VMAD"), 1508 INST("01011111--------", Id::VMAD, Type::Trivial, "VMAD"),
1509 INST("0101000011110---", Id::VSETP, Type::Trivial, "VSETP"),
1492 INST("0011001-1-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"), 1510 INST("0011001-1-------", Id::FFMA_IMM, Type::Ffma, "FFMA_IMM"),
1493 INST("010010011-------", Id::FFMA_CR, Type::Ffma, "FFMA_CR"), 1511 INST("010010011-------", Id::FFMA_CR, Type::Ffma, "FFMA_CR"),
1494 INST("010100011-------", Id::FFMA_RC, Type::Ffma, "FFMA_RC"), 1512 INST("010100011-------", Id::FFMA_RC, Type::Ffma, "FFMA_RC"),
@@ -1608,4 +1626,4 @@ private:
1608 } 1626 }
1609}; 1627};
1610 1628
1611} // namespace Tegra::Shader 1629} // namespace Tegra::Shader \ No newline at end of file
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 3daccf82f..be51c5215 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -570,10 +570,11 @@ void RasterizerOpenGL::DrawArrays() {
570 SyncBlendState(); 570 SyncBlendState();
571 SyncLogicOpState(); 571 SyncLogicOpState();
572 SyncCullMode(); 572 SyncCullMode();
573 SyncAlphaTest();
574 SyncScissorTest(); 573 SyncScissorTest();
574 // Alpha Testing is synced on shaders.
575 SyncTransformFeedback(); 575 SyncTransformFeedback();
576 SyncPointState(); 576 SyncPointState();
577 CheckAlphaTests();
577 578
578 // TODO(bunnei): Sync framebuffer_scale uniform here 579 // TODO(bunnei): Sync framebuffer_scale uniform here
579 // TODO(bunnei): Sync scissorbox uniform(s) here 580 // TODO(bunnei): Sync scissorbox uniform(s) here
@@ -1007,17 +1008,6 @@ void RasterizerOpenGL::SyncLogicOpState() {
1007 state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation); 1008 state.logic_op.operation = MaxwellToGL::LogicOp(regs.logic_op.operation);
1008} 1009}
1009 1010
1010void RasterizerOpenGL::SyncAlphaTest() {
1011 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1012
1013 // TODO(Rodrigo): Alpha testing is a legacy OpenGL feature, but it can be
1014 // implemented with a test+discard in fragment shaders.
1015 if (regs.alpha_test_enabled != 0) {
1016 LOG_CRITICAL(Render_OpenGL, "Alpha testing is not implemented");
1017 UNREACHABLE();
1018 }
1019}
1020
1021void RasterizerOpenGL::SyncScissorTest() { 1011void RasterizerOpenGL::SyncScissorTest() {
1022 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs; 1012 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1023 1013
@@ -1052,4 +1042,15 @@ void RasterizerOpenGL::SyncPointState() {
1052 state.point.size = regs.point_size == 0 ? 1 : regs.point_size; 1042 state.point.size = regs.point_size == 0 ? 1 : regs.point_size;
1053} 1043}
1054 1044
1045void RasterizerOpenGL::CheckAlphaTests() {
1046 const auto& regs = Core::System::GetInstance().GPU().Maxwell3D().regs;
1047
1048 if (regs.alpha_test_enabled != 0 && regs.rt_control.count > 1) {
1049 LOG_CRITICAL(
1050 Render_OpenGL,
1051 "Alpha Testing is enabled with Multiple Render Targets, this behavior is undefined.");
1052 UNREACHABLE();
1053 }
1054}
1055
1055} // namespace OpenGL 1056} // namespace OpenGL
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.h b/src/video_core/renderer_opengl/gl_rasterizer.h
index b1f7ccc7e..0e90a31f5 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.h
+++ b/src/video_core/renderer_opengl/gl_rasterizer.h
@@ -162,9 +162,6 @@ private:
162 /// Syncs the LogicOp state to match the guest state 162 /// Syncs the LogicOp state to match the guest state
163 void SyncLogicOpState(); 163 void SyncLogicOpState();
164 164
165 /// Syncs the alpha test state to match the guest state
166 void SyncAlphaTest();
167
168 /// Syncs the scissor test state to match the guest state 165 /// Syncs the scissor test state to match the guest state
169 void SyncScissorTest(); 166 void SyncScissorTest();
170 167
@@ -174,6 +171,9 @@ private:
174 /// Syncs the point state to match the guest state 171 /// Syncs the point state to match the guest state
175 void SyncPointState(); 172 void SyncPointState();
176 173
174 /// Check asserts for alpha testing.
175 void CheckAlphaTests();
176
177 bool has_ARB_direct_state_access = false; 177 bool has_ARB_direct_state_access = false;
178 bool has_ARB_multi_bind = false; 178 bool has_ARB_multi_bind = false;
179 bool has_ARB_separate_shader_objects = false; 179 bool has_ARB_separate_shader_objects = false;
diff --git a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
index a427353e9..fe4d1bd83 100644
--- a/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_decompiler.cpp
@@ -163,10 +163,11 @@ private:
163 const ExitMethod jmp = Scan(target, end, labels); 163 const ExitMethod jmp = Scan(target, end, labels);
164 return exit_method = ParallelExit(no_jmp, jmp); 164 return exit_method = ParallelExit(no_jmp, jmp);
165 } 165 }
166 case OpCode::Id::SSY: { 166 case OpCode::Id::SSY:
167 // The SSY instruction uses a similar encoding as the BRA instruction. 167 case OpCode::Id::PBK: {
168 // The SSY and PBK use a similar encoding as the BRA instruction.
168 ASSERT_MSG(instr.bra.constant_buffer == 0, 169 ASSERT_MSG(instr.bra.constant_buffer == 0,
169 "Constant buffer SSY is not supported"); 170 "Constant buffer branching is not supported");
170 const u32 target = offset + instr.bra.GetBranchTarget(); 171 const u32 target = offset + instr.bra.GetBranchTarget();
171 labels.insert(target); 172 labels.insert(target);
172 // Continue scanning for an exit method. 173 // Continue scanning for an exit method.
@@ -378,8 +379,8 @@ public:
378 * @param reg The destination register to use. 379 * @param reg The destination register to use.
379 * @param elem The element to use for the operation. 380 * @param elem The element to use for the operation.
380 * @param value The code representing the value to assign. Type has to be half float. 381 * @param value The code representing the value to assign. Type has to be half float.
381 * @param type Half float kind of assignment. 382 * @param merge Half float kind of assignment.
382 * @param dest_num_components Number of components in the destionation. 383 * @param dest_num_components Number of components in the destination.
383 * @param value_num_components Number of components in the value. 384 * @param value_num_components Number of components in the value.
384 * @param is_saturated Optional, when True, saturates the provided value. 385 * @param is_saturated Optional, when True, saturates the provided value.
385 * @param dest_elem Optional, the destination element to use for the operation. 386 * @param dest_elem Optional, the destination element to use for the operation.
@@ -422,6 +423,7 @@ public:
422 * @param reg The destination register to use. 423 * @param reg The destination register to use.
423 * @param elem The element to use for the operation. 424 * @param elem The element to use for the operation.
424 * @param attribute The input attribute to use as the source value. 425 * @param attribute The input attribute to use as the source value.
426 * @param input_mode The input mode.
425 * @param vertex The register that decides which vertex to read from (used in GS). 427 * @param vertex The register that decides which vertex to read from (used in GS).
426 */ 428 */
427 void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute, 429 void SetRegisterToInputAttibute(const Register& reg, u64 elem, Attribute::Index attribute,
@@ -951,7 +953,7 @@ private:
951 // Can't assign to the constant predicate. 953 // Can't assign to the constant predicate.
952 ASSERT(pred != static_cast<u64>(Pred::UnusedIndex)); 954 ASSERT(pred != static_cast<u64>(Pred::UnusedIndex));
953 955
954 const std::string variable = 'p' + std::to_string(pred) + '_' + suffix; 956 std::string variable = 'p' + std::to_string(pred) + '_' + suffix;
955 shader.AddLine(variable + " = " + value + ';'); 957 shader.AddLine(variable + " = " + value + ';');
956 declr_predicates.insert(std::move(variable)); 958 declr_predicates.insert(std::move(variable));
957 } 959 }
@@ -1058,7 +1060,7 @@ private:
1058 /* 1060 /*
1059 * Transforms the input string GLSL operand into an unpacked half float pair. 1061 * Transforms the input string GLSL operand into an unpacked half float pair.
1060 * @note This function returns a float type pair instead of a half float pair. This is because 1062 * @note This function returns a float type pair instead of a half float pair. This is because
1061 * real half floats are not standarized in GLSL but unpackHalf2x16 (which returns a vec2) is. 1063 * real half floats are not standardized in GLSL but unpackHalf2x16 (which returns a vec2) is.
1062 * @param operand Input operand. It has to be an unsigned integer. 1064 * @param operand Input operand. It has to be an unsigned integer.
1063 * @param type How to unpack the unsigned integer to a half float pair. 1065 * @param type How to unpack the unsigned integer to a half float pair.
1064 * @param abs Get the absolute value of unpacked half floats. 1066 * @param abs Get the absolute value of unpacked half floats.
@@ -1232,27 +1234,27 @@ private:
1232 } 1234 }
1233 1235
1234 /* 1236 /*
1235 * Emits code to push the input target address to the SSY address stack, incrementing the stack 1237 * Emits code to push the input target address to the flow address stack, incrementing the stack
1236 * top. 1238 * top.
1237 */ 1239 */
1238 void EmitPushToSSYStack(u32 target) { 1240 void EmitPushToFlowStack(u32 target) {
1239 shader.AddLine('{'); 1241 shader.AddLine('{');
1240 ++shader.scope; 1242 ++shader.scope;
1241 shader.AddLine("ssy_stack[ssy_stack_top] = " + std::to_string(target) + "u;"); 1243 shader.AddLine("flow_stack[flow_stack_top] = " + std::to_string(target) + "u;");
1242 shader.AddLine("ssy_stack_top++;"); 1244 shader.AddLine("flow_stack_top++;");
1243 --shader.scope; 1245 --shader.scope;
1244 shader.AddLine('}'); 1246 shader.AddLine('}');
1245 } 1247 }
1246 1248
1247 /* 1249 /*
1248 * Emits code to pop an address from the SSY address stack, setting the jump address to the 1250 * Emits code to pop an address from the flow address stack, setting the jump address to the
1249 * popped address and decrementing the stack top. 1251 * popped address and decrementing the stack top.
1250 */ 1252 */
1251 void EmitPopFromSSYStack() { 1253 void EmitPopFromFlowStack() {
1252 shader.AddLine('{'); 1254 shader.AddLine('{');
1253 ++shader.scope; 1255 ++shader.scope;
1254 shader.AddLine("ssy_stack_top--;"); 1256 shader.AddLine("flow_stack_top--;");
1255 shader.AddLine("jmp_to = ssy_stack[ssy_stack_top];"); 1257 shader.AddLine("jmp_to = flow_stack[flow_stack_top];");
1256 shader.AddLine("break;"); 1258 shader.AddLine("break;");
1257 --shader.scope; 1259 --shader.scope;
1258 shader.AddLine('}'); 1260 shader.AddLine('}');
@@ -1264,9 +1266,29 @@ private:
1264 1266
1265 ASSERT_MSG(header.ps.omap.sample_mask == 0, "Samplemask write is unimplemented"); 1267 ASSERT_MSG(header.ps.omap.sample_mask == 0, "Samplemask write is unimplemented");
1266 1268
1269 shader.AddLine("if (alpha_test[0] != 0) {");
1270 ++shader.scope;
1271 // We start on the register containing the alpha value in the first RT.
1272 u32 current_reg = 3;
1273 for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets;
1274 ++render_target) {
1275 // TODO(Blinkhawk): verify the behavior of alpha testing on hardware when
1276 // multiple render targets are used.
1277 if (header.ps.IsColorComponentOutputEnabled(render_target, 0) ||
1278 header.ps.IsColorComponentOutputEnabled(render_target, 1) ||
1279 header.ps.IsColorComponentOutputEnabled(render_target, 2) ||
1280 header.ps.IsColorComponentOutputEnabled(render_target, 3)) {
1281 shader.AddLine(fmt::format("if (!AlphaFunc({})) discard;",
1282 regs.GetRegisterAsFloat(current_reg)));
1283 current_reg += 4;
1284 }
1285 }
1286 --shader.scope;
1287 shader.AddLine('}');
1288
1267 // Write the color outputs using the data in the shader registers, disabled 1289 // Write the color outputs using the data in the shader registers, disabled
1268 // rendertargets/components are skipped in the register assignment. 1290 // rendertargets/components are skipped in the register assignment.
1269 u32 current_reg = 0; 1291 current_reg = 0;
1270 for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets; 1292 for (u32 render_target = 0; render_target < Maxwell3D::Regs::NumRenderTargets;
1271 ++render_target) { 1293 ++render_target) {
1272 // TODO(Subv): Figure out how dual-source blending is configured in the Switch. 1294 // TODO(Subv): Figure out how dual-source blending is configured in the Switch.
@@ -1290,6 +1312,63 @@ private:
1290 } 1312 }
1291 } 1313 }
1292 1314
1315 /// Unpacks a video instruction operand (e.g. VMAD).
1316 std::string GetVideoOperand(const std::string& op, bool is_chunk, bool is_signed,
1317 Tegra::Shader::VideoType type, u64 byte_height) {
1318 const std::string value = [&]() {
1319 if (!is_chunk) {
1320 const auto offset = static_cast<u32>(byte_height * 8);
1321 return "((" + op + " >> " + std::to_string(offset) + ") & 0xff)";
1322 }
1323 const std::string zero = "0";
1324
1325 switch (type) {
1326 case Tegra::Shader::VideoType::Size16_Low:
1327 return '(' + op + " & 0xffff)";
1328 case Tegra::Shader::VideoType::Size16_High:
1329 return '(' + op + " >> 16)";
1330 case Tegra::Shader::VideoType::Size32:
1331 // TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when
1332 // this type is used (1 * 1 + 0 == 0x5b800000). Until a better
1333 // explanation is found: assert.
1334 UNIMPLEMENTED();
1335 return zero;
1336 case Tegra::Shader::VideoType::Invalid:
1337 UNREACHABLE_MSG("Invalid instruction encoding");
1338 return zero;
1339 default:
1340 UNREACHABLE();
1341 return zero;
1342 }
1343 }();
1344
1345 if (is_signed) {
1346 return "int(" + value + ')';
1347 }
1348 return value;
1349 };
1350
1351 /// Gets the A operand for a video instruction.
1352 std::string GetVideoOperandA(Instruction instr) {
1353 return GetVideoOperand(regs.GetRegisterAsInteger(instr.gpr8, 0, false),
1354 instr.video.is_byte_chunk_a != 0, instr.video.signed_a,
1355 instr.video.type_a, instr.video.byte_height_a);
1356 }
1357
1358 /// Gets the B operand for a video instruction.
1359 std::string GetVideoOperandB(Instruction instr) {
1360 if (instr.video.use_register_b) {
1361 return GetVideoOperand(regs.GetRegisterAsInteger(instr.gpr20, 0, false),
1362 instr.video.is_byte_chunk_b != 0, instr.video.signed_b,
1363 instr.video.type_b, instr.video.byte_height_b);
1364 } else {
1365 return '(' +
1366 std::to_string(instr.video.signed_b ? static_cast<s16>(instr.alu.GetImm20_16())
1367 : instr.alu.GetImm20_16()) +
1368 ')';
1369 }
1370 }
1371
1293 /** 1372 /**
1294 * Compiles a single instruction from Tegra to GLSL. 1373 * Compiles a single instruction from Tegra to GLSL.
1295 * @param offset the offset of the Tegra shader instruction. 1374 * @param offset the offset of the Tegra shader instruction.
@@ -1459,9 +1538,10 @@ private:
1459 break; 1538 break;
1460 } 1539 }
1461 case OpCode::Id::FMUL32_IMM: { 1540 case OpCode::Id::FMUL32_IMM: {
1462 regs.SetRegisterToFloat( 1541 regs.SetRegisterToFloat(instr.gpr0, 0,
1463 instr.gpr0, 0, 1542 regs.GetRegisterAsFloat(instr.gpr8) + " * " +
1464 regs.GetRegisterAsFloat(instr.gpr8) + " * " + GetImmediate32(instr), 1, 1); 1543 GetImmediate32(instr),
1544 1, 1, instr.fmul32.saturate);
1465 break; 1545 break;
1466 } 1546 }
1467 case OpCode::Id::FADD32I: { 1547 case OpCode::Id::FADD32I: {
@@ -2736,20 +2816,13 @@ private:
2736 break; 2816 break;
2737 } 2817 }
2738 case OpCode::Type::FloatSetPredicate: { 2818 case OpCode::Type::FloatSetPredicate: {
2739 std::string op_a = instr.fsetp.neg_a ? "-" : ""; 2819 const std::string op_a =
2740 op_a += regs.GetRegisterAsFloat(instr.gpr8); 2820 GetOperandAbsNeg(regs.GetRegisterAsFloat(instr.gpr8), instr.fsetp.abs_a != 0,
2741 2821 instr.fsetp.neg_a != 0);
2742 if (instr.fsetp.abs_a) {
2743 op_a = "abs(" + op_a + ')';
2744 }
2745 2822
2746 std::string op_b{}; 2823 std::string op_b;
2747 2824
2748 if (instr.is_b_imm) { 2825 if (instr.is_b_imm) {
2749 if (instr.fsetp.neg_b) {
2750 // Only the immediate version of fsetp has a neg_b bit.
2751 op_b += '-';
2752 }
2753 op_b += '(' + GetImmediate19(instr) + ')'; 2826 op_b += '(' + GetImmediate19(instr) + ')';
2754 } else { 2827 } else {
2755 if (instr.is_b_gpr) { 2828 if (instr.is_b_gpr) {
@@ -2945,33 +3018,24 @@ private:
2945 break; 3018 break;
2946 } 3019 }
2947 case OpCode::Type::FloatSet: { 3020 case OpCode::Type::FloatSet: {
2948 std::string op_a = instr.fset.neg_a ? "-" : ""; 3021 const std::string op_a = GetOperandAbsNeg(regs.GetRegisterAsFloat(instr.gpr8),
2949 op_a += regs.GetRegisterAsFloat(instr.gpr8); 3022 instr.fset.abs_a != 0, instr.fset.neg_a != 0);
2950
2951 if (instr.fset.abs_a) {
2952 op_a = "abs(" + op_a + ')';
2953 }
2954 3023
2955 std::string op_b = instr.fset.neg_b ? "-" : ""; 3024 std::string op_b;
2956 3025
2957 if (instr.is_b_imm) { 3026 if (instr.is_b_imm) {
2958 const std::string imm = GetImmediate19(instr); 3027 const std::string imm = GetImmediate19(instr);
2959 if (instr.fset.neg_imm) 3028 op_b = imm;
2960 op_b += "(-" + imm + ')';
2961 else
2962 op_b += imm;
2963 } else { 3029 } else {
2964 if (instr.is_b_gpr) { 3030 if (instr.is_b_gpr) {
2965 op_b += regs.GetRegisterAsFloat(instr.gpr20); 3031 op_b = regs.GetRegisterAsFloat(instr.gpr20);
2966 } else { 3032 } else {
2967 op_b += regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset, 3033 op_b = regs.GetUniform(instr.cbuf34.index, instr.cbuf34.offset,
2968 GLSLRegister::Type::Float); 3034 GLSLRegister::Type::Float);
2969 } 3035 }
2970 } 3036 }
2971 3037
2972 if (instr.fset.abs_b) { 3038 op_b = GetOperandAbsNeg(op_b, instr.fset.abs_b != 0, instr.fset.neg_b != 0);
2973 op_b = "abs(" + op_b + ')';
2974 }
2975 3039
2976 // The fset instruction sets a register to 1.0 or -1 (depending on the bf bit) if the 3040 // The fset instruction sets a register to 1.0 or -1 (depending on the bf bit) if the
2977 // condition is true, and to 0 otherwise. 3041 // condition is true, and to 0 otherwise.
@@ -3279,16 +3343,32 @@ private:
3279 // The SSY opcode tells the GPU where to re-converge divergent execution paths, it 3343 // The SSY opcode tells the GPU where to re-converge divergent execution paths, it
3280 // sets the target of the jump that the SYNC instruction will make. The SSY opcode 3344 // sets the target of the jump that the SYNC instruction will make. The SSY opcode
3281 // has a similar structure to the BRA opcode. 3345 // has a similar structure to the BRA opcode.
3282 ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer SSY is not supported"); 3346 ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer flow is not supported");
3347
3348 const u32 target = offset + instr.bra.GetBranchTarget();
3349 EmitPushToFlowStack(target);
3350 break;
3351 }
3352 case OpCode::Id::PBK: {
3353 // PBK pushes to a stack the address where BRK will jump to. This shares stack with
3354 // SSY but using SYNC on a PBK address will kill the shader execution. We don't
3355 // emulate this because it's very unlikely a driver will emit such invalid shader.
3356 ASSERT_MSG(instr.bra.constant_buffer == 0, "Constant buffer PBK is not supported");
3283 3357
3284 const u32 target = offset + instr.bra.GetBranchTarget(); 3358 const u32 target = offset + instr.bra.GetBranchTarget();
3285 EmitPushToSSYStack(target); 3359 EmitPushToFlowStack(target);
3286 break; 3360 break;
3287 } 3361 }
3288 case OpCode::Id::SYNC: { 3362 case OpCode::Id::SYNC: {
3289 // The SYNC opcode jumps to the address previously set by the SSY opcode 3363 // The SYNC opcode jumps to the address previously set by the SSY opcode
3290 ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always); 3364 ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
3291 EmitPopFromSSYStack(); 3365 EmitPopFromFlowStack();
3366 break;
3367 }
3368 case OpCode::Id::BRK: {
3369 // The BRK opcode jumps to the address previously set by the PBK opcode
3370 ASSERT(instr.flow.cond == Tegra::Shader::FlowCondition::Always);
3371 EmitPopFromFlowStack();
3292 break; 3372 break;
3293 } 3373 }
3294 case OpCode::Id::DEPBAR: { 3374 case OpCode::Id::DEPBAR: {
@@ -3298,87 +3378,51 @@ private:
3298 break; 3378 break;
3299 } 3379 }
3300 case OpCode::Id::VMAD: { 3380 case OpCode::Id::VMAD: {
3301 const bool signed_a = instr.vmad.signed_a == 1; 3381 const bool result_signed = instr.video.signed_a == 1 || instr.video.signed_b == 1;
3302 const bool signed_b = instr.vmad.signed_b == 1; 3382 const std::string op_a = GetVideoOperandA(instr);
3303 const bool result_signed = signed_a || signed_b; 3383 const std::string op_b = GetVideoOperandB(instr);
3304 boost::optional<std::string> forced_result;
3305
3306 auto Unpack = [&](const std::string& op, bool is_chunk, bool is_signed,
3307 Tegra::Shader::VmadType type, u64 byte_height) {
3308 const std::string value = [&]() {
3309 if (!is_chunk) {
3310 const auto offset = static_cast<u32>(byte_height * 8);
3311 return "((" + op + " >> " + std::to_string(offset) + ") & 0xff)";
3312 }
3313 const std::string zero = "0";
3314
3315 switch (type) {
3316 case Tegra::Shader::VmadType::Size16_Low:
3317 return '(' + op + " & 0xffff)";
3318 case Tegra::Shader::VmadType::Size16_High:
3319 return '(' + op + " >> 16)";
3320 case Tegra::Shader::VmadType::Size32:
3321 // TODO(Rodrigo): From my hardware tests it becomes a bit "mad" when
3322 // this type is used (1 * 1 + 0 == 0x5b800000). Until a better
3323 // explanation is found: assert.
3324 UNREACHABLE_MSG("Unimplemented");
3325 return zero;
3326 case Tegra::Shader::VmadType::Invalid:
3327 // Note(Rodrigo): This flag is invalid according to nvdisasm. From my
3328 // testing (even though it's invalid) this makes the whole instruction
3329 // assign zero to target register.
3330 forced_result = boost::make_optional(zero);
3331 return zero;
3332 default:
3333 UNREACHABLE();
3334 return zero;
3335 }
3336 }();
3337
3338 if (is_signed) {
3339 return "int(" + value + ')';
3340 }
3341 return value;
3342 };
3343
3344 const std::string op_a = Unpack(regs.GetRegisterAsInteger(instr.gpr8, 0, false),
3345 instr.vmad.is_byte_chunk_a != 0, signed_a,
3346 instr.vmad.type_a, instr.vmad.byte_height_a);
3347
3348 std::string op_b;
3349 if (instr.vmad.use_register_b) {
3350 op_b = Unpack(regs.GetRegisterAsInteger(instr.gpr20, 0, false),
3351 instr.vmad.is_byte_chunk_b != 0, signed_b, instr.vmad.type_b,
3352 instr.vmad.byte_height_b);
3353 } else {
3354 op_b = '(' +
3355 std::to_string(signed_b ? static_cast<s16>(instr.alu.GetImm20_16())
3356 : instr.alu.GetImm20_16()) +
3357 ')';
3358 }
3359
3360 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39, 0, result_signed); 3384 const std::string op_c = regs.GetRegisterAsInteger(instr.gpr39, 0, result_signed);
3361 3385
3362 std::string result; 3386 std::string result = '(' + op_a + " * " + op_b + " + " + op_c + ')';
3363 if (forced_result) {
3364 result = *forced_result;
3365 } else {
3366 result = '(' + op_a + " * " + op_b + " + " + op_c + ')';
3367 3387
3368 switch (instr.vmad.shr) { 3388 switch (instr.vmad.shr) {
3369 case Tegra::Shader::VmadShr::Shr7: 3389 case Tegra::Shader::VmadShr::Shr7:
3370 result = '(' + result + " >> 7)"; 3390 result = '(' + result + " >> 7)";
3371 break; 3391 break;
3372 case Tegra::Shader::VmadShr::Shr15: 3392 case Tegra::Shader::VmadShr::Shr15:
3373 result = '(' + result + " >> 15)"; 3393 result = '(' + result + " >> 15)";
3374 break; 3394 break;
3375 }
3376 } 3395 }
3396
3377 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1, 3397 regs.SetRegisterToInteger(instr.gpr0, result_signed, 1, result, 1, 1,
3378 instr.vmad.saturate == 1, 0, Register::Size::Word, 3398 instr.vmad.saturate == 1, 0, Register::Size::Word,
3379 instr.vmad.cc); 3399 instr.vmad.cc);
3380 break; 3400 break;
3381 } 3401 }
3402 case OpCode::Id::VSETP: {
3403 const std::string op_a = GetVideoOperandA(instr);
3404 const std::string op_b = GetVideoOperandB(instr);
3405
3406 // We can't use the constant predicate as destination.
3407 ASSERT(instr.vsetp.pred3 != static_cast<u64>(Pred::UnusedIndex));
3408
3409 const std::string second_pred = GetPredicateCondition(instr.vsetp.pred39, false);
3410
3411 const std::string combiner = GetPredicateCombiner(instr.vsetp.op);
3412
3413 const std::string predicate = GetPredicateComparison(instr.vsetp.cond, op_a, op_b);
3414 // Set the primary predicate to the result of Predicate OP SecondPredicate
3415 SetPredicate(instr.vsetp.pred3,
3416 '(' + predicate + ") " + combiner + " (" + second_pred + ')');
3417
3418 if (instr.vsetp.pred0 != static_cast<u64>(Pred::UnusedIndex)) {
3419 // Set the secondary predicate to the result of !Predicate OP SecondPredicate,
3420 // if enabled
3421 SetPredicate(instr.vsetp.pred0,
3422 "!(" + predicate + ") " + combiner + " (" + second_pred + ')');
3423 }
3424 break;
3425 }
3382 default: { 3426 default: {
3383 LOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->GetName()); 3427 LOG_CRITICAL(HW_GPU, "Unhandled instruction: {}", opcode->GetName());
3384 UNREACHABLE(); 3428 UNREACHABLE();
@@ -3442,11 +3486,11 @@ private:
3442 labels.insert(subroutine.begin); 3486 labels.insert(subroutine.begin);
3443 shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;"); 3487 shader.AddLine("uint jmp_to = " + std::to_string(subroutine.begin) + "u;");
3444 3488
3445 // TODO(Subv): Figure out the actual depth of the SSY stack, for now it seems 3489 // TODO(Subv): Figure out the actual depth of the flow stack, for now it seems
3446 // unlikely that shaders will use 20 nested SSYs. 3490 // unlikely that shaders will use 20 nested SSYs and PBKs.
3447 constexpr u32 SSY_STACK_SIZE = 20; 3491 constexpr u32 FLOW_STACK_SIZE = 20;
3448 shader.AddLine("uint ssy_stack[" + std::to_string(SSY_STACK_SIZE) + "];"); 3492 shader.AddLine("uint flow_stack[" + std::to_string(FLOW_STACK_SIZE) + "];");
3449 shader.AddLine("uint ssy_stack_top = 0u;"); 3493 shader.AddLine("uint flow_stack_top = 0u;");
3450 3494
3451 shader.AddLine("while (true) {"); 3495 shader.AddLine("while (true) {");
3452 ++shader.scope; 3496 ++shader.scope;
@@ -3513,7 +3557,7 @@ private:
3513 3557
3514 // Declarations 3558 // Declarations
3515 std::set<std::string> declr_predicates; 3559 std::set<std::string> declr_predicates;
3516}; // namespace Decompiler 3560}; // namespace OpenGL::GLShader::Decompiler
3517 3561
3518std::string GetCommonDeclarations() { 3562std::string GetCommonDeclarations() {
3519 return fmt::format("#define MAX_CONSTBUFFER_ELEMENTS {}\n", 3563 return fmt::format("#define MAX_CONSTBUFFER_ELEMENTS {}\n",
diff --git a/src/video_core/renderer_opengl/gl_shader_gen.cpp b/src/video_core/renderer_opengl/gl_shader_gen.cpp
index ecbc9d8ed..e883ffb1d 100644
--- a/src/video_core/renderer_opengl/gl_shader_gen.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_gen.cpp
@@ -29,6 +29,7 @@ layout(std140) uniform vs_config {
29 vec4 viewport_flip; 29 vec4 viewport_flip;
30 uvec4 instance_id; 30 uvec4 instance_id;
31 uvec4 flip_stage; 31 uvec4 flip_stage;
32 uvec4 alpha_test;
32}; 33};
33)"; 34)";
34 35
@@ -105,6 +106,7 @@ layout (std140) uniform gs_config {
105 vec4 viewport_flip; 106 vec4 viewport_flip;
106 uvec4 instance_id; 107 uvec4 instance_id;
107 uvec4 flip_stage; 108 uvec4 flip_stage;
109 uvec4 alpha_test;
108}; 110};
109 111
110void main() { 112void main() {
@@ -142,8 +144,33 @@ layout (std140) uniform fs_config {
142 vec4 viewport_flip; 144 vec4 viewport_flip;
143 uvec4 instance_id; 145 uvec4 instance_id;
144 uvec4 flip_stage; 146 uvec4 flip_stage;
147 uvec4 alpha_test;
145}; 148};
146 149
150bool AlphaFunc(in float value) {
151 float ref = uintBitsToFloat(alpha_test[2]);
152 switch (alpha_test[1]) {
153 case 1:
154 return false;
155 case 2:
156 return value < ref;
157 case 3:
158 return value == ref;
159 case 4:
160 return value <= ref;
161 case 5:
162 return value > ref;
163 case 6:
164 return value != ref;
165 case 7:
166 return value >= ref;
167 case 8:
168 return true;
169 default:
170 return false;
171 }
172}
173
147void main() { 174void main() {
148 exec_fragment(); 175 exec_fragment();
149} 176}
@@ -152,4 +179,4 @@ void main() {
152 out += program.first; 179 out += program.first;
153 return {out, program.second}; 180 return {out, program.second};
154} 181}
155} // namespace OpenGL::GLShader \ No newline at end of file 182} // namespace OpenGL::GLShader
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.cpp b/src/video_core/renderer_opengl/gl_shader_manager.cpp
index 010857ec6..8b8869ecb 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.cpp
+++ b/src/video_core/renderer_opengl/gl_shader_manager.cpp
@@ -16,6 +16,17 @@ void MaxwellUniformData::SetFromRegs(const Maxwell3D::State::ShaderStageInfo& sh
16 viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f; 16 viewport_flip[0] = regs.viewport_transform[0].scale_x < 0.0 ? -1.0f : 1.0f;
17 viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f; 17 viewport_flip[1] = regs.viewport_transform[0].scale_y < 0.0 ? -1.0f : 1.0f;
18 18
19 u32 func = static_cast<u32>(regs.alpha_test_func);
20 // Normalize the gl variants of opCompare to be the same as the normal variants
21 u32 op_gl_variant_base = static_cast<u32>(Tegra::Engines::Maxwell3D::Regs::ComparisonOp::Never);
22 if (func >= op_gl_variant_base) {
23 func = func - op_gl_variant_base + 1U;
24 }
25
26 alpha_test.enabled = regs.alpha_test_enabled;
27 alpha_test.func = func;
28 alpha_test.ref = regs.alpha_test_ref;
29
19 // We only assign the instance to the first component of the vector, the rest is just padding. 30 // We only assign the instance to the first component of the vector, the rest is just padding.
20 instance_id[0] = state.current_instance; 31 instance_id[0] = state.current_instance;
21 32
diff --git a/src/video_core/renderer_opengl/gl_shader_manager.h b/src/video_core/renderer_opengl/gl_shader_manager.h
index b3a191cf2..36fe1f04c 100644
--- a/src/video_core/renderer_opengl/gl_shader_manager.h
+++ b/src/video_core/renderer_opengl/gl_shader_manager.h
@@ -22,8 +22,14 @@ struct MaxwellUniformData {
22 alignas(16) GLvec4 viewport_flip; 22 alignas(16) GLvec4 viewport_flip;
23 alignas(16) GLuvec4 instance_id; 23 alignas(16) GLuvec4 instance_id;
24 alignas(16) GLuvec4 flip_stage; 24 alignas(16) GLuvec4 flip_stage;
25 struct alignas(16) {
26 GLuint enabled;
27 GLuint func;
28 GLfloat ref;
29 GLuint padding;
30 } alpha_test;
25}; 31};
26static_assert(sizeof(MaxwellUniformData) == 48, "MaxwellUniformData structure size is incorrect"); 32static_assert(sizeof(MaxwellUniformData) == 64, "MaxwellUniformData structure size is incorrect");
27static_assert(sizeof(MaxwellUniformData) < 16384, 33static_assert(sizeof(MaxwellUniformData) < 16384,
28 "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec"); 34 "MaxwellUniformData structure must be less than 16kb as per the OpenGL spec");
29 35
diff --git a/src/video_core/renderer_opengl/maxwell_to_gl.h b/src/video_core/renderer_opengl/maxwell_to_gl.h
index 3c3bcaae4..0f6dcab2b 100644
--- a/src/video_core/renderer_opengl/maxwell_to_gl.h
+++ b/src/video_core/renderer_opengl/maxwell_to_gl.h
@@ -82,8 +82,20 @@ inline GLenum VertexType(Maxwell::VertexAttribute attrib) {
82 return {}; 82 return {};
83 } 83 }
84 84
85 case Maxwell::VertexAttribute::Type::Float: 85 case Maxwell::VertexAttribute::Type::Float: {
86 return GL_FLOAT; 86 switch (attrib.size) {
87 case Maxwell::VertexAttribute::Size::Size_16:
88 case Maxwell::VertexAttribute::Size::Size_16_16:
89 case Maxwell::VertexAttribute::Size::Size_16_16_16:
90 case Maxwell::VertexAttribute::Size::Size_16_16_16_16:
91 return GL_HALF_FLOAT;
92 case Maxwell::VertexAttribute::Size::Size_32:
93 case Maxwell::VertexAttribute::Size::Size_32_32:
94 case Maxwell::VertexAttribute::Size::Size_32_32_32:
95 case Maxwell::VertexAttribute::Size::Size_32_32_32_32:
96 return GL_FLOAT;
97 }
98 }
87 } 99 }
88 100
89 LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString()); 101 LOG_CRITICAL(Render_OpenGL, "Unimplemented vertex type={}", attrib.TypeString());
diff --git a/src/web_service/CMakeLists.txt b/src/web_service/CMakeLists.txt
index 93878f8ab..01f2d129d 100644
--- a/src/web_service/CMakeLists.txt
+++ b/src/web_service/CMakeLists.txt
@@ -12,5 +12,5 @@ create_target_directory_groups(web_service)
12get_directory_property(OPENSSL_LIBS 12get_directory_property(OPENSSL_LIBS
13 DIRECTORY ${PROJECT_SOURCE_DIR}/externals/libressl 13 DIRECTORY ${PROJECT_SOURCE_DIR}/externals/libressl
14 DEFINITION OPENSSL_LIBS) 14 DEFINITION OPENSSL_LIBS)
15target_compile_definitions(web_service PUBLIC -DCPPHTTPLIB_OPENSSL_SUPPORT) 15target_compile_definitions(web_service PRIVATE -DCPPHTTPLIB_OPENSSL_SUPPORT)
16target_link_libraries(web_service PRIVATE common json-headers ${OPENSSL_LIBS} httplib lurlparser) 16target_link_libraries(web_service PRIVATE common json-headers ${OPENSSL_LIBS} httplib lurlparser)
diff --git a/src/yuzu/CMakeLists.txt b/src/yuzu/CMakeLists.txt
index 0d24e8eb0..9379d9110 100644
--- a/src/yuzu/CMakeLists.txt
+++ b/src/yuzu/CMakeLists.txt
@@ -121,7 +121,7 @@ target_link_libraries(yuzu PRIVATE Boost::boost glad Qt5::OpenGL Qt5::Widgets)
121target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads) 121target_link_libraries(yuzu PRIVATE ${PLATFORM_LIBRARIES} Threads::Threads)
122 122
123if (YUZU_ENABLE_COMPATIBILITY_REPORTING) 123if (YUZU_ENABLE_COMPATIBILITY_REPORTING)
124 add_definitions(-DYUZU_ENABLE_COMPATIBILITY_REPORTING) 124 target_compile_definitions(yuzu PRIVATE -DYUZU_ENABLE_COMPATIBILITY_REPORTING)
125endif() 125endif()
126 126
127if (USE_DISCORD_PRESENCE) 127if (USE_DISCORD_PRESENCE)
diff --git a/src/yuzu/debugger/wait_tree.cpp b/src/yuzu/debugger/wait_tree.cpp
index 7403e9ccd..0c831c9f4 100644
--- a/src/yuzu/debugger/wait_tree.cpp
+++ b/src/yuzu/debugger/wait_tree.cpp
@@ -9,8 +9,8 @@
9#include "core/core.h" 9#include "core/core.h"
10#include "core/hle/kernel/event.h" 10#include "core/hle/kernel/event.h"
11#include "core/hle/kernel/handle_table.h" 11#include "core/hle/kernel/handle_table.h"
12#include "core/hle/kernel/kernel.h"
13#include "core/hle/kernel/mutex.h" 12#include "core/hle/kernel/mutex.h"
13#include "core/hle/kernel/process.h"
14#include "core/hle/kernel/scheduler.h" 14#include "core/hle/kernel/scheduler.h"
15#include "core/hle/kernel/thread.h" 15#include "core/hle/kernel/thread.h"
16#include "core/hle/kernel/timer.h" 16#include "core/hle/kernel/timer.h"
@@ -83,7 +83,7 @@ QString WaitTreeText::GetText() const {
83} 83}
84 84
85WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address) : mutex_address(mutex_address) { 85WaitTreeMutexInfo::WaitTreeMutexInfo(VAddr mutex_address) : mutex_address(mutex_address) {
86 auto& handle_table = Core::System::GetInstance().Kernel().HandleTable(); 86 const auto& handle_table = Core::CurrentProcess()->GetHandleTable();
87 87
88 mutex_value = Memory::Read32(mutex_address); 88 mutex_value = Memory::Read32(mutex_address);
89 owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask); 89 owner_handle = static_cast<Kernel::Handle>(mutex_value & Kernel::Mutex::MutexOwnerMask);
diff --git a/src/yuzu/main.ui b/src/yuzu/main.ui
index 9851f507d..dffd9c788 100644
--- a/src/yuzu/main.ui
+++ b/src/yuzu/main.ui
@@ -97,18 +97,24 @@
97 <addaction name="action_Show_Status_Bar"/> 97 <addaction name="action_Show_Status_Bar"/>
98 <addaction name="menu_View_Debugging"/> 98 <addaction name="menu_View_Debugging"/>
99 </widget> 99 </widget>
100 <widget class ="QMenu" name="menu_Tools">
101 <property name="title">
102 <string>Tools</string>
103 </property>
104 <addaction name="action_Rederive" />
105 </widget>
100 <widget class="QMenu" name="menu_Help"> 106 <widget class="QMenu" name="menu_Help">
101 <property name="title"> 107 <property name="title">
102 <string>&amp;Help</string> 108 <string>&amp;Help</string>
103 </property> 109 </property>
104 <addaction name="action_Report_Compatibility"/> 110 <addaction name="action_Report_Compatibility"/>
105 <addaction name="separator"/> 111 <addaction name="separator"/>
106 <addaction name="action_Rederive"/>
107 <addaction name="action_About"/> 112 <addaction name="action_About"/>
108 </widget> 113 </widget>
109 <addaction name="menu_File"/> 114 <addaction name="menu_File"/>
110 <addaction name="menu_Emulation"/> 115 <addaction name="menu_Emulation"/>
111 <addaction name="menu_View"/> 116 <addaction name="menu_View"/>
117 <addaction name="menu_Tools" />
112 <addaction name="menu_Help"/> 118 <addaction name="menu_Help"/>
113 </widget> 119 </widget>
114 <action name="action_Install_File_NAND"> 120 <action name="action_Install_File_NAND">