summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/common/CMakeLists.txt1
-rw-r--r--src/common/bit_cast.h22
-rw-r--r--src/common/logging/backend.cpp1
-rw-r--r--src/common/logging/log.h1
-rw-r--r--src/common/virtual_buffer.h7
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdevice.h36
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp21
-rw-r--r--src/core/hle/service/nvdrv/devices/nvdisp_disp0.h8
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp157
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h110
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp75
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl.h109
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp192
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h55
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp184
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_gpu.h153
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp88
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h25
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp43
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h110
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp42
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h18
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp70
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h24
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.cpp119
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h68
-rw-r--r--src/core/hle/service/nvdrv/interface.cpp199
-rw-r--r--src/core/hle/service/nvdrv/interface.h6
-rw-r--r--src/core/hle/service/nvdrv/nvdata.h86
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp97
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.h23
-rw-r--r--src/core/hle/service/olsc/olsc.cpp69
-rw-r--r--src/core/hle/service/olsc/olsc.h16
-rw-r--r--src/core/hle/service/service.cpp2
-rw-r--r--src/input_common/gcadapter/gc_poller.cpp4
-rw-r--r--src/input_common/sdl/sdl_impl.cpp3
-rw-r--r--src/video_core/engines/maxwell_3d.cpp265
-rw-r--r--src/video_core/engines/maxwell_3d.h8
-rw-r--r--src/video_core/engines/shader_bytecode.h184
-rw-r--r--src/video_core/renderer_opengl/gl_rasterizer.cpp4
-rw-r--r--src/yuzu/configuration/configure_input_player.cpp2
42 files changed, 1562 insertions, 1147 deletions
diff --git a/src/common/CMakeLists.txt b/src/common/CMakeLists.txt
index 207c7a0a6..d20e6c3b5 100644
--- a/src/common/CMakeLists.txt
+++ b/src/common/CMakeLists.txt
@@ -102,6 +102,7 @@ add_library(common STATIC
102 atomic_ops.h 102 atomic_ops.h
103 detached_tasks.cpp 103 detached_tasks.cpp
104 detached_tasks.h 104 detached_tasks.h
105 bit_cast.h
105 bit_field.h 106 bit_field.h
106 bit_util.h 107 bit_util.h
107 cityhash.cpp 108 cityhash.cpp
diff --git a/src/common/bit_cast.h b/src/common/bit_cast.h
new file mode 100644
index 000000000..a32a063d1
--- /dev/null
+++ b/src/common/bit_cast.h
@@ -0,0 +1,22 @@
1// Copyright 2020 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 <cstring>
8#include <type_traits>
9
10namespace Common {
11
12template <typename To, typename From>
13[[nodiscard]] std::enable_if_t<sizeof(To) == sizeof(From) && std::is_trivially_copyable_v<From> &&
14 std::is_trivially_copyable_v<To>,
15 To>
16BitCast(const From& src) noexcept {
17 To dst;
18 std::memcpy(&dst, &src, sizeof(To));
19 return dst;
20}
21
22} // namespace Common
diff --git a/src/common/logging/backend.cpp b/src/common/logging/backend.cpp
index 90dfa22ca..7859344b9 100644
--- a/src/common/logging/backend.cpp
+++ b/src/common/logging/backend.cpp
@@ -222,6 +222,7 @@ void DebuggerBackend::Write(const Entry& entry) {
222 SUB(Service, NPNS) \ 222 SUB(Service, NPNS) \
223 SUB(Service, NS) \ 223 SUB(Service, NS) \
224 SUB(Service, NVDRV) \ 224 SUB(Service, NVDRV) \
225 SUB(Service, OLSC) \
225 SUB(Service, PCIE) \ 226 SUB(Service, PCIE) \
226 SUB(Service, PCTL) \ 227 SUB(Service, PCTL) \
227 SUB(Service, PCV) \ 228 SUB(Service, PCV) \
diff --git a/src/common/logging/log.h b/src/common/logging/log.h
index 13a4f1e30..835894918 100644
--- a/src/common/logging/log.h
+++ b/src/common/logging/log.h
@@ -95,6 +95,7 @@ enum class Class : ClassType {
95 Service_NPNS, ///< The NPNS service 95 Service_NPNS, ///< The NPNS service
96 Service_NS, ///< The NS services 96 Service_NS, ///< The NS services
97 Service_NVDRV, ///< The NVDRV (Nvidia driver) service 97 Service_NVDRV, ///< The NVDRV (Nvidia driver) service
98 Service_OLSC, ///< The OLSC service
98 Service_PCIE, ///< The PCIe service 99 Service_PCIE, ///< The PCIe service
99 Service_PCTL, ///< The PCTL (Parental control) service 100 Service_PCTL, ///< The PCTL (Parental control) service
100 Service_PCV, ///< The PCV service 101 Service_PCV, ///< The PCV service
diff --git a/src/common/virtual_buffer.h b/src/common/virtual_buffer.h
index 078e61c77..91d430036 100644
--- a/src/common/virtual_buffer.h
+++ b/src/common/virtual_buffer.h
@@ -43,9 +43,14 @@ public:
43 } 43 }
44 44
45 void resize(std::size_t count) { 45 void resize(std::size_t count) {
46 const auto new_size = count * sizeof(T);
47 if (new_size == alloc_size) {
48 return;
49 }
50
46 FreeMemoryPages(base_ptr, alloc_size); 51 FreeMemoryPages(base_ptr, alloc_size);
47 52
48 alloc_size = count * sizeof(T); 53 alloc_size = new_size;
49 base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size)); 54 base_ptr = reinterpret_cast<T*>(AllocateMemoryPages(alloc_size));
50 } 55 }
51 56
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index a1d8dcfa5..e370fd225 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -458,6 +458,8 @@ add_library(core STATIC
458 hle/service/nvflinger/buffer_queue.h 458 hle/service/nvflinger/buffer_queue.h
459 hle/service/nvflinger/nvflinger.cpp 459 hle/service/nvflinger/nvflinger.cpp
460 hle/service/nvflinger/nvflinger.h 460 hle/service/nvflinger/nvflinger.h
461 hle/service/olsc/olsc.cpp
462 hle/service/olsc/olsc.h
461 hle/service/pcie/pcie.cpp 463 hle/service/pcie/pcie.cpp
462 hle/service/pcie/pcie.h 464 hle/service/pcie/pcie.h
463 hle/service/pctl/module.cpp 465 hle/service/pctl/module.cpp
diff --git a/src/core/hle/service/nvdrv/devices/nvdevice.h b/src/core/hle/service/nvdrv/devices/nvdevice.h
index 0240d6643..5681599ba 100644
--- a/src/core/hle/service/nvdrv/devices/nvdevice.h
+++ b/src/core/hle/service/nvdrv/devices/nvdevice.h
@@ -24,25 +24,37 @@ public:
24 explicit nvdevice(Core::System& system) : system{system} {} 24 explicit nvdevice(Core::System& system) : system{system} {}
25 virtual ~nvdevice() = default; 25 virtual ~nvdevice() = default;
26 26
27 union Ioctl { 27 /**
28 u32_le raw; 28 * Handles an ioctl1 request.
29 BitField<0, 8, u32> cmd; 29 * @param command The ioctl command id.
30 BitField<8, 8, u32> group; 30 * @param input A buffer containing the input data for the ioctl.
31 BitField<16, 14, u32> length; 31 * @param output A buffer where the output data will be written to.
32 BitField<30, 1, u32> is_in; 32 * @returns The result code of the ioctl.
33 BitField<31, 1, u32> is_out; 33 */
34 }; 34 virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input,
35 std::vector<u8>& output) = 0;
36
37 /**
38 * Handles an ioctl2 request.
39 * @param command The ioctl command id.
40 * @param input A buffer containing the input data for the ioctl.
41 * @param inline_input A buffer containing the input data for the ioctl which has been inlined.
42 * @param output A buffer where the output data will be written to.
43 * @returns The result code of the ioctl.
44 */
45 virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
46 const std::vector<u8>& inline_input, std::vector<u8>& output) = 0;
35 47
36 /** 48 /**
37 * Handles an ioctl request. 49 * Handles an ioctl3 request.
38 * @param command The ioctl command id. 50 * @param command The ioctl command id.
39 * @param input A buffer containing the input data for the ioctl. 51 * @param input A buffer containing the input data for the ioctl.
40 * @param output A buffer where the output data will be written to. 52 * @param output A buffer where the output data will be written to.
53 * @param inline_output A buffer where the inlined output data will be written to.
41 * @returns The result code of the ioctl. 54 * @returns The result code of the ioctl.
42 */ 55 */
43 virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 56 virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
44 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 57 std::vector<u8>& inline_output) = 0;
45 IoctlVersion version) = 0;
46 58
47protected: 59protected:
48 Core::System& system; 60 Core::System& system;
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
index 3f7b8e670..ce615c758 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.cpp
@@ -18,11 +18,22 @@ nvdisp_disp0::nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_de
18 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 18 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
19nvdisp_disp0 ::~nvdisp_disp0() = default; 19nvdisp_disp0 ::~nvdisp_disp0() = default;
20 20
21u32 nvdisp_disp0::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 21NvResult nvdisp_disp0::Ioctl1(Ioctl command, const std::vector<u8>& input,
22 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 22 std::vector<u8>& output) {
23 IoctlVersion version) { 23 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
24 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 24 return NvResult::NotImplemented;
25 return 0; 25}
26
27NvResult nvdisp_disp0::Ioctl2(Ioctl command, const std::vector<u8>& input,
28 const std::vector<u8>& inline_input, std::vector<u8>& output) {
29 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
30 return NvResult::NotImplemented;
31}
32
33NvResult nvdisp_disp0::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
34 std::vector<u8>& inline_output) {
35 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
36 return NvResult::NotImplemented;
26} 37}
27 38
28void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, 39void nvdisp_disp0::flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height,
diff --git a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
index 6fcdeee84..55a33b7e4 100644
--- a/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
+++ b/src/core/hle/service/nvdrv/devices/nvdisp_disp0.h
@@ -20,9 +20,11 @@ public:
20 explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 20 explicit nvdisp_disp0(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
21 ~nvdisp_disp0() override; 21 ~nvdisp_disp0() override;
22 22
23 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 23 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
24 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 24 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
25 IoctlVersion version) override; 25 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
26 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
27 std::vector<u8>& inline_output) override;
26 28
27 /// Performs a screen flip, drawing the buffer pointed to by the handle. 29 /// Performs a screen flip, drawing the buffer pointed to by the handle.
28 void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride, 30 void flip(u32 buffer_handle, u32 offset, u32 format, u32 width, u32 height, u32 stride,
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
index f2529a12e..6b062e10e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.cpp
@@ -17,59 +17,77 @@
17 17
18namespace Service::Nvidia::Devices { 18namespace Service::Nvidia::Devices {
19 19
20namespace NvErrCodes {
21constexpr u32 Success{};
22constexpr u32 OutOfMemory{static_cast<u32>(-12)};
23constexpr u32 InvalidInput{static_cast<u32>(-22)};
24} // namespace NvErrCodes
25
26nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) 20nvhost_as_gpu::nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
27 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 21 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
28nvhost_as_gpu::~nvhost_as_gpu() = default; 22nvhost_as_gpu::~nvhost_as_gpu() = default;
29 23
30u32 nvhost_as_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 24NvResult nvhost_as_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
31 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 25 std::vector<u8>& output) {
32 IoctlVersion version) { 26 switch (command.group) {
33 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 27 case 'A':
34 command.raw, input.size(), output.size()); 28 switch (command.cmd) {
35 29 case 0x1:
36 switch (static_cast<IoctlCommand>(command.raw)) { 30 return BindChannel(input, output);
37 case IoctlCommand::IocInitalizeExCommand: 31 case 0x2:
38 return InitalizeEx(input, output); 32 return AllocateSpace(input, output);
39 case IoctlCommand::IocAllocateSpaceCommand: 33 case 0x3:
40 return AllocateSpace(input, output); 34 return FreeSpace(input, output);
41 case IoctlCommand::IocMapBufferExCommand: 35 case 0x5:
42 return MapBufferEx(input, output); 36 return UnmapBuffer(input, output);
43 case IoctlCommand::IocBindChannelCommand: 37 case 0x6:
44 return BindChannel(input, output); 38 return MapBufferEx(input, output);
45 case IoctlCommand::IocGetVaRegionsCommand: 39 case 0x8:
46 return GetVARegions(input, output); 40 return GetVARegions(input, output);
47 case IoctlCommand::IocUnmapBufferCommand: 41 case 0x9:
48 return UnmapBuffer(input, output); 42 return InitalizeEx(input, output);
49 case IoctlCommand::IocFreeSpaceCommand: 43 case 0x14:
50 return FreeSpace(input, output); 44 return Remap(input, output);
45 default:
46 break;
47 }
48 break;
51 default: 49 default:
52 break; 50 break;
53 } 51 }
54 52
55 if (static_cast<IoctlCommand>(command.cmd.Value()) == IoctlCommand::IocRemapCommand) { 53 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
56 return Remap(input, output); 54 return NvResult::NotImplemented;
57 } 55}
56
57NvResult nvhost_as_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
58 const std::vector<u8>& inline_input, std::vector<u8>& output) {
59 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
60 return NvResult::NotImplemented;
61}
58 62
59 UNIMPLEMENTED_MSG("Unimplemented ioctl command"); 63NvResult nvhost_as_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
60 return 0; 64 std::vector<u8>& inline_output) {
65 switch (command.group) {
66 case 'A':
67 switch (command.cmd) {
68 case 0x8:
69 return GetVARegions(input, output, inline_output);
70 default:
71 break;
72 }
73 break;
74 default:
75 break;
76 }
77 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
78 return NvResult::NotImplemented;
61} 79}
62 80
63u32 nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) { 81NvResult nvhost_as_gpu::InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output) {
64 IoctlInitalizeEx params{}; 82 IoctlInitalizeEx params{};
65 std::memcpy(&params, input.data(), input.size()); 83 std::memcpy(&params, input.data(), input.size());
66 84
67 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size); 85 LOG_WARNING(Service_NVDRV, "(STUBBED) called, big_page_size=0x{:X}", params.big_page_size);
68 86
69 return 0; 87 return NvResult::Success;
70} 88}
71 89
72u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) { 90NvResult nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output) {
73 IoctlAllocSpace params{}; 91 IoctlAllocSpace params{};
74 std::memcpy(&params, input.data(), input.size()); 92 std::memcpy(&params, input.data(), input.size());
75 93
@@ -83,17 +101,17 @@ u32 nvhost_as_gpu::AllocateSpace(const std::vector<u8>& input, std::vector<u8>&
83 params.offset = system.GPU().MemoryManager().Allocate(size, params.align); 101 params.offset = system.GPU().MemoryManager().Allocate(size, params.align);
84 } 102 }
85 103
86 auto result{NvErrCodes::Success}; 104 auto result = NvResult::Success;
87 if (!params.offset) { 105 if (!params.offset) {
88 LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size); 106 LOG_CRITICAL(Service_NVDRV, "allocation failed for size {}", size);
89 result = NvErrCodes::OutOfMemory; 107 result = NvResult::InsufficientMemory;
90 } 108 }
91 109
92 std::memcpy(output.data(), &params, output.size()); 110 std::memcpy(output.data(), &params, output.size());
93 return result; 111 return result;
94} 112}
95 113
96u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) { 114NvResult nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& output) {
97 IoctlFreeSpace params{}; 115 IoctlFreeSpace params{};
98 std::memcpy(&params, input.data(), input.size()); 116 std::memcpy(&params, input.data(), input.size());
99 117
@@ -104,15 +122,15 @@ u32 nvhost_as_gpu::FreeSpace(const std::vector<u8>& input, std::vector<u8>& outp
104 static_cast<std::size_t>(params.pages) * params.page_size); 122 static_cast<std::size_t>(params.pages) * params.page_size);
105 123
106 std::memcpy(output.data(), &params, output.size()); 124 std::memcpy(output.data(), &params, output.size());
107 return NvErrCodes::Success; 125 return NvResult::Success;
108} 126}
109 127
110u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) { 128NvResult nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output) {
111 const auto num_entries = input.size() / sizeof(IoctlRemapEntry); 129 const auto num_entries = input.size() / sizeof(IoctlRemapEntry);
112 130
113 LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries); 131 LOG_DEBUG(Service_NVDRV, "called, num_entries=0x{:X}", num_entries);
114 132
115 auto result{NvErrCodes::Success}; 133 auto result = NvResult::Success;
116 std::vector<IoctlRemapEntry> entries(num_entries); 134 std::vector<IoctlRemapEntry> entries(num_entries);
117 std::memcpy(entries.data(), input.data(), input.size()); 135 std::memcpy(entries.data(), input.data(), input.size());
118 136
@@ -123,7 +141,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
123 const auto object{nvmap_dev->GetObject(entry.nvmap_handle)}; 141 const auto object{nvmap_dev->GetObject(entry.nvmap_handle)};
124 if (!object) { 142 if (!object) {
125 LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle); 143 LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", entry.nvmap_handle);
126 result = NvErrCodes::InvalidInput; 144 result = NvResult::InvalidState;
127 break; 145 break;
128 } 146 }
129 147
@@ -134,7 +152,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
134 152
135 if (!addr) { 153 if (!addr) {
136 LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!"); 154 LOG_CRITICAL(Service_NVDRV, "map returned an invalid address!");
137 result = NvErrCodes::InvalidInput; 155 result = NvResult::InvalidState;
138 break; 156 break;
139 } 157 }
140 } 158 }
@@ -143,7 +161,7 @@ u32 nvhost_as_gpu::Remap(const std::vector<u8>& input, std::vector<u8>& output)
143 return result; 161 return result;
144} 162}
145 163
146u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { 164NvResult nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
147 IoctlMapBufferEx params{}; 165 IoctlMapBufferEx params{};
148 std::memcpy(&params, input.data(), input.size()); 166 std::memcpy(&params, input.data(), input.size());
149 167
@@ -157,7 +175,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
157 if (!object) { 175 if (!object) {
158 LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle); 176 LOG_CRITICAL(Service_NVDRV, "invalid nvmap_handle={:X}", params.nvmap_handle);
159 std::memcpy(output.data(), &params, output.size()); 177 std::memcpy(output.data(), &params, output.size());
160 return NvErrCodes::InvalidInput; 178 return NvResult::InvalidState;
161 } 179 }
162 180
163 // The real nvservices doesn't make a distinction between handles and ids, and 181 // The real nvservices doesn't make a distinction between handles and ids, and
@@ -184,16 +202,16 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
184 params.mapping_size, params.offset); 202 params.mapping_size, params.offset);
185 203
186 std::memcpy(output.data(), &params, output.size()); 204 std::memcpy(output.data(), &params, output.size());
187 return NvErrCodes::InvalidInput; 205 return NvResult::InvalidState;
188 } 206 }
189 207
190 std::memcpy(output.data(), &params, output.size()); 208 std::memcpy(output.data(), &params, output.size());
191 return NvErrCodes::Success; 209 return NvResult::Success;
192 } else { 210 } else {
193 LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset); 211 LOG_CRITICAL(Service_NVDRV, "address not mapped offset={}", params.offset);
194 212
195 std::memcpy(output.data(), &params, output.size()); 213 std::memcpy(output.data(), &params, output.size());
196 return NvErrCodes::InvalidInput; 214 return NvResult::InvalidState;
197 } 215 }
198 } 216 }
199 217
@@ -213,10 +231,10 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
213 params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size); 231 params.offset = gpu.MemoryManager().Map(physical_address, params.offset, size);
214 } 232 }
215 233
216 auto result{NvErrCodes::Success}; 234 auto result = NvResult::Success;
217 if (!params.offset) { 235 if (!params.offset) {
218 LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size); 236 LOG_CRITICAL(Service_NVDRV, "failed to map size={}", size);
219 result = NvErrCodes::InvalidInput; 237 result = NvResult::InvalidState;
220 } else { 238 } else {
221 AddBufferMap(params.offset, size, physical_address, is_alloc); 239 AddBufferMap(params.offset, size, physical_address, is_alloc);
222 } 240 }
@@ -225,7 +243,7 @@ u32 nvhost_as_gpu::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& ou
225 return result; 243 return result;
226} 244}
227 245
228u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { 246NvResult nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
229 IoctlUnmapBuffer params{}; 247 IoctlUnmapBuffer params{};
230 std::memcpy(&params, input.data(), input.size()); 248 std::memcpy(&params, input.data(), input.size());
231 249
@@ -238,20 +256,42 @@ u32 nvhost_as_gpu::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& ou
238 } 256 }
239 257
240 std::memcpy(output.data(), &params, output.size()); 258 std::memcpy(output.data(), &params, output.size());
241 return NvErrCodes::Success; 259 return NvResult::Success;
242} 260}
243 261
244u32 nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) { 262NvResult nvhost_as_gpu::BindChannel(const std::vector<u8>& input, std::vector<u8>& output) {
245 IoctlBindChannel params{}; 263 IoctlBindChannel params{};
246 std::memcpy(&params, input.data(), input.size()); 264 std::memcpy(&params, input.data(), input.size());
247 265 LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}", params.fd);
248 LOG_DEBUG(Service_NVDRV, "called, fd={:X}", params.fd);
249 266
250 channel = params.fd; 267 channel = params.fd;
251 return 0; 268 return NvResult::Success;
269}
270
271NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) {
272 IoctlGetVaRegions params{};
273 std::memcpy(&params, input.data(), input.size());
274
275 LOG_WARNING(Service_NVDRV, "(STUBBED) called, buf_addr={:X}, buf_size={:X}", params.buf_addr,
276 params.buf_size);
277
278 params.buf_size = 0x30;
279 params.regions[0].offset = 0x04000000;
280 params.regions[0].page_size = 0x1000;
281 params.regions[0].pages = 0x3fbfff;
282
283 params.regions[1].offset = 0x04000000;
284 params.regions[1].page_size = 0x10000;
285 params.regions[1].pages = 0x1bffff;
286
287 // TODO(ogniK): This probably can stay stubbed but should add support way way later
288
289 std::memcpy(output.data(), &params, output.size());
290 return NvResult::Success;
252} 291}
253 292
254u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output) { 293NvResult nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& output,
294 std::vector<u8>& inline_output) {
255 IoctlGetVaRegions params{}; 295 IoctlGetVaRegions params{};
256 std::memcpy(&params, input.data(), input.size()); 296 std::memcpy(&params, input.data(), input.size());
257 297
@@ -270,7 +310,8 @@ u32 nvhost_as_gpu::GetVARegions(const std::vector<u8>& input, std::vector<u8>& o
270 // TODO(ogniK): This probably can stay stubbed but should add support way way later 310 // TODO(ogniK): This probably can stay stubbed but should add support way way later
271 311
272 std::memcpy(output.data(), &params, output.size()); 312 std::memcpy(output.data(), &params, output.size());
273 return 0; 313 std::memcpy(inline_output.data(), &params.regions, inline_output.size());
314 return NvResult::Success;
274} 315}
275 316
276std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const { 317std::optional<nvhost_as_gpu::BufferMap> nvhost_as_gpu::FindBufferMap(GPUVAddr gpu_addr) const {
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
index fcdb40d93..08035fa0e 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_as_gpu.h
@@ -30,9 +30,11 @@ public:
30 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 30 explicit nvhost_as_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
31 ~nvhost_as_gpu() override; 31 ~nvhost_as_gpu() override;
32 32
33 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 33 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
34 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 34 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
35 IoctlVersion version) override; 35 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
36 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
37 std::vector<u8>& inline_output) override;
36 38
37private: 39private:
38 class BufferMap final { 40 class BufferMap final {
@@ -74,32 +76,21 @@ private:
74 bool is_allocated{}; 76 bool is_allocated{};
75 }; 77 };
76 78
77 enum class IoctlCommand : u32_le {
78 IocInitalizeExCommand = 0x40284109,
79 IocAllocateSpaceCommand = 0xC0184102,
80 IocRemapCommand = 0x00000014,
81 IocMapBufferExCommand = 0xC0284106,
82 IocBindChannelCommand = 0x40044101,
83 IocGetVaRegionsCommand = 0xC0404108,
84 IocUnmapBufferCommand = 0xC0084105,
85 IocFreeSpaceCommand = 0xC0104103,
86 };
87
88 struct IoctlInitalizeEx { 79 struct IoctlInitalizeEx {
89 u32_le big_page_size; // depends on GPU's available_big_page_sizes; 0=default 80 u32_le big_page_size{}; // depends on GPU's available_big_page_sizes; 0=default
90 s32_le as_fd; // ignored; passes 0 81 s32_le as_fd{}; // ignored; passes 0
91 u32_le flags; // passes 0 82 u32_le flags{}; // passes 0
92 u32_le reserved; // ignored; passes 0 83 u32_le reserved{}; // ignored; passes 0
93 u64_le unk0; 84 u64_le unk0{};
94 u64_le unk1; 85 u64_le unk1{};
95 u64_le unk2; 86 u64_le unk2{};
96 }; 87 };
97 static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size"); 88 static_assert(sizeof(IoctlInitalizeEx) == 40, "IoctlInitalizeEx is incorrect size");
98 89
99 struct IoctlAllocSpace { 90 struct IoctlAllocSpace {
100 u32_le pages; 91 u32_le pages{};
101 u32_le page_size; 92 u32_le page_size{};
102 AddressSpaceFlags flags; 93 AddressSpaceFlags flags{};
103 INSERT_PADDING_WORDS(1); 94 INSERT_PADDING_WORDS(1);
104 union { 95 union {
105 u64_le offset; 96 u64_le offset;
@@ -109,70 +100,73 @@ private:
109 static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size"); 100 static_assert(sizeof(IoctlAllocSpace) == 24, "IoctlInitalizeEx is incorrect size");
110 101
111 struct IoctlFreeSpace { 102 struct IoctlFreeSpace {
112 u64_le offset; 103 u64_le offset{};
113 u32_le pages; 104 u32_le pages{};
114 u32_le page_size; 105 u32_le page_size{};
115 }; 106 };
116 static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size"); 107 static_assert(sizeof(IoctlFreeSpace) == 16, "IoctlFreeSpace is incorrect size");
117 108
118 struct IoctlRemapEntry { 109 struct IoctlRemapEntry {
119 u16_le flags; 110 u16_le flags{};
120 u16_le kind; 111 u16_le kind{};
121 u32_le nvmap_handle; 112 u32_le nvmap_handle{};
122 u32_le map_offset; 113 u32_le map_offset{};
123 u32_le offset; 114 u32_le offset{};
124 u32_le pages; 115 u32_le pages{};
125 }; 116 };
126 static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size"); 117 static_assert(sizeof(IoctlRemapEntry) == 20, "IoctlRemapEntry is incorrect size");
127 118
128 struct IoctlMapBufferEx { 119 struct IoctlMapBufferEx {
129 AddressSpaceFlags flags; // bit0: fixed_offset, bit2: cacheable 120 AddressSpaceFlags flags{}; // bit0: fixed_offset, bit2: cacheable
130 u32_le kind; // -1 is default 121 u32_le kind{}; // -1 is default
131 u32_le nvmap_handle; 122 u32_le nvmap_handle{};
132 u32_le page_size; // 0 means don't care 123 u32_le page_size{}; // 0 means don't care
133 s64_le buffer_offset; 124 s64_le buffer_offset{};
134 u64_le mapping_size; 125 u64_le mapping_size{};
135 s64_le offset; 126 s64_le offset{};
136 }; 127 };
137 static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size"); 128 static_assert(sizeof(IoctlMapBufferEx) == 40, "IoctlMapBufferEx is incorrect size");
138 129
139 struct IoctlUnmapBuffer { 130 struct IoctlUnmapBuffer {
140 s64_le offset; 131 s64_le offset{};
141 }; 132 };
142 static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size"); 133 static_assert(sizeof(IoctlUnmapBuffer) == 8, "IoctlUnmapBuffer is incorrect size");
143 134
144 struct IoctlBindChannel { 135 struct IoctlBindChannel {
145 u32_le fd; 136 s32_le fd{};
146 }; 137 };
147 static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size"); 138 static_assert(sizeof(IoctlBindChannel) == 4, "IoctlBindChannel is incorrect size");
148 139
149 struct IoctlVaRegion { 140 struct IoctlVaRegion {
150 u64_le offset; 141 u64_le offset{};
151 u32_le page_size; 142 u32_le page_size{};
152 INSERT_PADDING_WORDS(1); 143 INSERT_PADDING_WORDS(1);
153 u64_le pages; 144 u64_le pages{};
154 }; 145 };
155 static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size"); 146 static_assert(sizeof(IoctlVaRegion) == 24, "IoctlVaRegion is incorrect size");
156 147
157 struct IoctlGetVaRegions { 148 struct IoctlGetVaRegions {
158 u64_le buf_addr; // (contained output user ptr on linux, ignored) 149 u64_le buf_addr{}; // (contained output user ptr on linux, ignored)
159 u32_le buf_size; // forced to 2*sizeof(struct va_region) 150 u32_le buf_size{}; // forced to 2*sizeof(struct va_region)
160 u32_le reserved; 151 u32_le reserved{};
161 IoctlVaRegion regions[2]; 152 IoctlVaRegion regions[2]{};
162 }; 153 };
163 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2, 154 static_assert(sizeof(IoctlGetVaRegions) == 16 + sizeof(IoctlVaRegion) * 2,
164 "IoctlGetVaRegions is incorrect size"); 155 "IoctlGetVaRegions is incorrect size");
165 156
166 u32 channel{}; 157 s32 channel{};
158
159 NvResult InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output);
160 NvResult AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output);
161 NvResult Remap(const std::vector<u8>& input, std::vector<u8>& output);
162 NvResult MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
163 NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
164 NvResult FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
165 NvResult BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
167 166
168 u32 InitalizeEx(const std::vector<u8>& input, std::vector<u8>& output); 167 NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
169 u32 AllocateSpace(const std::vector<u8>& input, std::vector<u8>& output); 168 NvResult GetVARegions(const std::vector<u8>& input, std::vector<u8>& output,
170 u32 Remap(const std::vector<u8>& input, std::vector<u8>& output); 169 std::vector<u8>& inline_output);
171 u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
172 u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
173 u32 FreeSpace(const std::vector<u8>& input, std::vector<u8>& output);
174 u32 BindChannel(const std::vector<u8>& input, std::vector<u8>& output);
175 u32 GetVARegions(const std::vector<u8>& input, std::vector<u8>& output);
176 170
177 std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; 171 std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
178 void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); 172 void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
index 8356a8139..d90cf90a8 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.cpp
@@ -20,41 +20,54 @@ nvhost_ctrl::nvhost_ctrl(Core::System& system, EventInterface& events_interface,
20 : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {} 20 : nvdevice(system), events_interface{events_interface}, syncpoint_manager{syncpoint_manager} {}
21nvhost_ctrl::~nvhost_ctrl() = default; 21nvhost_ctrl::~nvhost_ctrl() = default;
22 22
23u32 nvhost_ctrl::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 23NvResult nvhost_ctrl::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
24 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 24 switch (command.group) {
25 IoctlVersion version) { 25 case 0x0:
26 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 26 switch (command.cmd) {
27 command.raw, input.size(), output.size()); 27 case 0x1b:
28 28 return NvOsGetConfigU32(input, output);
29 switch (static_cast<IoctlCommand>(command.raw)) { 29 case 0x1c:
30 case IoctlCommand::IocGetConfigCommand: 30 return IocCtrlClearEventWait(input, output);
31 return NvOsGetConfigU32(input, output); 31 case 0x1d:
32 case IoctlCommand::IocCtrlEventWaitCommand: 32 return IocCtrlEventWait(input, output, false);
33 return IocCtrlEventWait(input, output, false, ctrl); 33 case 0x1e:
34 case IoctlCommand::IocCtrlEventWaitAsyncCommand: 34 return IocCtrlEventWait(input, output, true);
35 return IocCtrlEventWait(input, output, true, ctrl); 35 case 0x1f:
36 case IoctlCommand::IocCtrlEventRegisterCommand: 36 return IocCtrlEventRegister(input, output);
37 return IocCtrlEventRegister(input, output); 37 case 0x20:
38 case IoctlCommand::IocCtrlEventUnregisterCommand: 38 return IocCtrlEventUnregister(input, output);
39 return IocCtrlEventUnregister(input, output); 39 }
40 case IoctlCommand::IocCtrlClearEventWaitCommand: 40 break;
41 return IocCtrlClearEventWait(input, output);
42 default: 41 default:
43 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 42 break;
44 return 0;
45 } 43 }
44
45 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
46 return NvResult::NotImplemented;
47}
48
49NvResult nvhost_ctrl::Ioctl2(Ioctl command, const std::vector<u8>& input,
50 const std::vector<u8>& inline_input, std::vector<u8>& output) {
51 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
52 return NvResult::NotImplemented;
53}
54
55NvResult nvhost_ctrl::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
56 std::vector<u8>& inline_output) {
57 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
58 return NvResult::NotImplemented;
46} 59}
47 60
48u32 nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) { 61NvResult nvhost_ctrl::NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output) {
49 IocGetConfigParams params{}; 62 IocGetConfigParams params{};
50 std::memcpy(&params, input.data(), sizeof(params)); 63 std::memcpy(&params, input.data(), sizeof(params));
51 LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(), 64 LOG_TRACE(Service_NVDRV, "called, setting={}!{}", params.domain_str.data(),
52 params.param_str.data()); 65 params.param_str.data());
53 return 0x30006; // Returns error on production mode 66 return NvResult::ConfigVarNotFound; // Returns error on production mode
54} 67}
55 68
56u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, 69NvResult nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output,
57 bool is_async, IoctlCtrl& ctrl) { 70 bool is_async) {
58 IocCtrlEventWaitParams params{}; 71 IocCtrlEventWaitParams params{};
59 std::memcpy(&params, input.data(), sizeof(params)); 72 std::memcpy(&params, input.data(), sizeof(params));
60 LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}", 73 LOG_DEBUG(Service_NVDRV, "syncpt_id={}, threshold={}, timeout={}, is_async={}",
@@ -126,10 +139,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
126 params.value |= event_id; 139 params.value |= event_id;
127 event.event.writable->Clear(); 140 event.event.writable->Clear();
128 gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value); 141 gpu.RegisterSyncptInterrupt(params.syncpt_id, target_value);
129 if (!is_async && ctrl.fresh_call) { 142 if (!is_async) {
130 ctrl.must_delay = true;
131 ctrl.timeout = params.timeout;
132 ctrl.event_id = event_id;
133 return NvResult::Timeout; 143 return NvResult::Timeout;
134 } 144 }
135 std::memcpy(output.data(), &params, sizeof(params)); 145 std::memcpy(output.data(), &params, sizeof(params));
@@ -139,7 +149,7 @@ u32 nvhost_ctrl::IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>&
139 return NvResult::BadParameter; 149 return NvResult::BadParameter;
140} 150}
141 151
142u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) { 152NvResult nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output) {
143 IocCtrlEventRegisterParams params{}; 153 IocCtrlEventRegisterParams params{};
144 std::memcpy(&params, input.data(), sizeof(params)); 154 std::memcpy(&params, input.data(), sizeof(params));
145 const u32 event_id = params.user_event_id & 0x00FF; 155 const u32 event_id = params.user_event_id & 0x00FF;
@@ -154,7 +164,8 @@ u32 nvhost_ctrl::IocCtrlEventRegister(const std::vector<u8>& input, std::vector<
154 return NvResult::Success; 164 return NvResult::Success;
155} 165}
156 166
157u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output) { 167NvResult nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input,
168 std::vector<u8>& output) {
158 IocCtrlEventUnregisterParams params{}; 169 IocCtrlEventUnregisterParams params{};
159 std::memcpy(&params, input.data(), sizeof(params)); 170 std::memcpy(&params, input.data(), sizeof(params));
160 const u32 event_id = params.user_event_id & 0x00FF; 171 const u32 event_id = params.user_event_id & 0x00FF;
@@ -169,7 +180,7 @@ u32 nvhost_ctrl::IocCtrlEventUnregister(const std::vector<u8>& input, std::vecto
169 return NvResult::Success; 180 return NvResult::Success;
170} 181}
171 182
172u32 nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) { 183NvResult nvhost_ctrl::IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output) {
173 IocCtrlEventSignalParams params{}; 184 IocCtrlEventSignalParams params{};
174 std::memcpy(&params, input.data(), sizeof(params)); 185 std::memcpy(&params, input.data(), sizeof(params));
175 186
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
index 24ad96cb9..c5aa1362a 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl.h
@@ -18,132 +18,113 @@ public:
18 SyncpointManager& syncpoint_manager); 18 SyncpointManager& syncpoint_manager);
19 ~nvhost_ctrl() override; 19 ~nvhost_ctrl() override;
20 20
21 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 21 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
22 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 22 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
23 IoctlVersion version) override; 23 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
24 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
25 std::vector<u8>& inline_output) override;
24 26
25private: 27private:
26 enum class IoctlCommand : u32_le {
27 IocSyncptReadCommand = 0xC0080014,
28 IocSyncptIncrCommand = 0x40040015,
29 IocSyncptWaitCommand = 0xC00C0016,
30 IocModuleMutexCommand = 0x40080017,
31 IocModuleRegRDWRCommand = 0xC0180018,
32 IocSyncptWaitexCommand = 0xC0100019,
33 IocSyncptReadMaxCommand = 0xC008001A,
34 IocGetConfigCommand = 0xC183001B,
35 IocCtrlClearEventWaitCommand = 0xC004001C,
36 IocCtrlEventWaitCommand = 0xC010001D,
37 IocCtrlEventWaitAsyncCommand = 0xC010001E,
38 IocCtrlEventRegisterCommand = 0xC004001F,
39 IocCtrlEventUnregisterCommand = 0xC0040020,
40 IocCtrlEventKillCommand = 0x40080021,
41 };
42 struct IocSyncptReadParams { 28 struct IocSyncptReadParams {
43 u32_le id; 29 u32_le id{};
44 u32_le value; 30 u32_le value{};
45 }; 31 };
46 static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size"); 32 static_assert(sizeof(IocSyncptReadParams) == 8, "IocSyncptReadParams is incorrect size");
47 33
48 struct IocSyncptIncrParams { 34 struct IocSyncptIncrParams {
49 u32_le id; 35 u32_le id{};
50 }; 36 };
51 static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size"); 37 static_assert(sizeof(IocSyncptIncrParams) == 4, "IocSyncptIncrParams is incorrect size");
52 38
53 struct IocSyncptWaitParams { 39 struct IocSyncptWaitParams {
54 u32_le id; 40 u32_le id{};
55 u32_le thresh; 41 u32_le thresh{};
56 s32_le timeout; 42 s32_le timeout{};
57 }; 43 };
58 static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size"); 44 static_assert(sizeof(IocSyncptWaitParams) == 12, "IocSyncptWaitParams is incorrect size");
59 45
60 struct IocModuleMutexParams { 46 struct IocModuleMutexParams {
61 u32_le id; 47 u32_le id{};
62 u32_le lock; // (0 = unlock and 1 = lock) 48 u32_le lock{}; // (0 = unlock and 1 = lock)
63 }; 49 };
64 static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size"); 50 static_assert(sizeof(IocModuleMutexParams) == 8, "IocModuleMutexParams is incorrect size");
65 51
66 struct IocModuleRegRDWRParams { 52 struct IocModuleRegRDWRParams {
67 u32_le id; 53 u32_le id{};
68 u32_le num_offsets; 54 u32_le num_offsets{};
69 u32_le block_size; 55 u32_le block_size{};
70 u32_le offsets; 56 u32_le offsets{};
71 u32_le values; 57 u32_le values{};
72 u32_le write; 58 u32_le write{};
73 }; 59 };
74 static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size"); 60 static_assert(sizeof(IocModuleRegRDWRParams) == 24, "IocModuleRegRDWRParams is incorrect size");
75 61
76 struct IocSyncptWaitexParams { 62 struct IocSyncptWaitexParams {
77 u32_le id; 63 u32_le id{};
78 u32_le thresh; 64 u32_le thresh{};
79 s32_le timeout; 65 s32_le timeout{};
80 u32_le value; 66 u32_le value{};
81 }; 67 };
82 static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size"); 68 static_assert(sizeof(IocSyncptWaitexParams) == 16, "IocSyncptWaitexParams is incorrect size");
83 69
84 struct IocSyncptReadMaxParams { 70 struct IocSyncptReadMaxParams {
85 u32_le id; 71 u32_le id{};
86 u32_le value; 72 u32_le value{};
87 }; 73 };
88 static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size"); 74 static_assert(sizeof(IocSyncptReadMaxParams) == 8, "IocSyncptReadMaxParams is incorrect size");
89 75
90 struct IocGetConfigParams { 76 struct IocGetConfigParams {
91 std::array<char, 0x41> domain_str; 77 std::array<char, 0x41> domain_str{};
92 std::array<char, 0x41> param_str; 78 std::array<char, 0x41> param_str{};
93 std::array<char, 0x101> config_str; 79 std::array<char, 0x101> config_str{};
94 }; 80 };
95 static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size"); 81 static_assert(sizeof(IocGetConfigParams) == 387, "IocGetConfigParams is incorrect size");
96 82
97 struct IocCtrlEventSignalParams { 83 struct IocCtrlEventSignalParams {
98 u32_le event_id; 84 u32_le event_id{};
99 }; 85 };
100 static_assert(sizeof(IocCtrlEventSignalParams) == 4, 86 static_assert(sizeof(IocCtrlEventSignalParams) == 4,
101 "IocCtrlEventSignalParams is incorrect size"); 87 "IocCtrlEventSignalParams is incorrect size");
102 88
103 struct IocCtrlEventWaitParams { 89 struct IocCtrlEventWaitParams {
104 u32_le syncpt_id; 90 u32_le syncpt_id{};
105 u32_le threshold; 91 u32_le threshold{};
106 s32_le timeout; 92 s32_le timeout{};
107 u32_le value; 93 u32_le value{};
108 }; 94 };
109 static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size"); 95 static_assert(sizeof(IocCtrlEventWaitParams) == 16, "IocCtrlEventWaitParams is incorrect size");
110 96
111 struct IocCtrlEventWaitAsyncParams { 97 struct IocCtrlEventWaitAsyncParams {
112 u32_le syncpt_id; 98 u32_le syncpt_id{};
113 u32_le threshold; 99 u32_le threshold{};
114 u32_le timeout; 100 u32_le timeout{};
115 u32_le value; 101 u32_le value{};
116 }; 102 };
117 static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16, 103 static_assert(sizeof(IocCtrlEventWaitAsyncParams) == 16,
118 "IocCtrlEventWaitAsyncParams is incorrect size"); 104 "IocCtrlEventWaitAsyncParams is incorrect size");
119 105
120 struct IocCtrlEventRegisterParams { 106 struct IocCtrlEventRegisterParams {
121 u32_le user_event_id; 107 u32_le user_event_id{};
122 }; 108 };
123 static_assert(sizeof(IocCtrlEventRegisterParams) == 4, 109 static_assert(sizeof(IocCtrlEventRegisterParams) == 4,
124 "IocCtrlEventRegisterParams is incorrect size"); 110 "IocCtrlEventRegisterParams is incorrect size");
125 111
126 struct IocCtrlEventUnregisterParams { 112 struct IocCtrlEventUnregisterParams {
127 u32_le user_event_id; 113 u32_le user_event_id{};
128 }; 114 };
129 static_assert(sizeof(IocCtrlEventUnregisterParams) == 4, 115 static_assert(sizeof(IocCtrlEventUnregisterParams) == 4,
130 "IocCtrlEventUnregisterParams is incorrect size"); 116 "IocCtrlEventUnregisterParams is incorrect size");
131 117
132 struct IocCtrlEventKill { 118 struct IocCtrlEventKill {
133 u64_le user_events; 119 u64_le user_events{};
134 }; 120 };
135 static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size"); 121 static_assert(sizeof(IocCtrlEventKill) == 8, "IocCtrlEventKill is incorrect size");
136 122
137 u32 NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output); 123 NvResult NvOsGetConfigU32(const std::vector<u8>& input, std::vector<u8>& output);
138 124 NvResult IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async);
139 u32 IocCtrlEventWait(const std::vector<u8>& input, std::vector<u8>& output, bool is_async, 125 NvResult IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
140 IoctlCtrl& ctrl); 126 NvResult IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
141 127 NvResult IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
142 u32 IocCtrlEventRegister(const std::vector<u8>& input, std::vector<u8>& output);
143
144 u32 IocCtrlEventUnregister(const std::vector<u8>& input, std::vector<u8>& output);
145
146 u32 IocCtrlClearEventWait(const std::vector<u8>& input, std::vector<u8>& output);
147 128
148 EventInterface& events_interface; 129 EventInterface& events_interface;
149 SyncpointManager& syncpoint_manager; 130 SyncpointManager& syncpoint_manager;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
index fba89e7a6..2d7ea433c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp
@@ -15,39 +15,66 @@ namespace Service::Nvidia::Devices {
15nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {} 15nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system) : nvdevice(system) {}
16nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default; 16nvhost_ctrl_gpu::~nvhost_ctrl_gpu() = default;
17 17
18u32 nvhost_ctrl_gpu::ioctl(Ioctl command, const std::vector<u8>& input, 18NvResult nvhost_ctrl_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input,
19 const std::vector<u8>& input2, std::vector<u8>& output, 19 std::vector<u8>& output) {
20 std::vector<u8>& output2, IoctlCtrl& ctrl, IoctlVersion version) { 20 switch (command.group) {
21 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 21 case 'G':
22 command.raw, input.size(), output.size()); 22 switch (command.cmd) {
23 23 case 0x1:
24 switch (static_cast<IoctlCommand>(command.raw)) { 24 return ZCullGetCtxSize(input, output);
25 case IoctlCommand::IocGetCharacteristicsCommand: 25 case 0x2:
26 return GetCharacteristics(input, output, output2, version); 26 return ZCullGetInfo(input, output);
27 case IoctlCommand::IocGetTPCMasksCommand: 27 case 0x3:
28 return GetTPCMasks(input, output, output2, version); 28 return ZBCSetTable(input, output);
29 case IoctlCommand::IocGetActiveSlotMaskCommand: 29 case 0x4:
30 return GetActiveSlotMask(input, output); 30 return ZBCQueryTable(input, output);
31 case IoctlCommand::IocZcullGetCtxSizeCommand: 31 case 0x5:
32 return ZCullGetCtxSize(input, output); 32 return GetCharacteristics(input, output);
33 case IoctlCommand::IocZcullGetInfo: 33 case 0x6:
34 return ZCullGetInfo(input, output); 34 return GetTPCMasks(input, output);
35 case IoctlCommand::IocZbcSetTable: 35 case 0x7:
36 return ZBCSetTable(input, output); 36 return FlushL2(input, output);
37 case IoctlCommand::IocZbcQueryTable: 37 case 0x14:
38 return ZBCQueryTable(input, output); 38 return GetActiveSlotMask(input, output);
39 case IoctlCommand::IocFlushL2: 39 case 0x1c:
40 return FlushL2(input, output); 40 return GetGpuTime(input, output);
41 case IoctlCommand::IocGetGpuTime: 41 default:
42 return GetGpuTime(input, output); 42 break;
43 }
44 break;
45 }
46 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
47 return NvResult::NotImplemented;
48}
49
50NvResult nvhost_ctrl_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
51 const std::vector<u8>& inline_input, std::vector<u8>& output) {
52 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
53 return NvResult::NotImplemented;
54}
55
56NvResult nvhost_ctrl_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input,
57 std::vector<u8>& output, std::vector<u8>& inline_output) {
58 switch (command.group) {
59 case 'G':
60 switch (command.cmd) {
61 case 0x5:
62 return GetCharacteristics(input, output, inline_output);
63 case 0x6:
64 return GetTPCMasks(input, output, inline_output);
65 default:
66 break;
67 }
68 break;
43 default: 69 default:
44 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 70 break;
45 return 0;
46 } 71 }
72 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
73 return NvResult::NotImplemented;
47} 74}
48 75
49u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, 76NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input,
50 std::vector<u8>& output2, IoctlVersion version) { 77 std::vector<u8>& output) {
51 LOG_DEBUG(Service_NVDRV, "called"); 78 LOG_DEBUG(Service_NVDRV, "called");
52 IoctlCharacteristics params{}; 79 IoctlCharacteristics params{};
53 std::memcpy(&params, input.data(), input.size()); 80 std::memcpy(&params, input.data(), input.size());
@@ -88,36 +115,83 @@ u32 nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vecto
88 params.gc.gr_compbit_store_base_hw = 0x0; 115 params.gc.gr_compbit_store_base_hw = 0x0;
89 params.gpu_characteristics_buf_size = 0xA0; 116 params.gpu_characteristics_buf_size = 0xA0;
90 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED) 117 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
118 std::memcpy(output.data(), &params, output.size());
119 return NvResult::Success;
120}
91 121
92 if (version == IoctlVersion::Version3) { 122NvResult nvhost_ctrl_gpu::GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
93 std::memcpy(output.data(), input.data(), output.size()); 123 std::vector<u8>& inline_output) {
94 std::memcpy(output2.data(), &params.gc, output2.size()); 124 LOG_DEBUG(Service_NVDRV, "called");
95 } else { 125 IoctlCharacteristics params{};
96 std::memcpy(output.data(), &params, output.size()); 126 std::memcpy(&params, input.data(), input.size());
97 } 127 params.gc.arch = 0x120;
98 return 0; 128 params.gc.impl = 0xb;
129 params.gc.rev = 0xa1;
130 params.gc.num_gpc = 0x1;
131 params.gc.l2_cache_size = 0x40000;
132 params.gc.on_board_video_memory_size = 0x0;
133 params.gc.num_tpc_per_gpc = 0x2;
134 params.gc.bus_type = 0x20;
135 params.gc.big_page_size = 0x20000;
136 params.gc.compression_page_size = 0x20000;
137 params.gc.pde_coverage_bit_count = 0x1B;
138 params.gc.available_big_page_sizes = 0x30000;
139 params.gc.gpc_mask = 0x1;
140 params.gc.sm_arch_sm_version = 0x503;
141 params.gc.sm_arch_spa_version = 0x503;
142 params.gc.sm_arch_warp_count = 0x80;
143 params.gc.gpu_va_bit_count = 0x28;
144 params.gc.reserved = 0x0;
145 params.gc.flags = 0x55;
146 params.gc.twod_class = 0x902D;
147 params.gc.threed_class = 0xB197;
148 params.gc.compute_class = 0xB1C0;
149 params.gc.gpfifo_class = 0xB06F;
150 params.gc.inline_to_memory_class = 0xA140;
151 params.gc.dma_copy_class = 0xB0B5;
152 params.gc.max_fbps_count = 0x1;
153 params.gc.fbp_en_mask = 0x0;
154 params.gc.max_ltc_per_fbp = 0x2;
155 params.gc.max_lts_per_ltc = 0x1;
156 params.gc.max_tex_per_tpc = 0x0;
157 params.gc.max_gpc_count = 0x1;
158 params.gc.rop_l2_en_mask_0 = 0x21D70;
159 params.gc.rop_l2_en_mask_1 = 0x0;
160 params.gc.chipname = 0x6230326D67;
161 params.gc.gr_compbit_store_base_hw = 0x0;
162 params.gpu_characteristics_buf_size = 0xA0;
163 params.gpu_characteristics_buf_addr = 0xdeadbeef; // Cannot be 0 (UNUSED)
164
165 std::memcpy(output.data(), input.data(), output.size());
166 std::memcpy(inline_output.data(), &params.gc, inline_output.size());
167 return NvResult::Success;
99} 168}
100 169
101u32 nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, 170NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output) {
102 std::vector<u8>& output2, IoctlVersion version) {
103 IoctlGpuGetTpcMasksArgs params{}; 171 IoctlGpuGetTpcMasksArgs params{};
104 std::memcpy(&params, input.data(), input.size()); 172 std::memcpy(&params, input.data(), input.size());
105 LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size); 173 LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
106 if (params.mask_buffer_size != 0) { 174 if (params.mask_buffer_size != 0) {
107 params.tcp_mask = 3; 175 params.tcp_mask = 3;
108 } 176 }
177 std::memcpy(output.data(), &params, output.size());
178 return NvResult::Success;
179}
109 180
110 if (version == IoctlVersion::Version3) { 181NvResult nvhost_ctrl_gpu::GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
111 std::memcpy(output.data(), input.data(), output.size()); 182 std::vector<u8>& inline_output) {
112 std::memcpy(output2.data(), &params.tcp_mask, output2.size()); 183 IoctlGpuGetTpcMasksArgs params{};
113 } else { 184 std::memcpy(&params, input.data(), input.size());
114 std::memcpy(output.data(), &params, output.size()); 185 LOG_DEBUG(Service_NVDRV, "called, mask_buffer_size=0x{:X}", params.mask_buffer_size);
186 if (params.mask_buffer_size != 0) {
187 params.tcp_mask = 3;
115 } 188 }
116 189 std::memcpy(output.data(), &params, output.size());
117 return 0; 190 std::memcpy(inline_output.data(), &params.tcp_mask, inline_output.size());
191 return NvResult::Success;
118} 192}
119 193
120u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) { 194NvResult nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output) {
121 LOG_DEBUG(Service_NVDRV, "called"); 195 LOG_DEBUG(Service_NVDRV, "called");
122 196
123 IoctlActiveSlotMask params{}; 197 IoctlActiveSlotMask params{};
@@ -127,10 +201,10 @@ u32 nvhost_ctrl_gpu::GetActiveSlotMask(const std::vector<u8>& input, std::vector
127 params.slot = 0x07; 201 params.slot = 0x07;
128 params.mask = 0x01; 202 params.mask = 0x01;
129 std::memcpy(output.data(), &params, output.size()); 203 std::memcpy(output.data(), &params, output.size());
130 return 0; 204 return NvResult::Success;
131} 205}
132 206
133u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) { 207NvResult nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output) {
134 LOG_DEBUG(Service_NVDRV, "called"); 208 LOG_DEBUG(Service_NVDRV, "called");
135 209
136 IoctlZcullGetCtxSize params{}; 210 IoctlZcullGetCtxSize params{};
@@ -139,10 +213,10 @@ u32 nvhost_ctrl_gpu::ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u
139 } 213 }
140 params.size = 0x1; 214 params.size = 0x1;
141 std::memcpy(output.data(), &params, output.size()); 215 std::memcpy(output.data(), &params, output.size());
142 return 0; 216 return NvResult::Success;
143} 217}
144 218
145u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) { 219NvResult nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output) {
146 LOG_DEBUG(Service_NVDRV, "called"); 220 LOG_DEBUG(Service_NVDRV, "called");
147 221
148 IoctlNvgpuGpuZcullGetInfoArgs params{}; 222 IoctlNvgpuGpuZcullGetInfoArgs params{};
@@ -162,47 +236,47 @@ u32 nvhost_ctrl_gpu::ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>&
162 params.subregion_height_align_pixels = 0x40; 236 params.subregion_height_align_pixels = 0x40;
163 params.subregion_count = 0x10; 237 params.subregion_count = 0x10;
164 std::memcpy(output.data(), &params, output.size()); 238 std::memcpy(output.data(), &params, output.size());
165 return 0; 239 return NvResult::Success;
166} 240}
167 241
168u32 nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) { 242NvResult nvhost_ctrl_gpu::ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output) {
169 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 243 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
170 244
171 IoctlZbcSetTable params{}; 245 IoctlZbcSetTable params{};
172 std::memcpy(&params, input.data(), input.size()); 246 std::memcpy(&params, input.data(), input.size());
173 // TODO(ogniK): What does this even actually do? 247 // TODO(ogniK): What does this even actually do?
174 std::memcpy(output.data(), &params, output.size()); 248 std::memcpy(output.data(), &params, output.size());
175 return 0; 249 return NvResult::Success;
176} 250}
177 251
178u32 nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) { 252NvResult nvhost_ctrl_gpu::ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output) {
179 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 253 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
180 254
181 IoctlZbcQueryTable params{}; 255 IoctlZbcQueryTable params{};
182 std::memcpy(&params, input.data(), input.size()); 256 std::memcpy(&params, input.data(), input.size());
183 // TODO : To implement properly 257 // TODO : To implement properly
184 std::memcpy(output.data(), &params, output.size()); 258 std::memcpy(output.data(), &params, output.size());
185 return 0; 259 return NvResult::Success;
186} 260}
187 261
188u32 nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) { 262NvResult nvhost_ctrl_gpu::FlushL2(const std::vector<u8>& input, std::vector<u8>& output) {
189 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 263 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
190 264
191 IoctlFlushL2 params{}; 265 IoctlFlushL2 params{};
192 std::memcpy(&params, input.data(), input.size()); 266 std::memcpy(&params, input.data(), input.size());
193 // TODO : To implement properly 267 // TODO : To implement properly
194 std::memcpy(output.data(), &params, output.size()); 268 std::memcpy(output.data(), &params, output.size());
195 return 0; 269 return NvResult::Success;
196} 270}
197 271
198u32 nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) { 272NvResult nvhost_ctrl_gpu::GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output) {
199 LOG_DEBUG(Service_NVDRV, "called"); 273 LOG_DEBUG(Service_NVDRV, "called");
200 274
201 IoctlGetGpuTime params{}; 275 IoctlGetGpuTime params{};
202 std::memcpy(&params, input.data(), input.size()); 276 std::memcpy(&params, input.data(), input.size());
203 params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count()); 277 params.gpu_time = static_cast<u64_le>(system.CoreTiming().GetGlobalTimeNs().count());
204 std::memcpy(output.data(), &params, output.size()); 278 std::memcpy(output.data(), &params, output.size());
205 return 0; 279 return NvResult::Success;
206} 280}
207 281
208} // namespace Service::Nvidia::Devices 282} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
index ef60f72ce..137b88238 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h
@@ -16,32 +16,13 @@ public:
16 explicit nvhost_ctrl_gpu(Core::System& system); 16 explicit nvhost_ctrl_gpu(Core::System& system);
17 ~nvhost_ctrl_gpu() override; 17 ~nvhost_ctrl_gpu() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 19 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
20 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 20 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
21 IoctlVersion version) override; 21 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
22 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
23 std::vector<u8>& inline_output) override;
22 24
23private: 25private:
24 enum class IoctlCommand : u32_le {
25 IocGetCharacteristicsCommand = 0xC0B04705,
26 IocGetTPCMasksCommand = 0xC0184706,
27 IocGetActiveSlotMaskCommand = 0x80084714,
28 IocZcullGetCtxSizeCommand = 0x80044701,
29 IocZcullGetInfo = 0x80284702,
30 IocZbcSetTable = 0x402C4703,
31 IocZbcQueryTable = 0xC0344704,
32 IocFlushL2 = 0x40084707,
33 IocInvalICache = 0x4008470D,
34 IocSetMmudebugMode = 0x4008470E,
35 IocSetSmDebugMode = 0x4010470F,
36 IocWaitForPause = 0xC0084710,
37 IocGetTcpExceptionEnStatus = 0x80084711,
38 IocNumVsms = 0x80084712,
39 IocVsmsMapping = 0xC0044713,
40 IocGetErrorChannelUserData = 0xC008471B,
41 IocGetGpuTime = 0xC010471C,
42 IocGetCpuTimeCorrelationInfo = 0xC108471D,
43 };
44
45 struct IoctlGpuCharacteristics { 26 struct IoctlGpuCharacteristics {
46 u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200) 27 u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200)
47 u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B) 28 u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B)
@@ -159,17 +140,21 @@ private:
159 }; 140 };
160 static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); 141 static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
161 142
162 u32 GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output, 143 NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output);
163 std::vector<u8>& output2, IoctlVersion version); 144 NvResult GetCharacteristics(const std::vector<u8>& input, std::vector<u8>& output,
164 u32 GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output, std::vector<u8>& output2, 145 std::vector<u8>& inline_output);
165 IoctlVersion version); 146
166 u32 GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output); 147 NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output);
167 u32 ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output); 148 NvResult GetTPCMasks(const std::vector<u8>& input, std::vector<u8>& output,
168 u32 ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output); 149 std::vector<u8>& inline_output);
169 u32 ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output); 150
170 u32 ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output); 151 NvResult GetActiveSlotMask(const std::vector<u8>& input, std::vector<u8>& output);
171 u32 FlushL2(const std::vector<u8>& input, std::vector<u8>& output); 152 NvResult ZCullGetCtxSize(const std::vector<u8>& input, std::vector<u8>& output);
172 u32 GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output); 153 NvResult ZCullGetInfo(const std::vector<u8>& input, std::vector<u8>& output);
154 NvResult ZBCSetTable(const std::vector<u8>& input, std::vector<u8>& output);
155 NvResult ZBCQueryTable(const std::vector<u8>& input, std::vector<u8>& output);
156 NvResult FlushL2(const std::vector<u8>& input, std::vector<u8>& output);
157 NvResult GetGpuTime(const std::vector<u8>& input, std::vector<u8>& output);
173}; 158};
174 159
175} // namespace Service::Nvidia::Devices 160} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
index b1d9d55b5..af8b3d9f1 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp
@@ -23,107 +23,132 @@ nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
23 23
24nvhost_gpu::~nvhost_gpu() = default; 24nvhost_gpu::~nvhost_gpu() = default;
25 25
26u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 26NvResult nvhost_gpu::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
27 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 27 switch (command.group) {
28 IoctlVersion version) { 28 case 0x0:
29 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 29 switch (command.cmd) {
30 command.raw, input.size(), output.size()); 30 case 0x3:
31 31 return GetWaitbase(input, output);
32 switch (static_cast<IoctlCommand>(command.raw)) { 32 default:
33 case IoctlCommand::IocSetNVMAPfdCommand: 33 break;
34 return SetNVMAPfd(input, output); 34 }
35 case IoctlCommand::IocSetClientDataCommand: 35 break;
36 return SetClientData(input, output); 36 case 'H':
37 case IoctlCommand::IocGetClientDataCommand: 37 switch (command.cmd) {
38 return GetClientData(input, output); 38 case 0x1:
39 case IoctlCommand::IocZCullBind: 39 return SetNVMAPfd(input, output);
40 return ZCullBind(input, output); 40 case 0x3:
41 case IoctlCommand::IocSetErrorNotifierCommand: 41 return ChannelSetTimeout(input, output);
42 return SetErrorNotifier(input, output); 42 case 0x8:
43 case IoctlCommand::IocChannelSetPriorityCommand: 43 return SubmitGPFIFOBase(input, output, false);
44 return SetChannelPriority(input, output); 44 case 0x9:
45 case IoctlCommand::IocAllocGPFIFOEx2Command: 45 return AllocateObjectContext(input, output);
46 return AllocGPFIFOEx2(input, output); 46 case 0xb:
47 case IoctlCommand::IocAllocObjCtxCommand: 47 return ZCullBind(input, output);
48 return AllocateObjectContext(input, output); 48 case 0xc:
49 case IoctlCommand::IocChannelGetWaitbaseCommand: 49 return SetErrorNotifier(input, output);
50 return GetWaitbase(input, output); 50 case 0xd:
51 case IoctlCommand::IocChannelSetTimeoutCommand: 51 return SetChannelPriority(input, output);
52 return ChannelSetTimeout(input, output); 52 case 0x1a:
53 case IoctlCommand::IocChannelSetTimeslice: 53 return AllocGPFIFOEx2(input, output);
54 return ChannelSetTimeslice(input, output); 54 case 0x1b:
55 default: 55 return SubmitGPFIFOBase(input, output, true);
56 case 0x1d:
57 return ChannelSetTimeslice(input, output);
58 default:
59 break;
60 }
61 break;
62 case 'G':
63 switch (command.cmd) {
64 case 0x14:
65 return SetClientData(input, output);
66 case 0x15:
67 return GetClientData(input, output);
68 default:
69 break;
70 }
56 break; 71 break;
57 } 72 }
73 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
74 return NvResult::NotImplemented;
75};
58 76
59 if (command.group == NVGPU_IOCTL_MAGIC) { 77NvResult nvhost_gpu::Ioctl2(Ioctl command, const std::vector<u8>& input,
60 if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) { 78 const std::vector<u8>& inline_input, std::vector<u8>& output) {
61 return SubmitGPFIFO(input, output); 79 switch (command.group) {
62 } 80 case 'H':
63 if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) { 81 switch (command.cmd) {
64 return KickoffPB(input, output, input2, version); 82 case 0x1b:
83 return SubmitGPFIFOBase(input, inline_input, output);
65 } 84 }
85 break;
66 } 86 }
87 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
88 return NvResult::NotImplemented;
89}
67 90
68 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 91NvResult nvhost_gpu::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
69 return 0; 92 std::vector<u8>& inline_output) {
70}; 93 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
94 return NvResult::NotImplemented;
95}
71 96
72u32 nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { 97NvResult nvhost_gpu::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
73 IoctlSetNvmapFD params{}; 98 IoctlSetNvmapFD params{};
74 std::memcpy(&params, input.data(), input.size()); 99 std::memcpy(&params, input.data(), input.size());
75 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 100 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
76 101
77 nvmap_fd = params.nvmap_fd; 102 nvmap_fd = params.nvmap_fd;
78 return 0; 103 return NvResult::Success;
79} 104}
80 105
81u32 nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) { 106NvResult nvhost_gpu::SetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
82 LOG_DEBUG(Service_NVDRV, "called"); 107 LOG_DEBUG(Service_NVDRV, "called");
83 108
84 IoctlClientData params{}; 109 IoctlClientData params{};
85 std::memcpy(&params, input.data(), input.size()); 110 std::memcpy(&params, input.data(), input.size());
86 user_data = params.data; 111 user_data = params.data;
87 return 0; 112 return NvResult::Success;
88} 113}
89 114
90u32 nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) { 115NvResult nvhost_gpu::GetClientData(const std::vector<u8>& input, std::vector<u8>& output) {
91 LOG_DEBUG(Service_NVDRV, "called"); 116 LOG_DEBUG(Service_NVDRV, "called");
92 117
93 IoctlClientData params{}; 118 IoctlClientData params{};
94 std::memcpy(&params, input.data(), input.size()); 119 std::memcpy(&params, input.data(), input.size());
95 params.data = user_data; 120 params.data = user_data;
96 std::memcpy(output.data(), &params, output.size()); 121 std::memcpy(output.data(), &params, output.size());
97 return 0; 122 return NvResult::Success;
98} 123}
99 124
100u32 nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) { 125NvResult nvhost_gpu::ZCullBind(const std::vector<u8>& input, std::vector<u8>& output) {
101 std::memcpy(&zcull_params, input.data(), input.size()); 126 std::memcpy(&zcull_params, input.data(), input.size());
102 LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va, 127 LOG_DEBUG(Service_NVDRV, "called, gpu_va={:X}, mode={:X}", zcull_params.gpu_va,
103 zcull_params.mode); 128 zcull_params.mode);
104 129
105 std::memcpy(output.data(), &zcull_params, output.size()); 130 std::memcpy(output.data(), &zcull_params, output.size());
106 return 0; 131 return NvResult::Success;
107} 132}
108 133
109u32 nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) { 134NvResult nvhost_gpu::SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output) {
110 IoctlSetErrorNotifier params{}; 135 IoctlSetErrorNotifier params{};
111 std::memcpy(&params, input.data(), input.size()); 136 std::memcpy(&params, input.data(), input.size());
112 LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset, 137 LOG_WARNING(Service_NVDRV, "(STUBBED) called, offset={:X}, size={:X}, mem={:X}", params.offset,
113 params.size, params.mem); 138 params.size, params.mem);
114 139
115 std::memcpy(output.data(), &params, output.size()); 140 std::memcpy(output.data(), &params, output.size());
116 return 0; 141 return NvResult::Success;
117} 142}
118 143
119u32 nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) { 144NvResult nvhost_gpu::SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output) {
120 std::memcpy(&channel_priority, input.data(), input.size()); 145 std::memcpy(&channel_priority, input.data(), input.size());
121 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority); 146 LOG_DEBUG(Service_NVDRV, "(STUBBED) called, priority={:X}", channel_priority);
122 147
123 return 0; 148 return NvResult::Success;
124} 149}
125 150
126u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) { 151NvResult nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output) {
127 IoctlAllocGpfifoEx2 params{}; 152 IoctlAllocGpfifoEx2 params{};
128 std::memcpy(&params, input.data(), input.size()); 153 std::memcpy(&params, input.data(), input.size());
129 LOG_WARNING(Service_NVDRV, 154 LOG_WARNING(Service_NVDRV,
@@ -137,10 +162,10 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou
137 params.fence_out = channel_fence; 162 params.fence_out = channel_fence;
138 163
139 std::memcpy(output.data(), &params, output.size()); 164 std::memcpy(output.data(), &params, output.size());
140 return 0; 165 return NvResult::Success;
141} 166}
142 167
143u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) { 168NvResult nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output) {
144 IoctlAllocObjCtx params{}; 169 IoctlAllocObjCtx params{};
145 std::memcpy(&params, input.data(), input.size()); 170 std::memcpy(&params, input.data(), input.size());
146 LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num, 171 LOG_WARNING(Service_NVDRV, "(STUBBED) called, class_num={:X}, flags={:X}", params.class_num,
@@ -148,7 +173,7 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector<
148 173
149 params.obj_id = 0x0; 174 params.obj_id = 0x0;
150 std::memcpy(output.data(), &params, output.size()); 175 std::memcpy(output.data(), &params, output.size());
151 return 0; 176 return NvResult::Success;
152} 177}
153 178
154static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) { 179static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) {
@@ -192,8 +217,8 @@ static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence
192 return result; 217 return result;
193} 218}
194 219
195u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, 220NvResult nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
196 Tegra::CommandList&& entries) { 221 Tegra::CommandList&& entries) {
197 LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, 222 LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address,
198 params.num_entries, params.flags.raw); 223 params.num_entries, params.flags.raw);
199 224
@@ -227,69 +252,70 @@ u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& out
227 } 252 }
228 253
229 std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo)); 254 std::memcpy(output.data(), &params, sizeof(IoctlSubmitGpfifo));
230 return 0; 255 return NvResult::Success;
231} 256}
232 257
233u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { 258NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output,
259 bool kickoff) {
234 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 260 if (input.size() < sizeof(IoctlSubmitGpfifo)) {
235 UNIMPLEMENTED(); 261 UNIMPLEMENTED();
262 return NvResult::InvalidSize;
236 } 263 }
237 IoctlSubmitGpfifo params{}; 264 IoctlSubmitGpfifo params{};
238 std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo)); 265 std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
239
240 Tegra::CommandList entries(params.num_entries); 266 Tegra::CommandList entries(params.num_entries);
241 std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], 267
242 params.num_entries * sizeof(Tegra::CommandListHeader)); 268 if (kickoff) {
269 system.Memory().ReadBlock(params.address, entries.command_lists.data(),
270 params.num_entries * sizeof(Tegra::CommandListHeader));
271 } else {
272 std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)],
273 params.num_entries * sizeof(Tegra::CommandListHeader));
274 }
243 275
244 return SubmitGPFIFOImpl(params, output, std::move(entries)); 276 return SubmitGPFIFOImpl(params, output, std::move(entries));
245} 277}
246 278
247u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, 279NvResult nvhost_gpu::SubmitGPFIFOBase(const std::vector<u8>& input,
248 const std::vector<u8>& input2, IoctlVersion version) { 280 const std::vector<u8>& input_inline,
281 std::vector<u8>& output) {
249 if (input.size() < sizeof(IoctlSubmitGpfifo)) { 282 if (input.size() < sizeof(IoctlSubmitGpfifo)) {
250 UNIMPLEMENTED(); 283 UNIMPLEMENTED();
284 return NvResult::InvalidSize;
251 } 285 }
252 IoctlSubmitGpfifo params{}; 286 IoctlSubmitGpfifo params{};
253 std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo)); 287 std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
254
255 Tegra::CommandList entries(params.num_entries); 288 Tegra::CommandList entries(params.num_entries);
256 if (version == IoctlVersion::Version2) { 289 std::memcpy(entries.command_lists.data(), input_inline.data(), input_inline.size());
257 std::memcpy(entries.command_lists.data(), input2.data(),
258 params.num_entries * sizeof(Tegra::CommandListHeader));
259 } else {
260 system.Memory().ReadBlock(params.address, entries.command_lists.data(),
261 params.num_entries * sizeof(Tegra::CommandListHeader));
262 }
263
264 return SubmitGPFIFOImpl(params, output, std::move(entries)); 290 return SubmitGPFIFOImpl(params, output, std::move(entries));
265} 291}
266 292
267u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { 293NvResult nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
268 IoctlGetWaitbase params{}; 294 IoctlGetWaitbase params{};
269 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase)); 295 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
270 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown); 296 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
271 297
272 params.value = 0; // Seems to be hard coded at 0 298 params.value = 0; // Seems to be hard coded at 0
273 std::memcpy(output.data(), &params, output.size()); 299 std::memcpy(output.data(), &params, output.size());
274 return 0; 300 return NvResult::Success;
275} 301}
276 302
277u32 nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) { 303NvResult nvhost_gpu::ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
278 IoctlChannelSetTimeout params{}; 304 IoctlChannelSetTimeout params{};
279 std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout)); 305 std::memcpy(&params, input.data(), sizeof(IoctlChannelSetTimeout));
280 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout); 306 LOG_INFO(Service_NVDRV, "called, timeout=0x{:X}", params.timeout);
281 307
282 return 0; 308 return NvResult::Success;
283} 309}
284 310
285u32 nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) { 311NvResult nvhost_gpu::ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output) {
286 IoctlSetTimeslice params{}; 312 IoctlSetTimeslice params{};
287 std::memcpy(&params, input.data(), sizeof(IoctlSetTimeslice)); 313 std::memcpy(&params, input.data(), sizeof(IoctlSetTimeslice));
288 LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice); 314 LOG_INFO(Service_NVDRV, "called, timeslice=0x{:X}", params.timeslice);
289 315
290 channel_timeslice = params.timeslice; 316 channel_timeslice = params.timeslice;
291 317
292 return 0; 318 return NvResult::Success;
293} 319}
294 320
295} // namespace Service::Nvidia::Devices 321} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
index a252fc06d..e0298b4fe 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h
@@ -20,43 +20,19 @@ class SyncpointManager;
20namespace Service::Nvidia::Devices { 20namespace Service::Nvidia::Devices {
21 21
22class nvmap; 22class nvmap;
23constexpr u32 NVGPU_IOCTL_MAGIC('H');
24constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8);
25constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b);
26
27class nvhost_gpu final : public nvdevice { 23class nvhost_gpu final : public nvdevice {
28public: 24public:
29 explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, 25 explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev,
30 SyncpointManager& syncpoint_manager); 26 SyncpointManager& syncpoint_manager);
31 ~nvhost_gpu() override; 27 ~nvhost_gpu() override;
32 28
33 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 29 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
34 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 30 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
35 IoctlVersion version) override; 31 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
32 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
33 std::vector<u8>& inline_output) override;
36 34
37private: 35private:
38 enum class IoctlCommand : u32_le {
39 IocSetNVMAPfdCommand = 0x40044801,
40 IocAllocGPFIFOCommand = 0x40084805,
41 IocSetClientDataCommand = 0x40084714,
42 IocGetClientDataCommand = 0x80084715,
43 IocZCullBind = 0xc010480b,
44 IocSetErrorNotifierCommand = 0xC018480C,
45 IocChannelSetPriorityCommand = 0x4004480D,
46 IocEnableCommand = 0x0000480E,
47 IocDisableCommand = 0x0000480F,
48 IocPreemptCommand = 0x00004810,
49 IocForceResetCommand = 0x00004811,
50 IocEventIdControlCommand = 0x40084812,
51 IocGetErrorNotificationCommand = 0xC0104817,
52 IocAllocGPFIFOExCommand = 0x40204818,
53 IocAllocGPFIFOEx2Command = 0xC020481A,
54 IocAllocObjCtxCommand = 0xC0104809,
55 IocChannelGetWaitbaseCommand = 0xC0080003,
56 IocChannelSetTimeoutCommand = 0x40044803,
57 IocChannelSetTimeslice = 0xC004481D,
58 };
59
60 enum class CtxObjects : u32_le { 36 enum class CtxObjects : u32_le {
61 Ctx2D = 0x902D, 37 Ctx2D = 0x902D,
62 Ctx3D = 0xB197, 38 Ctx3D = 0xB197,
@@ -67,63 +43,63 @@ private:
67 }; 43 };
68 44
69 struct IoctlSetNvmapFD { 45 struct IoctlSetNvmapFD {
70 u32_le nvmap_fd; 46 s32_le nvmap_fd{};
71 }; 47 };
72 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); 48 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
73 49
74 struct IoctlChannelSetTimeout { 50 struct IoctlChannelSetTimeout {
75 u32_le timeout; 51 u32_le timeout{};
76 }; 52 };
77 static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size"); 53 static_assert(sizeof(IoctlChannelSetTimeout) == 4, "IoctlChannelSetTimeout is incorrect size");
78 54
79 struct IoctlAllocGPFIFO { 55 struct IoctlAllocGPFIFO {
80 u32_le num_entries; 56 u32_le num_entries{};
81 u32_le flags; 57 u32_le flags{};
82 }; 58 };
83 static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size"); 59 static_assert(sizeof(IoctlAllocGPFIFO) == 8, "IoctlAllocGPFIFO is incorrect size");
84 60
85 struct IoctlClientData { 61 struct IoctlClientData {
86 u64_le data; 62 u64_le data{};
87 }; 63 };
88 static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size"); 64 static_assert(sizeof(IoctlClientData) == 8, "IoctlClientData is incorrect size");
89 65
90 struct IoctlZCullBind { 66 struct IoctlZCullBind {
91 u64_le gpu_va; 67 u64_le gpu_va{};
92 u32_le mode; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf 68 u32_le mode{}; // 0=global, 1=no_ctxsw, 2=separate_buffer, 3=part_of_regular_buf
93 INSERT_PADDING_WORDS(1); 69 INSERT_PADDING_WORDS(1);
94 }; 70 };
95 static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size"); 71 static_assert(sizeof(IoctlZCullBind) == 16, "IoctlZCullBind is incorrect size");
96 72
97 struct IoctlSetErrorNotifier { 73 struct IoctlSetErrorNotifier {
98 u64_le offset; 74 u64_le offset{};
99 u64_le size; 75 u64_le size{};
100 u32_le mem; // nvmap object handle 76 u32_le mem{}; // nvmap object handle
101 INSERT_PADDING_WORDS(1); 77 INSERT_PADDING_WORDS(1);
102 }; 78 };
103 static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size"); 79 static_assert(sizeof(IoctlSetErrorNotifier) == 24, "IoctlSetErrorNotifier is incorrect size");
104 80
105 struct IoctlChannelSetPriority { 81 struct IoctlChannelSetPriority {
106 u32_le priority; 82 u32_le priority{};
107 }; 83 };
108 static_assert(sizeof(IoctlChannelSetPriority) == 4, 84 static_assert(sizeof(IoctlChannelSetPriority) == 4,
109 "IoctlChannelSetPriority is incorrect size"); 85 "IoctlChannelSetPriority is incorrect size");
110 86
111 struct IoctlSetTimeslice { 87 struct IoctlSetTimeslice {
112 u32_le timeslice; 88 u32_le timeslice{};
113 }; 89 };
114 static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size"); 90 static_assert(sizeof(IoctlSetTimeslice) == 4, "IoctlSetTimeslice is incorrect size");
115 91
116 struct IoctlEventIdControl { 92 struct IoctlEventIdControl {
117 u32_le cmd; // 0=disable, 1=enable, 2=clear 93 u32_le cmd{}; // 0=disable, 1=enable, 2=clear
118 u32_le id; 94 u32_le id{};
119 }; 95 };
120 static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size"); 96 static_assert(sizeof(IoctlEventIdControl) == 8, "IoctlEventIdControl is incorrect size");
121 97
122 struct IoctlGetErrorNotification { 98 struct IoctlGetErrorNotification {
123 u64_le timestamp; 99 u64_le timestamp{};
124 u32_le info32; 100 u32_le info32{};
125 u16_le info16; 101 u16_le info16{};
126 u16_le status; // always 0xFFFF 102 u16_le status{}; // always 0xFFFF
127 }; 103 };
128 static_assert(sizeof(IoctlGetErrorNotification) == 16, 104 static_assert(sizeof(IoctlGetErrorNotification) == 16,
129 "IoctlGetErrorNotification is incorrect size"); 105 "IoctlGetErrorNotification is incorrect size");
@@ -131,39 +107,39 @@ private:
131 static_assert(sizeof(Fence) == 8, "Fence is incorrect size"); 107 static_assert(sizeof(Fence) == 8, "Fence is incorrect size");
132 108
133 struct IoctlAllocGpfifoEx { 109 struct IoctlAllocGpfifoEx {
134 u32_le num_entries; 110 u32_le num_entries{};
135 u32_le flags; 111 u32_le flags{};
136 u32_le unk0; 112 u32_le unk0{};
137 u32_le unk1; 113 u32_le unk1{};
138 u32_le unk2; 114 u32_le unk2{};
139 u32_le unk3; 115 u32_le unk3{};
140 u32_le unk4; 116 u32_le unk4{};
141 u32_le unk5; 117 u32_le unk5{};
142 }; 118 };
143 static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size"); 119 static_assert(sizeof(IoctlAllocGpfifoEx) == 32, "IoctlAllocGpfifoEx is incorrect size");
144 120
145 struct IoctlAllocGpfifoEx2 { 121 struct IoctlAllocGpfifoEx2 {
146 u32_le num_entries; // in 122 u32_le num_entries{}; // in
147 u32_le flags; // in 123 u32_le flags{}; // in
148 u32_le unk0; // in (1 works) 124 u32_le unk0{}; // in (1 works)
149 Fence fence_out; // out 125 Fence fence_out{}; // out
150 u32_le unk1; // in 126 u32_le unk1{}; // in
151 u32_le unk2; // in 127 u32_le unk2{}; // in
152 u32_le unk3; // in 128 u32_le unk3{}; // in
153 }; 129 };
154 static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size"); 130 static_assert(sizeof(IoctlAllocGpfifoEx2) == 32, "IoctlAllocGpfifoEx2 is incorrect size");
155 131
156 struct IoctlAllocObjCtx { 132 struct IoctlAllocObjCtx {
157 u32_le class_num; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA, 133 u32_le class_num{}; // 0x902D=2d, 0xB197=3d, 0xB1C0=compute, 0xA140=kepler, 0xB0B5=DMA,
158 // 0xB06F=channel_gpfifo 134 // 0xB06F=channel_gpfifo
159 u32_le flags; 135 u32_le flags{};
160 u64_le obj_id; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported 136 u64_le obj_id{}; // (ignored) used for FREE_OBJ_CTX ioctl, which is not supported
161 }; 137 };
162 static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size"); 138 static_assert(sizeof(IoctlAllocObjCtx) == 16, "IoctlAllocObjCtx is incorrect size");
163 139
164 struct IoctlSubmitGpfifo { 140 struct IoctlSubmitGpfifo {
165 u64_le address; // pointer to gpfifo entry structs 141 u64_le address{}; // pointer to gpfifo entry structs
166 u32_le num_entries; // number of fence objects being submitted 142 u32_le num_entries{}; // number of fence objects being submitted
167 union { 143 union {
168 u32_le raw; 144 u32_le raw;
169 BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list 145 BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list
@@ -172,7 +148,7 @@ private:
172 BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt 148 BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt
173 BitField<8, 1, u32_le> increment; // increment the returned fence 149 BitField<8, 1, u32_le> increment; // increment the returned fence
174 } flags; 150 } flags;
175 Fence fence_out; // returned new fence object for others to wait on 151 Fence fence_out{}; // returned new fence object for others to wait on
176 152
177 u32 AddIncrementValue() const { 153 u32 AddIncrementValue() const {
178 return flags.add_increment.Value() << 1; 154 return flags.add_increment.Value() << 1;
@@ -182,33 +158,34 @@ private:
182 "IoctlSubmitGpfifo is incorrect size"); 158 "IoctlSubmitGpfifo is incorrect size");
183 159
184 struct IoctlGetWaitbase { 160 struct IoctlGetWaitbase {
185 u32 unknown; // seems to be ignored? Nintendo added this 161 u32 unknown{}; // seems to be ignored? Nintendo added this
186 u32 value; 162 u32 value{};
187 }; 163 };
188 static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size"); 164 static_assert(sizeof(IoctlGetWaitbase) == 8, "IoctlGetWaitbase is incorrect size");
189 165
190 u32_le nvmap_fd{}; 166 s32_le nvmap_fd{};
191 u64_le user_data{}; 167 u64_le user_data{};
192 IoctlZCullBind zcull_params{}; 168 IoctlZCullBind zcull_params{};
193 u32_le channel_priority{}; 169 u32_le channel_priority{};
194 u32_le channel_timeslice{}; 170 u32_le channel_timeslice{};
195 171
196 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); 172 NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
197 u32 SetClientData(const std::vector<u8>& input, std::vector<u8>& output); 173 NvResult SetClientData(const std::vector<u8>& input, std::vector<u8>& output);
198 u32 GetClientData(const std::vector<u8>& input, std::vector<u8>& output); 174 NvResult GetClientData(const std::vector<u8>& input, std::vector<u8>& output);
199 u32 ZCullBind(const std::vector<u8>& input, std::vector<u8>& output); 175 NvResult ZCullBind(const std::vector<u8>& input, std::vector<u8>& output);
200 u32 SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output); 176 NvResult SetErrorNotifier(const std::vector<u8>& input, std::vector<u8>& output);
201 u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); 177 NvResult SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output);
202 u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); 178 NvResult AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
203 u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); 179 NvResult AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
204 u32 SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, 180 NvResult SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output,
205 Tegra::CommandList&& entries); 181 Tegra::CommandList&& entries);
206 u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); 182 NvResult SubmitGPFIFOBase(const std::vector<u8>& input, std::vector<u8>& output,
207 u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, 183 bool kickoff = false);
208 const std::vector<u8>& input2, IoctlVersion version); 184 NvResult SubmitGPFIFOBase(const std::vector<u8>& input, const std::vector<u8>& input_inline,
209 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); 185 std::vector<u8>& output);
210 u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); 186 NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
211 u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); 187 NvResult ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);
188 NvResult ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output);
212 189
213 std::shared_ptr<nvmap> nvmap_dev; 190 std::shared_ptr<nvmap> nvmap_dev;
214 SyncpointManager& syncpoint_manager; 191 SyncpointManager& syncpoint_manager;
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index b6df48360..d8735491c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -15,46 +15,58 @@ nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_de
15 : nvhost_nvdec_common(system, std::move(nvmap_dev)) {} 15 : nvhost_nvdec_common(system, std::move(nvmap_dev)) {}
16nvhost_nvdec::~nvhost_nvdec() = default; 16nvhost_nvdec::~nvhost_nvdec() = default;
17 17
18u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 18NvResult nvhost_nvdec::Ioctl1(Ioctl command, const std::vector<u8>& input,
19 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 19 std::vector<u8>& output) {
20 IoctlVersion version) { 20 switch (command.group) {
21 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 21 case 0x0:
22 command.raw, input.size(), output.size()); 22 switch (command.cmd) {
23 23 case 0x1:
24 switch (static_cast<IoctlCommand>(command.raw)) { 24 return Submit(input, output);
25 case IoctlCommand::IocSetNVMAPfdCommand: 25 case 0x2:
26 return SetNVMAPfd(input); 26 return GetSyncpoint(input, output);
27 case IoctlCommand::IocSubmit: 27 case 0x3:
28 return Submit(input, output); 28 return GetWaitbase(input, output);
29 case IoctlCommand::IocGetSyncpoint: 29 case 0x7:
30 return GetSyncpoint(input, output); 30 return SetSubmitTimeout(input, output);
31 case IoctlCommand::IocGetWaitbase: 31 case 0x9:
32 return GetWaitbase(input, output); 32 return MapBuffer(input, output);
33 case IoctlCommand::IocMapBuffer: 33 case 0xa: {
34 case IoctlCommand::IocMapBuffer2: 34 if (command.length == 0x1c) {
35 case IoctlCommand::IocMapBuffer3: 35 LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
36 case IoctlCommand::IocMapBufferEx: 36 Tegra::ChCommandHeaderList cmdlist(1);
37 return MapBuffer(input, output); 37 cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F};
38 case IoctlCommand::IocUnmapBufferEx: { 38 system.GPU().PushCommandBuffer(cmdlist);
39 // This command is sent when the video stream has ended, flush all video contexts 39 }
40 // This is usually sent in the folowing order: vic, nvdec, vic. 40 return UnmapBuffer(input, output);
41 // Inform the GPU to clear any remaining nvdec buffers when this is detected. 41 }
42 LOG_INFO(Service_NVDRV, "NVDEC video stream ended"); 42 default:
43 Tegra::ChCommandHeaderList cmdlist(1); 43 break;
44 cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F}; 44 }
45 system.GPU().PushCommandBuffer(cmdlist); 45 break;
46 [[fallthrough]]; // fallthrough to unmap buffers 46 case 'H':
47 }; 47 switch (command.cmd) {
48 case IoctlCommand::IocUnmapBuffer: 48 case 0x1:
49 case IoctlCommand::IocUnmapBuffer2: 49 return SetNVMAPfd(input);
50 case IoctlCommand::IocUnmapBuffer3: 50 default:
51 return UnmapBuffer(input, output); 51 break;
52 case IoctlCommand::IocSetSubmitTimeout: 52 }
53 return SetSubmitTimeout(input, output); 53 break;
54 } 54 }
55 55
56 UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw); 56 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
57 return 0; 57 return NvResult::NotImplemented;
58}
59
60NvResult nvhost_nvdec::Ioctl2(Ioctl command, const std::vector<u8>& input,
61 const std::vector<u8>& inline_input, std::vector<u8>& output) {
62 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
63 return NvResult::NotImplemented;
64}
65
66NvResult nvhost_nvdec::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
67 std::vector<u8>& inline_output) {
68 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
69 return NvResult::NotImplemented;
58} 70}
59 71
60} // namespace Service::Nvidia::Devices 72} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index 102777ddd..79b8b6de1 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -14,26 +14,11 @@ public:
14 explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 14 explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
15 ~nvhost_nvdec() override; 15 ~nvhost_nvdec() override;
16 16
17 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 17 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
18 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 18 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
19 IoctlVersion version) override; 19 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
20 20 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
21private: 21 std::vector<u8>& inline_output) override;
22 enum class IoctlCommand : u32_le {
23 IocSetNVMAPfdCommand = 0x40044801,
24 IocSubmit = 0xC0400001,
25 IocGetSyncpoint = 0xC0080002,
26 IocGetWaitbase = 0xC0080003,
27 IocMapBuffer = 0xC01C0009,
28 IocMapBuffer2 = 0xC16C0009,
29 IocMapBuffer3 = 0xC15C0009,
30 IocMapBufferEx = 0xC0A40009,
31 IocUnmapBuffer = 0xC0A4000A,
32 IocUnmapBuffer2 = 0xC16C000A,
33 IocUnmapBufferEx = 0xC01C000A,
34 IocUnmapBuffer3 = 0xC15C000A,
35 IocSetSubmitTimeout = 0x40040007,
36 };
37}; 22};
38 23
39} // namespace Service::Nvidia::Devices 24} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
index 30f03f845..b49cecb42 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -36,26 +36,20 @@ std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::s
36} 36}
37} // Anonymous namespace 37} // Anonymous namespace
38 38
39namespace NvErrCodes {
40constexpr u32 Success{};
41[[maybe_unused]] constexpr u32 OutOfMemory{static_cast<u32>(-12)};
42constexpr u32 InvalidInput{static_cast<u32>(-22)};
43} // namespace NvErrCodes
44
45nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) 39nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
46 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} 40 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
47nvhost_nvdec_common::~nvhost_nvdec_common() = default; 41nvhost_nvdec_common::~nvhost_nvdec_common() = default;
48 42
49u32 nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { 43NvResult nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
50 IoctlSetNvmapFD params{}; 44 IoctlSetNvmapFD params{};
51 std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD)); 45 std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
52 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 46 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
53 47
54 nvmap_fd = params.nvmap_fd; 48 nvmap_fd = params.nvmap_fd;
55 return 0; 49 return NvResult::Success;
56} 50}
57 51
58u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) { 52NvResult nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
59 IoctlSubmit params{}; 53 IoctlSubmit params{};
60 std::memcpy(&params, input.data(), sizeof(IoctlSubmit)); 54 std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
61 LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count); 55 LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
@@ -83,12 +77,12 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o
83 77
84 for (const auto& cmd_buffer : command_buffers) { 78 for (const auto& cmd_buffer : command_buffers) {
85 auto object = nvmap_dev->GetObject(cmd_buffer.memory_id); 79 auto object = nvmap_dev->GetObject(cmd_buffer.memory_id);
86 ASSERT_OR_EXECUTE(object, return NvErrCodes::InvalidInput;); 80 ASSERT_OR_EXECUTE(object, return NvResult::InvalidState;);
87 const auto map = FindBufferMap(object->dma_map_addr); 81 const auto map = FindBufferMap(object->dma_map_addr);
88 if (!map) { 82 if (!map) {
89 LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}", 83 LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}",
90 object->addr, object->dma_map_addr); 84 object->addr, object->dma_map_addr);
91 return 0; 85 return NvResult::Success;
92 } 86 }
93 Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count); 87 Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
94 gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(), 88 gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(),
@@ -105,10 +99,10 @@ u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& o
105 offset = WriteVectors(output, syncpt_increments, offset); 99 offset = WriteVectors(output, syncpt_increments, offset);
106 offset = WriteVectors(output, wait_checks, offset); 100 offset = WriteVectors(output, wait_checks, offset);
107 101
108 return NvErrCodes::Success; 102 return NvResult::Success;
109} 103}
110 104
111u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { 105NvResult nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
112 IoctlGetSyncpoint params{}; 106 IoctlGetSyncpoint params{};
113 std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint)); 107 std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
114 LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param); 108 LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
@@ -118,18 +112,18 @@ u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<
118 params.value = 0; 112 params.value = 0;
119 std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint)); 113 std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
120 114
121 return NvErrCodes::Success; 115 return NvResult::Success;
122} 116}
123 117
124u32 nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { 118NvResult nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
125 IoctlGetWaitbase params{}; 119 IoctlGetWaitbase params{};
126 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase)); 120 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
127 params.value = 0; // Seems to be hard coded at 0 121 params.value = 0; // Seems to be hard coded at 0
128 std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase)); 122 std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
129 return 0; 123 return NvResult::Success;
130} 124}
131 125
132u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { 126NvResult nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
133 IoctlMapBuffer params{}; 127 IoctlMapBuffer params{};
134 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer)); 128 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
135 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); 129 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
@@ -143,7 +137,7 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>
143 if (!object) { 137 if (!object) {
144 LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle); 138 LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
145 std::memcpy(output.data(), &params, output.size()); 139 std::memcpy(output.data(), &params, output.size());
146 return NvErrCodes::InvalidInput; 140 return NvResult::InvalidState;
147 } 141 }
148 if (object->dma_map_addr == 0) { 142 if (object->dma_map_addr == 0) {
149 // NVDEC and VIC memory is in the 32-bit address space 143 // NVDEC and VIC memory is in the 32-bit address space
@@ -165,10 +159,10 @@ u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>
165 std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(), 159 std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),
166 cmd_buffer_handles.size() * sizeof(MapBufferEntry)); 160 cmd_buffer_handles.size() * sizeof(MapBufferEntry));
167 161
168 return NvErrCodes::Success; 162 return NvResult::Success;
169} 163}
170 164
171u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { 165NvResult nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
172 IoctlMapBuffer params{}; 166 IoctlMapBuffer params{};
173 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer)); 167 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
174 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries); 168 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
@@ -181,7 +175,7 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u
181 if (!object) { 175 if (!object) {
182 LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle); 176 LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
183 std::memcpy(output.data(), &params, output.size()); 177 std::memcpy(output.data(), &params, output.size());
184 return NvErrCodes::InvalidInput; 178 return NvResult::InvalidState;
185 } 179 }
186 if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) { 180 if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
187 gpu.MemoryManager().Unmap(object->dma_map_addr, *size); 181 gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
@@ -193,13 +187,14 @@ u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u
193 object->dma_map_addr = 0; 187 object->dma_map_addr = 0;
194 } 188 }
195 std::memset(output.data(), 0, output.size()); 189 std::memset(output.data(), 0, output.size());
196 return NvErrCodes::Success; 190 return NvResult::Success;
197} 191}
198 192
199u32 nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output) { 193NvResult nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input,
194 std::vector<u8>& output) {
200 std::memcpy(&submit_timeout, input.data(), input.size()); 195 std::memcpy(&submit_timeout, input.data(), input.size());
201 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 196 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
202 return NvErrCodes::Success; 197 return NvResult::Success;
203} 198}
204 199
205std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap( 200std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap(
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
index c249c5349..86ba3a4d1 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -18,9 +18,37 @@ public:
18 explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 18 explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
19 ~nvhost_nvdec_common() override; 19 ~nvhost_nvdec_common() override;
20 20
21 virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 21 /**
22 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 22 * Handles an ioctl1 request.
23 IoctlVersion version) = 0; 23 * @param command The ioctl command id.
24 * @param input A buffer containing the input data for the ioctl.
25 * @param output A buffer where the output data will be written to.
26 * @returns The result code of the ioctl.
27 */
28 virtual NvResult Ioctl1(Ioctl command, const std::vector<u8>& input,
29 std::vector<u8>& output) = 0;
30
31 /**
32 * Handles an ioctl2 request.
33 * @param command The ioctl command id.
34 * @param input A buffer containing the input data for the ioctl.
35 * @param inline_input A buffer containing the input data for the ioctl which has been inlined.
36 * @param output A buffer where the output data will be written to.
37 * @returns The result code of the ioctl.
38 */
39 virtual NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
40 const std::vector<u8>& inline_input, std::vector<u8>& output) = 0;
41
42 /**
43 * Handles an ioctl3 request.
44 * @param command The ioctl command id.
45 * @param input A buffer containing the input data for the ioctl.
46 * @param output A buffer where the output data will be written to.
47 * @param inline_output A buffer where the inlined output data will be written to.
48 * @returns The result code of the ioctl.
49 */
50 virtual NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
51 std::vector<u8>& inline_output) = 0;
24 52
25protected: 53protected:
26 class BufferMap final { 54 class BufferMap final {
@@ -63,102 +91,102 @@ protected:
63 }; 91 };
64 92
65 struct IoctlSetNvmapFD { 93 struct IoctlSetNvmapFD {
66 u32_le nvmap_fd; 94 s32_le nvmap_fd{};
67 }; 95 };
68 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); 96 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
69 97
70 struct IoctlSubmitCommandBuffer { 98 struct IoctlSubmitCommandBuffer {
71 u32_le id; 99 u32_le id{};
72 u32_le offset; 100 u32_le offset{};
73 u32_le count; 101 u32_le count{};
74 }; 102 };
75 static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC, 103 static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
76 "IoctlSubmitCommandBuffer is incorrect size"); 104 "IoctlSubmitCommandBuffer is incorrect size");
77 struct IoctlSubmit { 105 struct IoctlSubmit {
78 u32_le cmd_buffer_count; 106 u32_le cmd_buffer_count{};
79 u32_le relocation_count; 107 u32_le relocation_count{};
80 u32_le syncpoint_count; 108 u32_le syncpoint_count{};
81 u32_le fence_count; 109 u32_le fence_count{};
82 }; 110 };
83 static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size"); 111 static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size");
84 112
85 struct CommandBuffer { 113 struct CommandBuffer {
86 s32 memory_id; 114 s32 memory_id{};
87 u32 offset; 115 u32 offset{};
88 s32 word_count; 116 s32 word_count{};
89 }; 117 };
90 static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size"); 118 static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size");
91 119
92 struct Reloc { 120 struct Reloc {
93 s32 cmdbuffer_memory; 121 s32 cmdbuffer_memory{};
94 s32 cmdbuffer_offset; 122 s32 cmdbuffer_offset{};
95 s32 target; 123 s32 target{};
96 s32 target_offset; 124 s32 target_offset{};
97 }; 125 };
98 static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size"); 126 static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size");
99 127
100 struct SyncptIncr { 128 struct SyncptIncr {
101 u32 id; 129 u32 id{};
102 u32 increments; 130 u32 increments{};
103 }; 131 };
104 static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size"); 132 static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size");
105 133
106 struct Fence { 134 struct Fence {
107 u32 id; 135 u32 id{};
108 u32 value; 136 u32 value{};
109 }; 137 };
110 static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size"); 138 static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size");
111 139
112 struct IoctlGetSyncpoint { 140 struct IoctlGetSyncpoint {
113 // Input 141 // Input
114 u32_le param; 142 u32_le param{};
115 // Output 143 // Output
116 u32_le value; 144 u32_le value{};
117 }; 145 };
118 static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size"); 146 static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size");
119 147
120 struct IoctlGetWaitbase { 148 struct IoctlGetWaitbase {
121 u32_le unknown; // seems to be ignored? Nintendo added this 149 u32_le unknown{}; // seems to be ignored? Nintendo added this
122 u32_le value; 150 u32_le value{};
123 }; 151 };
124 static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size"); 152 static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
125 153
126 struct IoctlMapBuffer { 154 struct IoctlMapBuffer {
127 u32_le num_entries; 155 u32_le num_entries{};
128 u32_le data_address; // Ignored by the driver. 156 u32_le data_address{}; // Ignored by the driver.
129 u32_le attach_host_ch_das; 157 u32_le attach_host_ch_das{};
130 }; 158 };
131 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); 159 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
132 160
133 struct IocGetIdParams { 161 struct IocGetIdParams {
134 // Input 162 // Input
135 u32_le param; 163 u32_le param{};
136 // Output 164 // Output
137 u32_le value; 165 u32_le value{};
138 }; 166 };
139 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); 167 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
140 168
141 // Used for mapping and unmapping command buffers 169 // Used for mapping and unmapping command buffers
142 struct MapBufferEntry { 170 struct MapBufferEntry {
143 u32_le map_handle; 171 u32_le map_handle{};
144 u32_le map_address; 172 u32_le map_address{};
145 }; 173 };
146 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size"); 174 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
147 175
148 /// Ioctl command implementations 176 /// Ioctl command implementations
149 u32 SetNVMAPfd(const std::vector<u8>& input); 177 NvResult SetNVMAPfd(const std::vector<u8>& input);
150 u32 Submit(const std::vector<u8>& input, std::vector<u8>& output); 178 NvResult Submit(const std::vector<u8>& input, std::vector<u8>& output);
151 u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output); 179 NvResult GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
152 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); 180 NvResult GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
153 u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output); 181 NvResult MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
154 u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output); 182 NvResult UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
155 u32 SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output); 183 NvResult SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
156 184
157 std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const; 185 std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
158 void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated); 186 void AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr, bool is_allocated);
159 std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr); 187 std::optional<std::size_t> RemoveBufferMap(GPUVAddr gpu_addr);
160 188
161 u32_le nvmap_fd{}; 189 s32_le nvmap_fd{};
162 u32_le submit_timeout{}; 190 u32_le submit_timeout{};
163 std::shared_ptr<nvmap> nvmap_dev; 191 std::shared_ptr<nvmap> nvmap_dev;
164 192
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
index 96e7b7dab..2d06955c0 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.cpp
@@ -13,28 +13,44 @@ namespace Service::Nvidia::Devices {
13nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {} 13nvhost_nvjpg::nvhost_nvjpg(Core::System& system) : nvdevice(system) {}
14nvhost_nvjpg::~nvhost_nvjpg() = default; 14nvhost_nvjpg::~nvhost_nvjpg() = default;
15 15
16u32 nvhost_nvjpg::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 16NvResult nvhost_nvjpg::Ioctl1(Ioctl command, const std::vector<u8>& input,
17 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 17 std::vector<u8>& output) {
18 IoctlVersion version) { 18 switch (command.group) {
19 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 19 case 'H':
20 command.raw, input.size(), output.size()); 20 switch (command.cmd) {
21 21 case 0x1:
22 switch (static_cast<IoctlCommand>(command.raw)) { 22 return SetNVMAPfd(input, output);
23 case IoctlCommand::IocSetNVMAPfdCommand: 23 default:
24 return SetNVMAPfd(input, output); 24 break;
25 }
26 break;
27 default:
28 break;
25 } 29 }
26 30
27 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 31 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
28 return 0; 32 return NvResult::NotImplemented;
29} 33}
30 34
31u32 nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { 35NvResult nvhost_nvjpg::Ioctl2(Ioctl command, const std::vector<u8>& input,
36 const std::vector<u8>& inline_input, std::vector<u8>& output) {
37 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
38 return NvResult::NotImplemented;
39}
40
41NvResult nvhost_nvjpg::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
42 std::vector<u8>& inline_output) {
43 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
44 return NvResult::NotImplemented;
45}
46
47NvResult nvhost_nvjpg::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
32 IoctlSetNvmapFD params{}; 48 IoctlSetNvmapFD params{};
33 std::memcpy(&params, input.data(), input.size()); 49 std::memcpy(&params, input.data(), input.size());
34 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd); 50 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
35 51
36 nvmap_fd = params.nvmap_fd; 52 nvmap_fd = params.nvmap_fd;
37 return 0; 53 return NvResult::Success;
38} 54}
39 55
40} // namespace Service::Nvidia::Devices 56} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
index 98dcac52f..43948d18d 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvjpg.h
@@ -16,23 +16,21 @@ public:
16 explicit nvhost_nvjpg(Core::System& system); 16 explicit nvhost_nvjpg(Core::System& system);
17 ~nvhost_nvjpg() override; 17 ~nvhost_nvjpg() override;
18 18
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 19 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
20 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 20 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
21 IoctlVersion version) override; 21 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
22 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
23 std::vector<u8>& inline_output) override;
22 24
23private: 25private:
24 enum class IoctlCommand : u32_le {
25 IocSetNVMAPfdCommand = 0x40044801,
26 };
27
28 struct IoctlSetNvmapFD { 26 struct IoctlSetNvmapFD {
29 u32_le nvmap_fd; 27 s32_le nvmap_fd{};
30 }; 28 };
31 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size"); 29 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
32 30
33 u32_le nvmap_fd{}; 31 s32_le nvmap_fd{};
34 32
35 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output); 33 NvResult SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
36}; 34};
37 35
38} // namespace Service::Nvidia::Devices 36} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
index 60db54d00..805fe86ae 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -15,36 +15,50 @@ nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
15 15
16nvhost_vic::~nvhost_vic() = default; 16nvhost_vic::~nvhost_vic() = default;
17 17
18u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 18NvResult nvhost_vic::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
19 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 19 switch (command.group) {
20 IoctlVersion version) { 20 case 0x0:
21 LOG_DEBUG(Service_NVDRV, "called, command=0x{:08X}, input_size=0x{:X}, output_size=0x{:X}", 21 switch (command.cmd) {
22 command.raw, input.size(), output.size()); 22 case 0x1:
23 23 return Submit(input, output);
24 switch (static_cast<IoctlCommand>(command.raw)) { 24 case 0x2:
25 case IoctlCommand::IocSetNVMAPfdCommand: 25 return GetSyncpoint(input, output);
26 return SetNVMAPfd(input); 26 case 0x3:
27 case IoctlCommand::IocSubmit: 27 return GetWaitbase(input, output);
28 return Submit(input, output); 28 case 0x9:
29 case IoctlCommand::IocGetSyncpoint: 29 return MapBuffer(input, output);
30 return GetSyncpoint(input, output); 30 case 0xa:
31 case IoctlCommand::IocGetWaitbase: 31 return UnmapBuffer(input, output);
32 return GetWaitbase(input, output); 32 default:
33 case IoctlCommand::IocMapBuffer: 33 break;
34 case IoctlCommand::IocMapBuffer2: 34 }
35 case IoctlCommand::IocMapBuffer3: 35 break;
36 case IoctlCommand::IocMapBuffer4: 36 case 'H':
37 case IoctlCommand::IocMapBufferEx: 37 switch (command.cmd) {
38 return MapBuffer(input, output); 38 case 0x1:
39 case IoctlCommand::IocUnmapBuffer: 39 return SetNVMAPfd(input);
40 case IoctlCommand::IocUnmapBuffer2: 40 default:
41 case IoctlCommand::IocUnmapBuffer3: 41 break;
42 case IoctlCommand::IocUnmapBufferEx: 42 }
43 return UnmapBuffer(input, output); 43 break;
44 default:
45 break;
44 } 46 }
45 47
46 UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw); 48 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
47 return 0; 49 return NvResult::NotImplemented;
50}
51
52NvResult nvhost_vic::Ioctl2(Ioctl command, const std::vector<u8>& input,
53 const std::vector<u8>& inline_input, std::vector<u8>& output) {
54 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
55 return NvResult::NotImplemented;
56}
57
58NvResult nvhost_vic::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
59 std::vector<u8>& inline_output) {
60 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
61 return NvResult::NotImplemented;
48} 62}
49 63
50} // namespace Service::Nvidia::Devices 64} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index f975b190c..b2e11f4d4 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -13,25 +13,11 @@ class nvhost_vic final : public nvhost_nvdec_common {
13public: 13public:
14 explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); 14 explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
15 ~nvhost_vic(); 15 ~nvhost_vic();
16 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
17 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
18 IoctlVersion version) override;
19 16
20private: 17 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
21 enum class IoctlCommand : u32_le { 18 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
22 IocSetNVMAPfdCommand = 0x40044801, 19 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
23 IocSubmit = 0xC0400001, 20 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
24 IocGetSyncpoint = 0xC0080002, 21 std::vector<u8>& inline_output) override;
25 IocGetWaitbase = 0xC0080003,
26 IocMapBuffer = 0xC01C0009,
27 IocMapBuffer2 = 0xC0340009,
28 IocMapBuffer3 = 0xC0140009,
29 IocMapBuffer4 = 0xC00C0009,
30 IocMapBufferEx = 0xC03C0009,
31 IocUnmapBuffer = 0xC03C000A,
32 IocUnmapBuffer2 = 0xC034000A,
33 IocUnmapBuffer3 = 0xC00C000A,
34 IocUnmapBufferEx = 0xC01C000A,
35 };
36}; 22};
37} // namespace Service::Nvidia::Devices 23} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.cpp b/src/core/hle/service/nvdrv/devices/nvmap.cpp
index 9436e16ad..4015a2740 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvmap.cpp
@@ -11,13 +11,6 @@
11 11
12namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
13 13
14namespace NvErrCodes {
15enum {
16 OperationNotPermitted = -1,
17 InvalidValue = -22,
18};
19}
20
21nvmap::nvmap(Core::System& system) : nvdevice(system) { 14nvmap::nvmap(Core::System& system) : nvdevice(system) {
22 // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to 15 // Handle 0 appears to be used when remapping, so we create a placeholder empty nvmap object to
23 // represent this. 16 // represent this.
@@ -26,6 +19,46 @@ nvmap::nvmap(Core::System& system) : nvdevice(system) {
26 19
27nvmap::~nvmap() = default; 20nvmap::~nvmap() = default;
28 21
22NvResult nvmap::Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) {
23 switch (command.group) {
24 case 0x1:
25 switch (command.cmd) {
26 case 0x1:
27 return IocCreate(input, output);
28 case 0x3:
29 return IocFromId(input, output);
30 case 0x4:
31 return IocAlloc(input, output);
32 case 0x5:
33 return IocFree(input, output);
34 case 0x9:
35 return IocParam(input, output);
36 case 0xe:
37 return IocGetId(input, output);
38 default:
39 break;
40 }
41 break;
42 default:
43 break;
44 }
45
46 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
47 return NvResult::NotImplemented;
48}
49
50NvResult nvmap::Ioctl2(Ioctl command, const std::vector<u8>& input,
51 const std::vector<u8>& inline_input, std::vector<u8>& output) {
52 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
53 return NvResult::NotImplemented;
54}
55
56NvResult nvmap::Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
57 std::vector<u8>& inline_output) {
58 UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
59 return NvResult::NotImplemented;
60}
61
29VAddr nvmap::GetObjectAddress(u32 handle) const { 62VAddr nvmap::GetObjectAddress(u32 handle) const {
30 auto object = GetObject(handle); 63 auto object = GetObject(handle);
31 ASSERT(object); 64 ASSERT(object);
@@ -33,28 +66,6 @@ VAddr nvmap::GetObjectAddress(u32 handle) const {
33 return object->addr; 66 return object->addr;
34} 67}
35 68
36u32 nvmap::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
37 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
38 IoctlVersion version) {
39 switch (static_cast<IoctlCommand>(command.raw)) {
40 case IoctlCommand::Create:
41 return IocCreate(input, output);
42 case IoctlCommand::Alloc:
43 return IocAlloc(input, output);
44 case IoctlCommand::GetId:
45 return IocGetId(input, output);
46 case IoctlCommand::FromId:
47 return IocFromId(input, output);
48 case IoctlCommand::Param:
49 return IocParam(input, output);
50 case IoctlCommand::Free:
51 return IocFree(input, output);
52 }
53
54 UNIMPLEMENTED_MSG("Unimplemented ioctl");
55 return 0;
56}
57
58u32 nvmap::CreateObject(u32 size) { 69u32 nvmap::CreateObject(u32 size) {
59 // Create a new nvmap object and obtain a handle to it. 70 // Create a new nvmap object and obtain a handle to it.
60 auto object = std::make_shared<Object>(); 71 auto object = std::make_shared<Object>();
@@ -70,35 +81,35 @@ u32 nvmap::CreateObject(u32 size) {
70 return handle; 81 return handle;
71} 82}
72 83
73u32 nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) { 84NvResult nvmap::IocCreate(const std::vector<u8>& input, std::vector<u8>& output) {
74 IocCreateParams params; 85 IocCreateParams params;
75 std::memcpy(&params, input.data(), sizeof(params)); 86 std::memcpy(&params, input.data(), sizeof(params));
76 LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size); 87 LOG_DEBUG(Service_NVDRV, "size=0x{:08X}", params.size);
77 88
78 if (!params.size) { 89 if (!params.size) {
79 LOG_ERROR(Service_NVDRV, "Size is 0"); 90 LOG_ERROR(Service_NVDRV, "Size is 0");
80 return static_cast<u32>(NvErrCodes::InvalidValue); 91 return NvResult::BadValue;
81 } 92 }
82 93
83 params.handle = CreateObject(params.size); 94 params.handle = CreateObject(params.size);
84 95
85 std::memcpy(output.data(), &params, sizeof(params)); 96 std::memcpy(output.data(), &params, sizeof(params));
86 return 0; 97 return NvResult::Success;
87} 98}
88 99
89u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) { 100NvResult nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
90 IocAllocParams params; 101 IocAllocParams params;
91 std::memcpy(&params, input.data(), sizeof(params)); 102 std::memcpy(&params, input.data(), sizeof(params));
92 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr); 103 LOG_DEBUG(Service_NVDRV, "called, addr={:X}", params.addr);
93 104
94 if (!params.handle) { 105 if (!params.handle) {
95 LOG_ERROR(Service_NVDRV, "Handle is 0"); 106 LOG_ERROR(Service_NVDRV, "Handle is 0");
96 return static_cast<u32>(NvErrCodes::InvalidValue); 107 return NvResult::BadValue;
97 } 108 }
98 109
99 if ((params.align - 1) & params.align) { 110 if ((params.align - 1) & params.align) {
100 LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align); 111 LOG_ERROR(Service_NVDRV, "Incorrect alignment used, alignment={:08X}", params.align);
101 return static_cast<u32>(NvErrCodes::InvalidValue); 112 return NvResult::BadValue;
102 } 113 }
103 114
104 const u32 min_alignment = 0x1000; 115 const u32 min_alignment = 0x1000;
@@ -109,12 +120,12 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
109 auto object = GetObject(params.handle); 120 auto object = GetObject(params.handle);
110 if (!object) { 121 if (!object) {
111 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); 122 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
112 return static_cast<u32>(NvErrCodes::InvalidValue); 123 return NvResult::BadValue;
113 } 124 }
114 125
115 if (object->status == Object::Status::Allocated) { 126 if (object->status == Object::Status::Allocated) {
116 LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle); 127 LOG_ERROR(Service_NVDRV, "Object is already allocated, handle={:08X}", params.handle);
117 return static_cast<u32>(NvErrCodes::OperationNotPermitted); 128 return NvResult::InsufficientMemory;
118 } 129 }
119 130
120 object->flags = params.flags; 131 object->flags = params.flags;
@@ -124,10 +135,10 @@ u32 nvmap::IocAlloc(const std::vector<u8>& input, std::vector<u8>& output) {
124 object->status = Object::Status::Allocated; 135 object->status = Object::Status::Allocated;
125 136
126 std::memcpy(output.data(), &params, sizeof(params)); 137 std::memcpy(output.data(), &params, sizeof(params));
127 return 0; 138 return NvResult::Success;
128} 139}
129 140
130u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) { 141NvResult nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
131 IocGetIdParams params; 142 IocGetIdParams params;
132 std::memcpy(&params, input.data(), sizeof(params)); 143 std::memcpy(&params, input.data(), sizeof(params));
133 144
@@ -135,22 +146,22 @@ u32 nvmap::IocGetId(const std::vector<u8>& input, std::vector<u8>& output) {
135 146
136 if (!params.handle) { 147 if (!params.handle) {
137 LOG_ERROR(Service_NVDRV, "Handle is zero"); 148 LOG_ERROR(Service_NVDRV, "Handle is zero");
138 return static_cast<u32>(NvErrCodes::InvalidValue); 149 return NvResult::BadValue;
139 } 150 }
140 151
141 auto object = GetObject(params.handle); 152 auto object = GetObject(params.handle);
142 if (!object) { 153 if (!object) {
143 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); 154 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
144 return static_cast<u32>(NvErrCodes::OperationNotPermitted); 155 return NvResult::BadValue;
145 } 156 }
146 157
147 params.id = object->id; 158 params.id = object->id;
148 159
149 std::memcpy(output.data(), &params, sizeof(params)); 160 std::memcpy(output.data(), &params, sizeof(params));
150 return 0; 161 return NvResult::Success;
151} 162}
152 163
153u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) { 164NvResult nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
154 IocFromIdParams params; 165 IocFromIdParams params;
155 std::memcpy(&params, input.data(), sizeof(params)); 166 std::memcpy(&params, input.data(), sizeof(params));
156 167
@@ -160,13 +171,13 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
160 [&](const auto& entry) { return entry.second->id == params.id; }); 171 [&](const auto& entry) { return entry.second->id == params.id; });
161 if (itr == handles.end()) { 172 if (itr == handles.end()) {
162 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); 173 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
163 return static_cast<u32>(NvErrCodes::InvalidValue); 174 return NvResult::BadValue;
164 } 175 }
165 176
166 auto& object = itr->second; 177 auto& object = itr->second;
167 if (object->status != Object::Status::Allocated) { 178 if (object->status != Object::Status::Allocated) {
168 LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); 179 LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
169 return static_cast<u32>(NvErrCodes::InvalidValue); 180 return NvResult::BadValue;
170 } 181 }
171 182
172 itr->second->refcount++; 183 itr->second->refcount++;
@@ -175,10 +186,10 @@ u32 nvmap::IocFromId(const std::vector<u8>& input, std::vector<u8>& output) {
175 params.handle = itr->first; 186 params.handle = itr->first;
176 187
177 std::memcpy(output.data(), &params, sizeof(params)); 188 std::memcpy(output.data(), &params, sizeof(params));
178 return 0; 189 return NvResult::Success;
179} 190}
180 191
181u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) { 192NvResult nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
182 enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 }; 193 enum class ParamTypes { Size = 1, Alignment = 2, Base = 3, Heap = 4, Kind = 5, Compr = 6 };
183 194
184 IocParamParams params; 195 IocParamParams params;
@@ -189,12 +200,12 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
189 auto object = GetObject(params.handle); 200 auto object = GetObject(params.handle);
190 if (!object) { 201 if (!object) {
191 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); 202 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
192 return static_cast<u32>(NvErrCodes::InvalidValue); 203 return NvResult::BadValue;
193 } 204 }
194 205
195 if (object->status != Object::Status::Allocated) { 206 if (object->status != Object::Status::Allocated) {
196 LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle); 207 LOG_ERROR(Service_NVDRV, "Object is not allocated, handle={:08X}", params.handle);
197 return static_cast<u32>(NvErrCodes::OperationNotPermitted); 208 return NvResult::BadValue;
198 } 209 }
199 210
200 switch (static_cast<ParamTypes>(params.param)) { 211 switch (static_cast<ParamTypes>(params.param)) {
@@ -216,10 +227,10 @@ u32 nvmap::IocParam(const std::vector<u8>& input, std::vector<u8>& output) {
216 } 227 }
217 228
218 std::memcpy(output.data(), &params, sizeof(params)); 229 std::memcpy(output.data(), &params, sizeof(params));
219 return 0; 230 return NvResult::Success;
220} 231}
221 232
222u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) { 233NvResult nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
223 // TODO(Subv): These flags are unconfirmed. 234 // TODO(Subv): These flags are unconfirmed.
224 enum FreeFlags { 235 enum FreeFlags {
225 Freed = 0, 236 Freed = 0,
@@ -234,14 +245,14 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
234 auto itr = handles.find(params.handle); 245 auto itr = handles.find(params.handle);
235 if (itr == handles.end()) { 246 if (itr == handles.end()) {
236 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle); 247 LOG_ERROR(Service_NVDRV, "Object does not exist, handle={:08X}", params.handle);
237 return static_cast<u32>(NvErrCodes::InvalidValue); 248 return NvResult::BadValue;
238 } 249 }
239 if (!itr->second->refcount) { 250 if (!itr->second->refcount) {
240 LOG_ERROR( 251 LOG_ERROR(
241 Service_NVDRV, 252 Service_NVDRV,
242 "There is no references to this object. The object is already freed. handle={:08X}", 253 "There is no references to this object. The object is already freed. handle={:08X}",
243 params.handle); 254 params.handle);
244 return static_cast<u32>(NvErrCodes::InvalidValue); 255 return NvResult::BadValue;
245 } 256 }
246 257
247 itr->second->refcount--; 258 itr->second->refcount--;
@@ -261,7 +272,7 @@ u32 nvmap::IocFree(const std::vector<u8>& input, std::vector<u8>& output) {
261 handles.erase(params.handle); 272 handles.erase(params.handle);
262 273
263 std::memcpy(output.data(), &params, sizeof(params)); 274 std::memcpy(output.data(), &params, sizeof(params));
264 return 0; 275 return NvResult::Success;
265} 276}
266 277
267} // namespace Service::Nvidia::Devices 278} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvmap.h b/src/core/hle/service/nvdrv/devices/nvmap.h
index 04b9ef540..4484bd79f 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -19,13 +19,15 @@ public:
19 explicit nvmap(Core::System& system); 19 explicit nvmap(Core::System& system);
20 ~nvmap() override; 20 ~nvmap() override;
21 21
22 NvResult Ioctl1(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output) override;
23 NvResult Ioctl2(Ioctl command, const std::vector<u8>& input,
24 const std::vector<u8>& inline_input, std::vector<u8>& output) override;
25 NvResult Ioctl3(Ioctl command, const std::vector<u8>& input, std::vector<u8>& output,
26 std::vector<u8>& inline_output) override;
27
22 /// Returns the allocated address of an nvmap object given its handle. 28 /// Returns the allocated address of an nvmap object given its handle.
23 VAddr GetObjectAddress(u32 handle) const; 29 VAddr GetObjectAddress(u32 handle) const;
24 30
25 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
26 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
27 IoctlVersion version) override;
28
29 /// Represents an nvmap object. 31 /// Represents an nvmap object.
30 struct Object { 32 struct Object {
31 enum class Status { Created, Allocated }; 33 enum class Status { Created, Allocated };
@@ -58,76 +60,68 @@ private:
58 /// Mapping of currently allocated handles to the objects they represent. 60 /// Mapping of currently allocated handles to the objects they represent.
59 std::unordered_map<u32, std::shared_ptr<Object>> handles; 61 std::unordered_map<u32, std::shared_ptr<Object>> handles;
60 62
61 enum class IoctlCommand : u32 {
62 Create = 0xC0080101,
63 FromId = 0xC0080103,
64 Alloc = 0xC0200104,
65 Free = 0xC0180105,
66 Param = 0xC00C0109,
67 GetId = 0xC008010E,
68 };
69 struct IocCreateParams { 63 struct IocCreateParams {
70 // Input 64 // Input
71 u32_le size; 65 u32_le size{};
72 // Output 66 // Output
73 u32_le handle; 67 u32_le handle{};
74 }; 68 };
75 static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size"); 69 static_assert(sizeof(IocCreateParams) == 8, "IocCreateParams has wrong size");
76 70
77 struct IocFromIdParams { 71 struct IocFromIdParams {
78 // Input 72 // Input
79 u32_le id; 73 u32_le id{};
80 // Output 74 // Output
81 u32_le handle; 75 u32_le handle{};
82 }; 76 };
83 static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size"); 77 static_assert(sizeof(IocFromIdParams) == 8, "IocFromIdParams has wrong size");
84 78
85 struct IocAllocParams { 79 struct IocAllocParams {
86 // Input 80 // Input
87 u32_le handle; 81 u32_le handle{};
88 u32_le heap_mask; 82 u32_le heap_mask{};
89 u32_le flags; 83 u32_le flags{};
90 u32_le align; 84 u32_le align{};
91 u8 kind; 85 u8 kind{};
92 INSERT_PADDING_BYTES(7); 86 INSERT_PADDING_BYTES(7);
93 u64_le addr; 87 u64_le addr{};
94 }; 88 };
95 static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size"); 89 static_assert(sizeof(IocAllocParams) == 32, "IocAllocParams has wrong size");
96 90
97 struct IocFreeParams { 91 struct IocFreeParams {
98 u32_le handle; 92 u32_le handle{};
99 INSERT_PADDING_BYTES(4); 93 INSERT_PADDING_BYTES(4);
100 u64_le address; 94 u64_le address{};
101 u32_le size; 95 u32_le size{};
102 u32_le flags; 96 u32_le flags{};
103 }; 97 };
104 static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size"); 98 static_assert(sizeof(IocFreeParams) == 24, "IocFreeParams has wrong size");
105 99
106 struct IocParamParams { 100 struct IocParamParams {
107 // Input 101 // Input
108 u32_le handle; 102 u32_le handle{};
109 u32_le param; 103 u32_le param{};
110 // Output 104 // Output
111 u32_le result; 105 u32_le result{};
112 }; 106 };
113 static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size"); 107 static_assert(sizeof(IocParamParams) == 12, "IocParamParams has wrong size");
114 108
115 struct IocGetIdParams { 109 struct IocGetIdParams {
116 // Output 110 // Output
117 u32_le id; 111 u32_le id{};
118 // Input 112 // Input
119 u32_le handle; 113 u32_le handle{};
120 }; 114 };
121 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size"); 115 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
122 116
123 u32 CreateObject(u32 size); 117 u32 CreateObject(u32 size);
124 118
125 u32 IocCreate(const std::vector<u8>& input, std::vector<u8>& output); 119 NvResult IocCreate(const std::vector<u8>& input, std::vector<u8>& output);
126 u32 IocAlloc(const std::vector<u8>& input, std::vector<u8>& output); 120 NvResult IocAlloc(const std::vector<u8>& input, std::vector<u8>& output);
127 u32 IocGetId(const std::vector<u8>& input, std::vector<u8>& output); 121 NvResult IocGetId(const std::vector<u8>& input, std::vector<u8>& output);
128 u32 IocFromId(const std::vector<u8>& input, std::vector<u8>& output); 122 NvResult IocFromId(const std::vector<u8>& input, std::vector<u8>& output);
129 u32 IocParam(const std::vector<u8>& input, std::vector<u8>& output); 123 NvResult IocParam(const std::vector<u8>& input, std::vector<u8>& output);
130 u32 IocFree(const std::vector<u8>& input, std::vector<u8>& output); 124 NvResult IocFree(const std::vector<u8>& input, std::vector<u8>& output);
131}; 125};
132 126
133} // namespace Service::Nvidia::Devices 127} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/interface.cpp b/src/core/hle/service/nvdrv/interface.cpp
index 88fbfa9b0..f6c38e853 100644
--- a/src/core/hle/service/nvdrv/interface.cpp
+++ b/src/core/hle/service/nvdrv/interface.cpp
@@ -23,124 +23,170 @@ void NVDRV::SignalGPUInterruptSyncpt(const u32 syncpoint_id, const u32 value) {
23void NVDRV::Open(Kernel::HLERequestContext& ctx) { 23void NVDRV::Open(Kernel::HLERequestContext& ctx) {
24 LOG_DEBUG(Service_NVDRV, "called"); 24 LOG_DEBUG(Service_NVDRV, "called");
25 25
26 if (!is_initialized) {
27 ServiceError(ctx, NvResult::NotInitialized);
28 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
29 return;
30 }
31
26 const auto& buffer = ctx.ReadBuffer(); 32 const auto& buffer = ctx.ReadBuffer();
27 std::string device_name(buffer.begin(), buffer.end()); 33 const std::string device_name(buffer.begin(), buffer.end());
34 DeviceFD fd = nvdrv->Open(device_name);
28 35
29 u32 fd = nvdrv->Open(device_name);
30 IPC::ResponseBuilder rb{ctx, 4}; 36 IPC::ResponseBuilder rb{ctx, 4};
31 rb.Push(RESULT_SUCCESS); 37 rb.Push(RESULT_SUCCESS);
32 rb.Push<u32>(fd); 38 rb.Push<DeviceFD>(fd);
33 rb.Push<u32>(0); 39 rb.PushEnum(fd != INVALID_NVDRV_FD ? NvResult::Success : NvResult::FileOperationFailed);
40}
41
42void NVDRV::ServiceError(Kernel::HLERequestContext& ctx, NvResult result) {
43 IPC::ResponseBuilder rb{ctx, 3};
44 rb.Push(RESULT_SUCCESS);
45 rb.PushEnum(result);
34} 46}
35 47
36void NVDRV::IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version) { 48void NVDRV::Ioctl1(Kernel::HLERequestContext& ctx) {
37 IPC::RequestParser rp{ctx}; 49 IPC::RequestParser rp{ctx};
38 u32 fd = rp.Pop<u32>(); 50 const auto fd = rp.Pop<DeviceFD>();
39 u32 command = rp.Pop<u32>(); 51 const auto command = rp.PopRaw<Ioctl>();
40 52 LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
41 /// Ioctl 3 has 2 outputs, first in the input params, second is the result 53
42 std::vector<u8> output(ctx.GetWriteBufferSize(0)); 54 if (!is_initialized) {
43 std::vector<u8> output2; 55 ServiceError(ctx, NvResult::NotInitialized);
44 if (version == IoctlVersion::Version3) { 56 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
45 output2.resize((ctx.GetWriteBufferSize(1))); 57 return;
46 } 58 }
47 59
48 /// Ioctl2 has 2 inputs. It's used to pass data directly instead of providing a pointer. 60 // Check device
49 /// KickOfPB uses this 61 std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
50 auto input = ctx.ReadBuffer(0); 62 const auto input_buffer = ctx.ReadBuffer(0);
51 63
52 std::vector<u8> input2; 64 const auto nv_result = nvdrv->Ioctl1(fd, command, input_buffer, output_buffer);
53 if (version == IoctlVersion::Version2) {
54 input2 = ctx.ReadBuffer(1);
55 }
56 65
57 IoctlCtrl ctrl{}; 66 if (command.is_out != 0) {
58 67 ctx.WriteBuffer(output_buffer);
59 u32 result = nvdrv->Ioctl(fd, command, input, input2, output, output2, ctrl, version);
60
61 if (ctrl.must_delay) {
62 ctrl.fresh_call = false;
63 ctx.SleepClientThread(
64 "NVServices::DelayedResponse", ctrl.timeout,
65 [=, this](std::shared_ptr<Kernel::Thread> thread, Kernel::HLERequestContext& ctx_,
66 Kernel::ThreadWakeupReason reason) {
67 IoctlCtrl ctrl2{ctrl};
68 std::vector<u8> tmp_output = output;
69 std::vector<u8> tmp_output2 = output2;
70 const u32 ioctl_result = nvdrv->Ioctl(fd, command, input, input2, tmp_output,
71 tmp_output2, ctrl2, version);
72 ctx_.WriteBuffer(tmp_output, 0);
73 if (version == IoctlVersion::Version3) {
74 ctx_.WriteBuffer(tmp_output2, 1);
75 }
76 IPC::ResponseBuilder rb{ctx_, 3};
77 rb.Push(RESULT_SUCCESS);
78 rb.Push(ioctl_result);
79 },
80 nvdrv->GetEventWriteable(ctrl.event_id));
81 } else {
82 ctx.WriteBuffer(output);
83 if (version == IoctlVersion::Version3) {
84 ctx.WriteBuffer(output2, 1);
85 }
86 } 68 }
69
87 IPC::ResponseBuilder rb{ctx, 3}; 70 IPC::ResponseBuilder rb{ctx, 3};
88 rb.Push(RESULT_SUCCESS); 71 rb.Push(RESULT_SUCCESS);
89 rb.Push(result); 72 rb.PushEnum(nv_result);
90}
91
92void NVDRV::Ioctl(Kernel::HLERequestContext& ctx) {
93 LOG_DEBUG(Service_NVDRV, "called");
94 IoctlBase(ctx, IoctlVersion::Version1);
95} 73}
96 74
97void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) { 75void NVDRV::Ioctl2(Kernel::HLERequestContext& ctx) {
98 LOG_DEBUG(Service_NVDRV, "called"); 76 IPC::RequestParser rp{ctx};
99 IoctlBase(ctx, IoctlVersion::Version2); 77 const auto fd = rp.Pop<DeviceFD>();
78 const auto command = rp.PopRaw<Ioctl>();
79 LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
80
81 if (!is_initialized) {
82 ServiceError(ctx, NvResult::NotInitialized);
83 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
84 return;
85 }
86
87 const auto input_buffer = ctx.ReadBuffer(0);
88 const auto input_inlined_buffer = ctx.ReadBuffer(1);
89 std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
90
91 const auto nv_result =
92 nvdrv->Ioctl2(fd, command, input_buffer, input_inlined_buffer, output_buffer);
93
94 if (command.is_out != 0) {
95 ctx.WriteBuffer(output_buffer);
96 }
97
98 IPC::ResponseBuilder rb{ctx, 3};
99 rb.Push(RESULT_SUCCESS);
100 rb.PushEnum(nv_result);
100} 101}
101 102
102void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) { 103void NVDRV::Ioctl3(Kernel::HLERequestContext& ctx) {
103 LOG_DEBUG(Service_NVDRV, "called"); 104 IPC::RequestParser rp{ctx};
104 IoctlBase(ctx, IoctlVersion::Version3); 105 const auto fd = rp.Pop<DeviceFD>();
106 const auto command = rp.PopRaw<Ioctl>();
107 LOG_DEBUG(Service_NVDRV, "called fd={}, ioctl=0x{:08X}", fd, command.raw);
108
109 if (!is_initialized) {
110 ServiceError(ctx, NvResult::NotInitialized);
111 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
112 return;
113 }
114
115 const auto input_buffer = ctx.ReadBuffer(0);
116 std::vector<u8> output_buffer(ctx.GetWriteBufferSize(0));
117 std::vector<u8> output_buffer_inline(ctx.GetWriteBufferSize(1));
118
119 const auto nv_result =
120 nvdrv->Ioctl3(fd, command, input_buffer, output_buffer, output_buffer_inline);
121
122 if (command.is_out != 0) {
123 ctx.WriteBuffer(output_buffer, 0);
124 ctx.WriteBuffer(output_buffer_inline, 1);
125 }
126
127 IPC::ResponseBuilder rb{ctx, 3};
128 rb.Push(RESULT_SUCCESS);
129 rb.PushEnum(nv_result);
105} 130}
106 131
107void NVDRV::Close(Kernel::HLERequestContext& ctx) { 132void NVDRV::Close(Kernel::HLERequestContext& ctx) {
108 LOG_DEBUG(Service_NVDRV, "called"); 133 LOG_DEBUG(Service_NVDRV, "called");
109 134
110 IPC::RequestParser rp{ctx}; 135 if (!is_initialized) {
111 u32 fd = rp.Pop<u32>(); 136 ServiceError(ctx, NvResult::NotInitialized);
137 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
138 return;
139 }
112 140
113 auto result = nvdrv->Close(fd); 141 IPC::RequestParser rp{ctx};
142 const auto fd = rp.Pop<DeviceFD>();
143 const auto result = nvdrv->Close(fd);
114 144
115 IPC::ResponseBuilder rb{ctx, 2}; 145 IPC::ResponseBuilder rb{ctx, 3};
116 rb.Push(result); 146 rb.Push(RESULT_SUCCESS);
147 rb.PushEnum(result);
117} 148}
118 149
119void NVDRV::Initialize(Kernel::HLERequestContext& ctx) { 150void NVDRV::Initialize(Kernel::HLERequestContext& ctx) {
120 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 151 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
121 152
153 is_initialized = true;
154
122 IPC::ResponseBuilder rb{ctx, 3}; 155 IPC::ResponseBuilder rb{ctx, 3};
123 rb.Push(RESULT_SUCCESS); 156 rb.Push(RESULT_SUCCESS);
124 rb.Push<u32>(0); 157 rb.PushEnum(NvResult::Success);
125} 158}
126 159
127void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) { 160void NVDRV::QueryEvent(Kernel::HLERequestContext& ctx) {
128 IPC::RequestParser rp{ctx}; 161 IPC::RequestParser rp{ctx};
129 u32 fd = rp.Pop<u32>(); 162 const auto fd = rp.Pop<DeviceFD>();
130 // TODO(Blinkhawk): Figure the meaning of the flag at bit 16 163 const auto event_id = rp.Pop<u32>() & 0x00FF;
131 u32 event_id = rp.Pop<u32>() & 0x000000FF;
132 LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id); 164 LOG_WARNING(Service_NVDRV, "(STUBBED) called, fd={:X}, event_id={:X}", fd, event_id);
133 165
134 IPC::ResponseBuilder rb{ctx, 3, 1}; 166 if (!is_initialized) {
135 rb.Push(RESULT_SUCCESS); 167 ServiceError(ctx, NvResult::NotInitialized);
168 LOG_ERROR(Service_NVDRV, "NvServices is not initalized!");
169 return;
170 }
171
172 const auto nv_result = nvdrv->VerifyFD(fd);
173 if (nv_result != NvResult::Success) {
174 LOG_ERROR(Service_NVDRV, "Invalid FD specified DeviceFD={}!", fd);
175 ServiceError(ctx, nv_result);
176 return;
177 }
178
136 if (event_id < MaxNvEvents) { 179 if (event_id < MaxNvEvents) {
180 IPC::ResponseBuilder rb{ctx, 3, 1};
181 rb.Push(RESULT_SUCCESS);
137 auto event = nvdrv->GetEvent(event_id); 182 auto event = nvdrv->GetEvent(event_id);
138 event->Clear(); 183 event->Clear();
139 rb.PushCopyObjects(event); 184 rb.PushCopyObjects(event);
140 rb.Push<u32>(NvResult::Success); 185 rb.PushEnum(NvResult::Success);
141 } else { 186 } else {
142 rb.Push<u32>(0); 187 IPC::ResponseBuilder rb{ctx, 3};
143 rb.Push<u32>(NvResult::BadParameter); 188 rb.Push(RESULT_SUCCESS);
189 rb.PushEnum(NvResult::BadParameter);
144 } 190 }
145} 191}
146 192
@@ -151,7 +197,7 @@ void NVDRV::SetAruid(Kernel::HLERequestContext& ctx) {
151 197
152 IPC::ResponseBuilder rb{ctx, 3}; 198 IPC::ResponseBuilder rb{ctx, 3};
153 rb.Push(RESULT_SUCCESS); 199 rb.Push(RESULT_SUCCESS);
154 rb.Push<u32>(0); 200 rb.PushEnum(NvResult::Success);
155} 201}
156 202
157void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) { 203void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx) {
@@ -164,8 +210,9 @@ void NVDRV::SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ct
164void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) { 210void NVDRV::GetStatus(Kernel::HLERequestContext& ctx) {
165 LOG_WARNING(Service_NVDRV, "(STUBBED) called"); 211 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
166 212
167 IPC::ResponseBuilder rb{ctx, 2}; 213 IPC::ResponseBuilder rb{ctx, 3};
168 rb.Push(RESULT_SUCCESS); 214 rb.Push(RESULT_SUCCESS);
215 rb.PushEnum(NvResult::Success);
169} 216}
170 217
171void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) { 218void NVDRV::DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx) {
@@ -181,7 +228,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
181 : ServiceFramework(name), nvdrv(std::move(nvdrv)) { 228 : ServiceFramework(name), nvdrv(std::move(nvdrv)) {
182 static const FunctionInfo functions[] = { 229 static const FunctionInfo functions[] = {
183 {0, &NVDRV::Open, "Open"}, 230 {0, &NVDRV::Open, "Open"},
184 {1, &NVDRV::Ioctl, "Ioctl"}, 231 {1, &NVDRV::Ioctl1, "Ioctl"},
185 {2, &NVDRV::Close, "Close"}, 232 {2, &NVDRV::Close, "Close"},
186 {3, &NVDRV::Initialize, "Initialize"}, 233 {3, &NVDRV::Initialize, "Initialize"},
187 {4, &NVDRV::QueryEvent, "QueryEvent"}, 234 {4, &NVDRV::QueryEvent, "QueryEvent"},
diff --git a/src/core/hle/service/nvdrv/interface.h b/src/core/hle/service/nvdrv/interface.h
index 72e17a728..e05f905ae 100644
--- a/src/core/hle/service/nvdrv/interface.h
+++ b/src/core/hle/service/nvdrv/interface.h
@@ -23,7 +23,7 @@ public:
23 23
24private: 24private:
25 void Open(Kernel::HLERequestContext& ctx); 25 void Open(Kernel::HLERequestContext& ctx);
26 void Ioctl(Kernel::HLERequestContext& ctx); 26 void Ioctl1(Kernel::HLERequestContext& ctx);
27 void Ioctl2(Kernel::HLERequestContext& ctx); 27 void Ioctl2(Kernel::HLERequestContext& ctx);
28 void Ioctl3(Kernel::HLERequestContext& ctx); 28 void Ioctl3(Kernel::HLERequestContext& ctx);
29 void Close(Kernel::HLERequestContext& ctx); 29 void Close(Kernel::HLERequestContext& ctx);
@@ -33,11 +33,13 @@ private:
33 void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx); 33 void SetGraphicsFirmwareMemoryMarginEnabled(Kernel::HLERequestContext& ctx);
34 void GetStatus(Kernel::HLERequestContext& ctx); 34 void GetStatus(Kernel::HLERequestContext& ctx);
35 void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx); 35 void DumpGraphicsMemoryInfo(Kernel::HLERequestContext& ctx);
36 void IoctlBase(Kernel::HLERequestContext& ctx, IoctlVersion version); 36
37 void ServiceError(Kernel::HLERequestContext& ctx, NvResult result);
37 38
38 std::shared_ptr<Module> nvdrv; 39 std::shared_ptr<Module> nvdrv;
39 40
40 u64 pid{}; 41 u64 pid{};
42 bool is_initialized{};
41}; 43};
42 44
43} // namespace Service::Nvidia 45} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdata.h b/src/core/hle/service/nvdrv/nvdata.h
index 529b03471..3294bc0e7 100644
--- a/src/core/hle/service/nvdrv/nvdata.h
+++ b/src/core/hle/service/nvdrv/nvdata.h
@@ -1,12 +1,16 @@
1#pragma once 1#pragma once
2 2
3#include <array> 3#include <array>
4#include "common/bit_field.h"
4#include "common/common_types.h" 5#include "common/common_types.h"
5 6
6namespace Service::Nvidia { 7namespace Service::Nvidia {
7 8
8constexpr u32 MaxSyncPoints = 192; 9constexpr u32 MaxSyncPoints = 192;
9constexpr u32 MaxNvEvents = 64; 10constexpr u32 MaxNvEvents = 64;
11using DeviceFD = s32;
12
13constexpr DeviceFD INVALID_NVDRV_FD = -1;
10 14
11struct Fence { 15struct Fence {
12 s32 id; 16 s32 id;
@@ -20,11 +24,61 @@ struct MultiFence {
20 std::array<Fence, 4> fences; 24 std::array<Fence, 4> fences;
21}; 25};
22 26
23enum NvResult : u32 { 27enum class NvResult : u32 {
24 Success = 0, 28 Success = 0x0,
25 BadParameter = 4, 29 NotImplemented = 0x1,
26 Timeout = 5, 30 NotSupported = 0x2,
27 ResourceError = 15, 31 NotInitialized = 0x3,
32 BadParameter = 0x4,
33 Timeout = 0x5,
34 InsufficientMemory = 0x6,
35 ReadOnlyAttribute = 0x7,
36 InvalidState = 0x8,
37 InvalidAddress = 0x9,
38 InvalidSize = 0xA,
39 BadValue = 0xB,
40 AlreadyAllocated = 0xD,
41 Busy = 0xE,
42 ResourceError = 0xF,
43 CountMismatch = 0x10,
44 OverFlow = 0x11,
45 InsufficientTransferMemory = 0x1000,
46 InsufficientVideoMemory = 0x10000,
47 BadSurfaceColorScheme = 0x10001,
48 InvalidSurface = 0x10002,
49 SurfaceNotSupported = 0x10003,
50 DispInitFailed = 0x20000,
51 DispAlreadyAttached = 0x20001,
52 DispTooManyDisplays = 0x20002,
53 DispNoDisplaysAttached = 0x20003,
54 DispModeNotSupported = 0x20004,
55 DispNotFound = 0x20005,
56 DispAttachDissallowed = 0x20006,
57 DispTypeNotSupported = 0x20007,
58 DispAuthenticationFailed = 0x20008,
59 DispNotAttached = 0x20009,
60 DispSamePwrState = 0x2000A,
61 DispEdidFailure = 0x2000B,
62 DispDsiReadAckError = 0x2000C,
63 DispDsiReadInvalidResp = 0x2000D,
64 FileWriteFailed = 0x30000,
65 FileReadFailed = 0x30001,
66 EndOfFile = 0x30002,
67 FileOperationFailed = 0x30003,
68 DirOperationFailed = 0x30004,
69 EndOfDirList = 0x30005,
70 ConfigVarNotFound = 0x30006,
71 InvalidConfigVar = 0x30007,
72 LibraryNotFound = 0x30008,
73 SymbolNotFound = 0x30009,
74 MemoryMapFailed = 0x3000A,
75 IoctlFailed = 0x3000F,
76 AccessDenied = 0x30010,
77 DeviceNotFound = 0x30011,
78 KernelDriverNotFound = 0x30012,
79 FileNotFound = 0x30013,
80 PathAlreadyExists = 0x30014,
81 ModuleNotPresent = 0xA000E,
28}; 82};
29 83
30enum class EventState { 84enum class EventState {
@@ -34,21 +88,13 @@ enum class EventState {
34 Busy = 3, 88 Busy = 3,
35}; 89};
36 90
37enum class IoctlVersion : u32 { 91union Ioctl {
38 Version1, 92 u32_le raw;
39 Version2, 93 BitField<0, 8, u32> cmd;
40 Version3, 94 BitField<8, 8, u32> group;
41}; 95 BitField<16, 14, u32> length;
42 96 BitField<30, 1, u32> is_in;
43struct IoctlCtrl { 97 BitField<31, 1, u32> is_out;
44 // First call done to the servioce for services that call itself again after a call.
45 bool fresh_call{true};
46 // Tells the Ioctl Wrapper that it must delay the IPC response and send the thread to sleep
47 bool must_delay{};
48 // Timeout for the delay
49 s64 timeout{};
50 // NV Event Id
51 s32 event_id{-1};
52}; 98};
53 99
54} // namespace Service::Nvidia 100} // namespace Service::Nvidia
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 046a1f28c..bdbbedd0d 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -62,36 +62,101 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} {
62 62
63Module::~Module() = default; 63Module::~Module() = default;
64 64
65u32 Module::Open(const std::string& device_name) { 65NvResult Module::VerifyFD(DeviceFD fd) const {
66 ASSERT_MSG(devices.find(device_name) != devices.end(), "Trying to open unknown device {}", 66 if (fd < 0) {
67 device_name); 67 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
68 return NvResult::InvalidState;
69 }
70
71 if (open_files.find(fd) == open_files.end()) {
72 LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
73 return NvResult::NotImplemented;
74 }
75
76 return NvResult::Success;
77}
78
79DeviceFD Module::Open(const std::string& device_name) {
80 if (devices.find(device_name) == devices.end()) {
81 LOG_ERROR(Service_NVDRV, "Trying to open unknown device {}", device_name);
82 return INVALID_NVDRV_FD;
83 }
68 84
69 auto device = devices[device_name]; 85 auto device = devices[device_name];
70 const u32 fd = next_fd++; 86 const DeviceFD fd = next_fd++;
71 87
72 open_files[fd] = std::move(device); 88 open_files[fd] = std::move(device);
73 89
74 return fd; 90 return fd;
75} 91}
76 92
77u32 Module::Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, 93NvResult Module::Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
78 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 94 std::vector<u8>& output) {
79 IoctlVersion version) { 95 if (fd < 0) {
80 auto itr = open_files.find(fd); 96 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
81 ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); 97 return NvResult::InvalidState;
98 }
82 99
83 auto& device = itr->second; 100 const auto itr = open_files.find(fd);
84 return device->ioctl({command}, input, input2, output, output2, ctrl, version); 101
102 if (itr == open_files.end()) {
103 LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
104 return NvResult::NotImplemented;
105 }
106
107 return itr->second->Ioctl1(command, input, output);
85} 108}
86 109
87ResultCode Module::Close(u32 fd) { 110NvResult Module::Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
88 auto itr = open_files.find(fd); 111 const std::vector<u8>& inline_input, std::vector<u8>& output) {
89 ASSERT_MSG(itr != open_files.end(), "Tried to talk to an invalid device"); 112 if (fd < 0) {
113 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
114 return NvResult::InvalidState;
115 }
116
117 const auto itr = open_files.find(fd);
118
119 if (itr == open_files.end()) {
120 LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
121 return NvResult::NotImplemented;
122 }
123
124 return itr->second->Ioctl2(command, input, inline_input, output);
125}
126
127NvResult Module::Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
128 std::vector<u8>& output, std::vector<u8>& inline_output) {
129 if (fd < 0) {
130 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
131 return NvResult::InvalidState;
132 }
133
134 const auto itr = open_files.find(fd);
135
136 if (itr == open_files.end()) {
137 LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
138 return NvResult::NotImplemented;
139 }
140
141 return itr->second->Ioctl3(command, input, output, inline_output);
142}
143
144NvResult Module::Close(DeviceFD fd) {
145 if (fd < 0) {
146 LOG_ERROR(Service_NVDRV, "Invalid DeviceFD={}!", fd);
147 return NvResult::InvalidState;
148 }
149
150 const auto itr = open_files.find(fd);
151
152 if (itr == open_files.end()) {
153 LOG_ERROR(Service_NVDRV, "Could not find DeviceFD={}!", fd);
154 return NvResult::NotImplemented;
155 }
90 156
91 open_files.erase(itr); 157 open_files.erase(itr);
92 158
93 // TODO(flerovium): return correct result code if operation failed. 159 return NvResult::Success;
94 return RESULT_SUCCESS;
95} 160}
96 161
97void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) { 162void Module::SignalSyncpt(const u32 syncpoint_id, const u32 value) {
diff --git a/src/core/hle/service/nvdrv/nvdrv.h b/src/core/hle/service/nvdrv/nvdrv.h
index f3d863dac..7654bb026 100644
--- a/src/core/hle/service/nvdrv/nvdrv.h
+++ b/src/core/hle/service/nvdrv/nvdrv.h
@@ -112,14 +112,23 @@ public:
112 return std::static_pointer_cast<T>(itr->second); 112 return std::static_pointer_cast<T>(itr->second);
113 } 113 }
114 114
115 NvResult VerifyFD(DeviceFD fd) const;
116
115 /// Opens a device node and returns a file descriptor to it. 117 /// Opens a device node and returns a file descriptor to it.
116 u32 Open(const std::string& device_name); 118 DeviceFD Open(const std::string& device_name);
119
117 /// Sends an ioctl command to the specified file descriptor. 120 /// Sends an ioctl command to the specified file descriptor.
118 u32 Ioctl(u32 fd, u32 command, const std::vector<u8>& input, const std::vector<u8>& input2, 121 NvResult Ioctl1(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
119 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 122 std::vector<u8>& output);
120 IoctlVersion version); 123
124 NvResult Ioctl2(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
125 const std::vector<u8>& inline_input, std::vector<u8>& output);
126
127 NvResult Ioctl3(DeviceFD fd, Ioctl command, const std::vector<u8>& input,
128 std::vector<u8>& output, std::vector<u8>& inline_output);
129
121 /// Closes a device file descriptor and returns operation success. 130 /// Closes a device file descriptor and returns operation success.
122 ResultCode Close(u32 fd); 131 NvResult Close(DeviceFD fd);
123 132
124 void SignalSyncpt(const u32 syncpoint_id, const u32 value); 133 void SignalSyncpt(const u32 syncpoint_id, const u32 value);
125 134
@@ -132,10 +141,10 @@ private:
132 SyncpointManager syncpoint_manager; 141 SyncpointManager syncpoint_manager;
133 142
134 /// Id to use for the next open file descriptor. 143 /// Id to use for the next open file descriptor.
135 u32 next_fd = 1; 144 DeviceFD next_fd = 1;
136 145
137 /// Mapping of file descriptors to the devices they reference. 146 /// Mapping of file descriptors to the devices they reference.
138 std::unordered_map<u32, std::shared_ptr<Devices::nvdevice>> open_files; 147 std::unordered_map<DeviceFD, std::shared_ptr<Devices::nvdevice>> open_files;
139 148
140 /// Mapping of device node names to their implementation. 149 /// Mapping of device node names to their implementation.
141 std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices; 150 std::unordered_map<std::string, std::shared_ptr<Devices::nvdevice>> devices;
diff --git a/src/core/hle/service/olsc/olsc.cpp b/src/core/hle/service/olsc/olsc.cpp
new file mode 100644
index 000000000..aad4ca706
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc.cpp
@@ -0,0 +1,69 @@
1// Copyright 2020 yuzu emulator team
2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included.
4
5#include "core/hle/ipc_helpers.h"
6#include "core/hle/kernel/hle_ipc.h"
7#include "core/hle/service/olsc/olsc.h"
8#include "core/hle/service/service.h"
9#include "core/hle/service/sm/sm.h"
10
11namespace Service::OLSC {
12
13class OLSC final : public ServiceFramework<OLSC> {
14public:
15 explicit OLSC() : ServiceFramework{"olsc:u"} {
16 // clang-format off
17 static const FunctionInfo functions[] = {
18 {0, &OLSC::Initialize, "Initialize"},
19 {10, nullptr, "VerifySaveDataBackupLicenseAsync"},
20 {13, nullptr, "GetSaveDataBackupSetting"},
21 {14, &OLSC::SetSaveDataBackupSettingEnabled, "SetSaveDataBackupSettingEnabled"},
22 {15, nullptr, "SetCustomData"},
23 {16, nullptr, "DeleteSaveDataBackupSetting"},
24 {18, nullptr, "GetSaveDataBackupInfoCache"},
25 {19, nullptr, "UpdateSaveDataBackupInfoCacheAsync"},
26 {22, nullptr, "DeleteSaveDataBackupAsync"},
27 {25, nullptr, "ListDownloadableSaveDataBackupInfoAsync"},
28 {26, nullptr, "DownloadSaveDataBackupAsync"},
29 {9010, nullptr, "VerifySaveDataBackupLicenseAsyncForDebug"},
30 {9013, nullptr, "GetSaveDataBackupSettingForDebug"},
31 {9014, nullptr, "SetSaveDataBackupSettingEnabledForDebug"},
32 {9015, nullptr, "SetCustomDataForDebug"},
33 {9016, nullptr, "DeleteSaveDataBackupSettingForDebug"},
34 {9018, nullptr, "GetSaveDataBackupInfoCacheForDebug"},
35 {9019, nullptr, "UpdateSaveDataBackupInfoCacheAsyncForDebug"},
36 {9022, nullptr, "DeleteSaveDataBackupAsyncForDebug"},
37 {9025, nullptr, "ListDownloadableSaveDataBackupInfoAsyncForDebug"},
38 {9026, nullptr, "DownloadSaveDataBackupAsyncForDebug"},
39 };
40 // clang-format on
41
42 RegisterHandlers(functions);
43 }
44
45private:
46 void Initialize(Kernel::HLERequestContext& ctx) {
47 LOG_WARNING(Service_OLSC, "(STUBBED) called");
48
49 initialized = true;
50
51 IPC::ResponseBuilder rb{ctx, 2};
52 rb.Push(RESULT_SUCCESS);
53 }
54
55 void SetSaveDataBackupSettingEnabled(Kernel::HLERequestContext& ctx) {
56 LOG_WARNING(Service_OLSC, "(STUBBED) called");
57
58 IPC::ResponseBuilder rb{ctx, 2};
59 rb.Push(RESULT_SUCCESS);
60 }
61
62 bool initialized{};
63};
64
65void InstallInterfaces(SM::ServiceManager& service_manager) {
66 std::make_shared<OLSC>()->InstallAsService(service_manager);
67}
68
69} // namespace Service::OLSC
diff --git a/src/core/hle/service/olsc/olsc.h b/src/core/hle/service/olsc/olsc.h
new file mode 100644
index 000000000..edee4376b
--- /dev/null
+++ b/src/core/hle/service/olsc/olsc.h
@@ -0,0 +1,16 @@
1// Copyright 2020 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::OLSC {
12
13/// Registers all SSL services with the specified service manager.
14void InstallInterfaces(SM::ServiceManager& service_manager);
15
16} // namespace Service::OLSC
diff --git a/src/core/hle/service/service.cpp b/src/core/hle/service/service.cpp
index ba9159ee0..fbfda2d5b 100644
--- a/src/core/hle/service/service.cpp
+++ b/src/core/hle/service/service.cpp
@@ -51,6 +51,7 @@
51#include "core/hle/service/ns/ns.h" 51#include "core/hle/service/ns/ns.h"
52#include "core/hle/service/nvdrv/nvdrv.h" 52#include "core/hle/service/nvdrv/nvdrv.h"
53#include "core/hle/service/nvflinger/nvflinger.h" 53#include "core/hle/service/nvflinger/nvflinger.h"
54#include "core/hle/service/olsc/olsc.h"
54#include "core/hle/service/pcie/pcie.h" 55#include "core/hle/service/pcie/pcie.h"
55#include "core/hle/service/pctl/module.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"
@@ -231,6 +232,7 @@ void Init(std::shared_ptr<SM::ServiceManager>& sm, Core::System& system) {
231 NPNS::InstallInterfaces(*sm); 232 NPNS::InstallInterfaces(*sm);
232 NS::InstallInterfaces(*sm, system); 233 NS::InstallInterfaces(*sm, system);
233 Nvidia::InstallInterfaces(*sm, *nv_flinger, system); 234 Nvidia::InstallInterfaces(*sm, *nv_flinger, system);
235 OLSC::InstallInterfaces(*sm);
234 PCIe::InstallInterfaces(*sm); 236 PCIe::InstallInterfaces(*sm);
235 PCTL::InstallInterfaces(*sm); 237 PCTL::InstallInterfaces(*sm);
236 PCV::InstallInterfaces(*sm); 238 PCV::InstallInterfaces(*sm);
diff --git a/src/input_common/gcadapter/gc_poller.cpp b/src/input_common/gcadapter/gc_poller.cpp
index fe57c13a5..d95574bb5 100644
--- a/src/input_common/gcadapter/gc_poller.cpp
+++ b/src/input_common/gcadapter/gc_poller.cpp
@@ -302,8 +302,8 @@ public:
302 302
303 bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override { 303 bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override {
304 const auto mean_amplitude = (amp_low + amp_high) * 0.5f; 304 const auto mean_amplitude = (amp_low + amp_high) * 0.5f;
305 const auto processed_amplitude = static_cast<u8>( 305 const auto processed_amplitude =
306 pow(mean_amplitude, 0.5f) * (3.0f - 2.0f * pow(mean_amplitude, 0.15f)) * 0x8); 306 static_cast<u8>((mean_amplitude + std::pow(mean_amplitude, 0.3f)) * 0.5f * 0x8);
307 307
308 return gcadapter->RumblePlay(port, processed_amplitude); 308 return gcadapter->RumblePlay(port, processed_amplitude);
309 } 309 }
diff --git a/src/input_common/sdl/sdl_impl.cpp b/src/input_common/sdl/sdl_impl.cpp
index 8c48bb861..c395d96cf 100644
--- a/src/input_common/sdl/sdl_impl.cpp
+++ b/src/input_common/sdl/sdl_impl.cpp
@@ -402,8 +402,7 @@ public:
402 402
403 bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override { 403 bool SetRumblePlay(f32 amp_low, f32 freq_low, f32 amp_high, f32 freq_high) const override {
404 const auto process_amplitude = [](f32 amplitude) { 404 const auto process_amplitude = [](f32 amplitude) {
405 return static_cast<u16>(std::pow(amplitude, 0.5f) * 405 return static_cast<u16>((amplitude + std::pow(amplitude, 0.3f)) * 0.5f * 0xFFFF);
406 (3.0f - 2.0f * std::pow(amplitude, 0.15f)) * 0xFFFF);
407 }; 406 };
408 407
409 const auto processed_amp_low = process_amplitude(amp_low); 408 const auto processed_amp_low = process_amplitude(amp_low);
diff --git a/src/video_core/engines/maxwell_3d.cpp b/src/video_core/engines/maxwell_3d.cpp
index 57ebc785f..6287df633 100644
--- a/src/video_core/engines/maxwell_3d.cpp
+++ b/src/video_core/engines/maxwell_3d.cpp
@@ -124,6 +124,112 @@ void Maxwell3D::InitializeRegisterDefaults() {
124 mme_inline[MAXWELL3D_REG_INDEX(index_array.count)] = true; 124 mme_inline[MAXWELL3D_REG_INDEX(index_array.count)] = true;
125} 125}
126 126
127void Maxwell3D::ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call) {
128 if (executing_macro == 0) {
129 // A macro call must begin by writing the macro method's register, not its argument.
130 ASSERT_MSG((method % 2) == 0,
131 "Can't start macro execution by writing to the ARGS register");
132 executing_macro = method;
133 }
134
135 macro_params.insert(macro_params.end(), base_start, base_start + amount);
136
137 // Call the macro when there are no more parameters in the command buffer
138 if (is_last_call) {
139 CallMacroMethod(executing_macro, macro_params);
140 macro_params.clear();
141 }
142}
143
144u32 Maxwell3D::ProcessShadowRam(u32 method, u32 argument) {
145 // Keep track of the register value in shadow_state when requested.
146 const auto control = shadow_state.shadow_ram_control;
147 if (control == Regs::ShadowRamControl::Track ||
148 control == Regs::ShadowRamControl::TrackWithFilter) {
149 shadow_state.reg_array[method] = argument;
150 return argument;
151 }
152 if (control == Regs::ShadowRamControl::Replay) {
153 return shadow_state.reg_array[method];
154 }
155 return argument;
156}
157
158void Maxwell3D::ProcessDirtyRegisters(u32 method, u32 argument) {
159 if (regs.reg_array[method] == argument) {
160 return;
161 }
162 regs.reg_array[method] = argument;
163
164 for (const auto& table : dirty.tables) {
165 dirty.flags[table[method]] = true;
166 }
167}
168
169void Maxwell3D::ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argument,
170 bool is_last_call) {
171 switch (method) {
172 case MAXWELL3D_REG_INDEX(wait_for_idle):
173 return rasterizer->WaitForIdle();
174 case MAXWELL3D_REG_INDEX(shadow_ram_control):
175 shadow_state.shadow_ram_control = static_cast<Regs::ShadowRamControl>(nonshadow_argument);
176 return;
177 case MAXWELL3D_REG_INDEX(macros.data):
178 return macro_engine->AddCode(regs.macros.upload_address, argument);
179 case MAXWELL3D_REG_INDEX(macros.bind):
180 return ProcessMacroBind(argument);
181 case MAXWELL3D_REG_INDEX(firmware[4]):
182 return ProcessFirmwareCall4();
183 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
184 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
185 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
186 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[3]):
187 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[4]):
188 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[5]):
189 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[6]):
190 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[7]):
191 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[8]):
192 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[9]):
193 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[10]):
194 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[11]):
195 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]):
196 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]):
197 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]):
198 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]):
199 return StartCBData(method);
200 case MAXWELL3D_REG_INDEX(cb_bind[0]):
201 return ProcessCBBind(0);
202 case MAXWELL3D_REG_INDEX(cb_bind[1]):
203 return ProcessCBBind(1);
204 case MAXWELL3D_REG_INDEX(cb_bind[2]):
205 return ProcessCBBind(2);
206 case MAXWELL3D_REG_INDEX(cb_bind[3]):
207 return ProcessCBBind(3);
208 case MAXWELL3D_REG_INDEX(cb_bind[4]):
209 return ProcessCBBind(4);
210 case MAXWELL3D_REG_INDEX(draw.vertex_end_gl):
211 return DrawArrays();
212 case MAXWELL3D_REG_INDEX(clear_buffers):
213 return ProcessClearBuffers();
214 case MAXWELL3D_REG_INDEX(query.query_get):
215 return ProcessQueryGet();
216 case MAXWELL3D_REG_INDEX(condition.mode):
217 return ProcessQueryCondition();
218 case MAXWELL3D_REG_INDEX(counter_reset):
219 return ProcessCounterReset();
220 case MAXWELL3D_REG_INDEX(sync_info):
221 return ProcessSyncPoint();
222 case MAXWELL3D_REG_INDEX(exec_upload):
223 return upload_state.ProcessExec(regs.exec_upload.linear != 0);
224 case MAXWELL3D_REG_INDEX(data_upload):
225 upload_state.ProcessData(argument, is_last_call);
226 if (is_last_call) {
227 OnMemoryWrite();
228 }
229 return;
230 }
231}
232
127void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters) { 233void Maxwell3D::CallMacroMethod(u32 method, const std::vector<u32>& parameters) {
128 // Reset the current macro. 234 // Reset the current macro.
129 executing_macro = 0; 235 executing_macro = 0;
@@ -157,142 +263,16 @@ void Maxwell3D::CallMethod(u32 method, u32 method_argument, bool is_last_call) {
157 // Methods after 0xE00 are special, they're actually triggers for some microcode that was 263 // Methods after 0xE00 are special, they're actually triggers for some microcode that was
158 // uploaded to the GPU during initialization. 264 // uploaded to the GPU during initialization.
159 if (method >= MacroRegistersStart) { 265 if (method >= MacroRegistersStart) {
160 // We're trying to execute a macro 266 ProcessMacro(method, &method_argument, 1, is_last_call);
161 if (executing_macro == 0) {
162 // A macro call must begin by writing the macro method's register, not its argument.
163 ASSERT_MSG((method % 2) == 0,
164 "Can't start macro execution by writing to the ARGS register");
165 executing_macro = method;
166 }
167
168 macro_params.push_back(method_argument);
169
170 // Call the macro when there are no more parameters in the command buffer
171 if (is_last_call) {
172 CallMacroMethod(executing_macro, macro_params);
173 macro_params.clear();
174 }
175 return; 267 return;
176 } 268 }
177 269
178 ASSERT_MSG(method < Regs::NUM_REGS, 270 ASSERT_MSG(method < Regs::NUM_REGS,
179 "Invalid Maxwell3D register, increase the size of the Regs structure"); 271 "Invalid Maxwell3D register, increase the size of the Regs structure");
180 272
181 u32 arg = method_argument; 273 const u32 argument = ProcessShadowRam(method, method_argument);
182 // Keep track of the register value in shadow_state when requested. 274 ProcessDirtyRegisters(method, argument);
183 if (shadow_state.shadow_ram_control == Regs::ShadowRamControl::Track || 275 ProcessMethodCall(method, argument, method_argument, is_last_call);
184 shadow_state.shadow_ram_control == Regs::ShadowRamControl::TrackWithFilter) {
185 shadow_state.reg_array[method] = arg;
186 } else if (shadow_state.shadow_ram_control == Regs::ShadowRamControl::Replay) {
187 arg = shadow_state.reg_array[method];
188 }
189
190 if (regs.reg_array[method] != arg) {
191 regs.reg_array[method] = arg;
192
193 for (const auto& table : dirty.tables) {
194 dirty.flags[table[method]] = true;
195 }
196 }
197
198 switch (method) {
199 case MAXWELL3D_REG_INDEX(wait_for_idle): {
200 rasterizer->WaitForIdle();
201 break;
202 }
203 case MAXWELL3D_REG_INDEX(shadow_ram_control): {
204 shadow_state.shadow_ram_control = static_cast<Regs::ShadowRamControl>(method_argument);
205 break;
206 }
207 case MAXWELL3D_REG_INDEX(macros.data): {
208 macro_engine->AddCode(regs.macros.upload_address, arg);
209 break;
210 }
211 case MAXWELL3D_REG_INDEX(macros.bind): {
212 ProcessMacroBind(arg);
213 break;
214 }
215 case MAXWELL3D_REG_INDEX(firmware[4]): {
216 ProcessFirmwareCall4();
217 break;
218 }
219 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[0]):
220 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[1]):
221 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[2]):
222 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[3]):
223 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[4]):
224 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[5]):
225 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[6]):
226 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[7]):
227 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[8]):
228 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[9]):
229 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[10]):
230 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[11]):
231 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]):
232 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]):
233 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]):
234 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): {
235 StartCBData(method);
236 break;
237 }
238 case MAXWELL3D_REG_INDEX(cb_bind[0]): {
239 ProcessCBBind(0);
240 break;
241 }
242 case MAXWELL3D_REG_INDEX(cb_bind[1]): {
243 ProcessCBBind(1);
244 break;
245 }
246 case MAXWELL3D_REG_INDEX(cb_bind[2]): {
247 ProcessCBBind(2);
248 break;
249 }
250 case MAXWELL3D_REG_INDEX(cb_bind[3]): {
251 ProcessCBBind(3);
252 break;
253 }
254 case MAXWELL3D_REG_INDEX(cb_bind[4]): {
255 ProcessCBBind(4);
256 break;
257 }
258 case MAXWELL3D_REG_INDEX(draw.vertex_end_gl): {
259 DrawArrays();
260 break;
261 }
262 case MAXWELL3D_REG_INDEX(clear_buffers): {
263 ProcessClearBuffers();
264 break;
265 }
266 case MAXWELL3D_REG_INDEX(query.query_get): {
267 ProcessQueryGet();
268 break;
269 }
270 case MAXWELL3D_REG_INDEX(condition.mode): {
271 ProcessQueryCondition();
272 break;
273 }
274 case MAXWELL3D_REG_INDEX(counter_reset): {
275 ProcessCounterReset();
276 break;
277 }
278 case MAXWELL3D_REG_INDEX(sync_info): {
279 ProcessSyncPoint();
280 break;
281 }
282 case MAXWELL3D_REG_INDEX(exec_upload): {
283 upload_state.ProcessExec(regs.exec_upload.linear != 0);
284 break;
285 }
286 case MAXWELL3D_REG_INDEX(data_upload): {
287 upload_state.ProcessData(arg, is_last_call);
288 if (is_last_call) {
289 OnMemoryWrite();
290 }
291 break;
292 }
293 default:
294 break;
295 }
296} 276}
297 277
298void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount, 278void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
@@ -300,23 +280,7 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
300 // Methods after 0xE00 are special, they're actually triggers for some microcode that was 280 // Methods after 0xE00 are special, they're actually triggers for some microcode that was
301 // uploaded to the GPU during initialization. 281 // uploaded to the GPU during initialization.
302 if (method >= MacroRegistersStart) { 282 if (method >= MacroRegistersStart) {
303 // We're trying to execute a macro 283 ProcessMacro(method, base_start, amount, amount == methods_pending);
304 if (executing_macro == 0) {
305 // A macro call must begin by writing the macro method's register, not its argument.
306 ASSERT_MSG((method % 2) == 0,
307 "Can't start macro execution by writing to the ARGS register");
308 executing_macro = method;
309 }
310
311 for (std::size_t i = 0; i < amount; i++) {
312 macro_params.push_back(base_start[i]);
313 }
314
315 // Call the macro when there are no more parameters in the command buffer
316 if (amount == methods_pending) {
317 CallMacroMethod(executing_macro, macro_params);
318 macro_params.clear();
319 }
320 return; 284 return;
321 } 285 }
322 switch (method) { 286 switch (method) {
@@ -335,15 +299,14 @@ void Maxwell3D::CallMultiMethod(u32 method, const u32* base_start, u32 amount,
335 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]): 299 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[12]):
336 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]): 300 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[13]):
337 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]): 301 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[14]):
338 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]): { 302 case MAXWELL3D_REG_INDEX(const_buffer.cb_data[15]):
339 ProcessCBMultiData(method, base_start, amount); 303 ProcessCBMultiData(method, base_start, amount);
340 break; 304 break;
341 } 305 default:
342 default: {
343 for (std::size_t i = 0; i < amount; i++) { 306 for (std::size_t i = 0; i < amount; i++) {
344 CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1); 307 CallMethod(method, base_start[i], methods_pending - static_cast<u32>(i) <= 1);
345 } 308 }
346 } 309 break;
347 } 310 }
348} 311}
349 312
diff --git a/src/video_core/engines/maxwell_3d.h b/src/video_core/engines/maxwell_3d.h
index bc289c55d..1cbe8fe67 100644
--- a/src/video_core/engines/maxwell_3d.h
+++ b/src/video_core/engines/maxwell_3d.h
@@ -1461,6 +1461,14 @@ public:
1461private: 1461private:
1462 void InitializeRegisterDefaults(); 1462 void InitializeRegisterDefaults();
1463 1463
1464 void ProcessMacro(u32 method, const u32* base_start, u32 amount, bool is_last_call);
1465
1466 u32 ProcessShadowRam(u32 method, u32 argument);
1467
1468 void ProcessDirtyRegisters(u32 method, u32 argument);
1469
1470 void ProcessMethodCall(u32 method, u32 argument, u32 nonshadow_argument, bool is_last_call);
1471
1464 Core::System& system; 1472 Core::System& system;
1465 MemoryManager& memory_manager; 1473 MemoryManager& memory_manager;
1466 1474
diff --git a/src/video_core/engines/shader_bytecode.h b/src/video_core/engines/shader_bytecode.h
index a3c05d1b0..37d17efdc 100644
--- a/src/video_core/engines/shader_bytecode.h
+++ b/src/video_core/engines/shader_bytecode.h
@@ -32,31 +32,31 @@ struct Register {
32 32
33 constexpr Register() = default; 33 constexpr Register() = default;
34 34
35 constexpr Register(u64 value) : value(value) {} 35 constexpr Register(u64 value_) : value(value_) {}
36 36
37 constexpr operator u64() const { 37 [[nodiscard]] constexpr operator u64() const {
38 return value; 38 return value;
39 } 39 }
40 40
41 template <typename T> 41 template <typename T>
42 constexpr u64 operator-(const T& oth) const { 42 [[nodiscard]] constexpr u64 operator-(const T& oth) const {
43 return value - oth; 43 return value - oth;
44 } 44 }
45 45
46 template <typename T> 46 template <typename T>
47 constexpr u64 operator&(const T& oth) const { 47 [[nodiscard]] constexpr u64 operator&(const T& oth) const {
48 return value & oth; 48 return value & oth;
49 } 49 }
50 50
51 constexpr u64 operator&(const Register& oth) const { 51 [[nodiscard]] constexpr u64 operator&(const Register& oth) const {
52 return value & oth.value; 52 return value & oth.value;
53 } 53 }
54 54
55 constexpr u64 operator~() const { 55 [[nodiscard]] constexpr u64 operator~() const {
56 return ~value; 56 return ~value;
57 } 57 }
58 58
59 u64 GetSwizzledIndex(u64 elem) const { 59 [[nodiscard]] u64 GetSwizzledIndex(u64 elem) const {
60 elem = (value + elem) & 3; 60 elem = (value + elem) & 3;
61 return (value & ~3) + elem; 61 return (value & ~3) + elem;
62 } 62 }
@@ -75,7 +75,7 @@ enum class AttributeSize : u64 {
75union Attribute { 75union Attribute {
76 Attribute() = default; 76 Attribute() = default;
77 77
78 constexpr explicit Attribute(u64 value) : value(value) {} 78 constexpr explicit Attribute(u64 value_) : value(value_) {}
79 79
80 enum class Index : u64 { 80 enum class Index : u64 {
81 LayerViewportPointSize = 6, 81 LayerViewportPointSize = 6,
@@ -107,7 +107,7 @@ union Attribute {
107 BitField<31, 1, u64> patch; 107 BitField<31, 1, u64> patch;
108 BitField<47, 3, AttributeSize> size; 108 BitField<47, 3, AttributeSize> size;
109 109
110 bool IsPhysical() const { 110 [[nodiscard]] bool IsPhysical() const {
111 return patch == 0 && element == 0 && static_cast<u64>(index.Value()) == 0; 111 return patch == 0 && element == 0 && static_cast<u64>(index.Value()) == 0;
112 } 112 }
113 } fmt20; 113 } fmt20;
@@ -124,7 +124,7 @@ union Attribute {
124union Sampler { 124union Sampler {
125 Sampler() = default; 125 Sampler() = default;
126 126
127 constexpr explicit Sampler(u64 value) : value(value) {} 127 constexpr explicit Sampler(u64 value_) : value(value_) {}
128 128
129 enum class Index : u64 { 129 enum class Index : u64 {
130 Sampler_0 = 8, 130 Sampler_0 = 8,
@@ -137,7 +137,7 @@ union Sampler {
137union Image { 137union Image {
138 Image() = default; 138 Image() = default;
139 139
140 constexpr explicit Image(u64 value) : value{value} {} 140 constexpr explicit Image(u64 value_) : value{value_} {}
141 141
142 BitField<36, 13, u64> index; 142 BitField<36, 13, u64> index;
143 u64 value; 143 u64 value;
@@ -505,14 +505,14 @@ struct IpaMode {
505 IpaInterpMode interpolation_mode; 505 IpaInterpMode interpolation_mode;
506 IpaSampleMode sampling_mode; 506 IpaSampleMode sampling_mode;
507 507
508 bool operator==(const IpaMode& a) const { 508 [[nodiscard]] bool operator==(const IpaMode& a) const {
509 return std::tie(interpolation_mode, sampling_mode) == 509 return std::tie(interpolation_mode, sampling_mode) ==
510 std::tie(a.interpolation_mode, a.sampling_mode); 510 std::tie(a.interpolation_mode, a.sampling_mode);
511 } 511 }
512 bool operator!=(const IpaMode& a) const { 512 [[nodiscard]] bool operator!=(const IpaMode& a) const {
513 return !operator==(a); 513 return !operator==(a);
514 } 514 }
515 bool operator<(const IpaMode& a) const { 515 [[nodiscard]] bool operator<(const IpaMode& a) const {
516 return std::tie(interpolation_mode, sampling_mode) < 516 return std::tie(interpolation_mode, sampling_mode) <
517 std::tie(a.interpolation_mode, a.sampling_mode); 517 std::tie(a.interpolation_mode, a.sampling_mode);
518 } 518 }
@@ -658,10 +658,10 @@ union Instruction {
658 return *this; 658 return *this;
659 } 659 }
660 660
661 constexpr Instruction(u64 value) : value{value} {} 661 constexpr Instruction(u64 value_) : value{value_} {}
662 constexpr Instruction(const Instruction& instr) : value(instr.value) {} 662 constexpr Instruction(const Instruction& instr) : value(instr.value) {}
663 663
664 constexpr bool Bit(u64 offset) const { 664 [[nodiscard]] constexpr bool Bit(u64 offset) const {
665 return ((value >> offset) & 1) != 0; 665 return ((value >> offset) & 1) != 0;
666 } 666 }
667 667
@@ -746,34 +746,34 @@ union Instruction {
746 BitField<28, 8, u64> imm_lut28; 746 BitField<28, 8, u64> imm_lut28;
747 BitField<48, 8, u64> imm_lut48; 747 BitField<48, 8, u64> imm_lut48;
748 748
749 u32 GetImmLut28() const { 749 [[nodiscard]] u32 GetImmLut28() const {
750 return static_cast<u32>(imm_lut28); 750 return static_cast<u32>(imm_lut28);
751 } 751 }
752 752
753 u32 GetImmLut48() const { 753 [[nodiscard]] u32 GetImmLut48() const {
754 return static_cast<u32>(imm_lut48); 754 return static_cast<u32>(imm_lut48);
755 } 755 }
756 } lop3; 756 } lop3;
757 757
758 u16 GetImm20_16() const { 758 [[nodiscard]] u16 GetImm20_16() const {
759 return static_cast<u16>(imm20_16); 759 return static_cast<u16>(imm20_16);
760 } 760 }
761 761
762 u32 GetImm20_19() const { 762 [[nodiscard]] u32 GetImm20_19() const {
763 u32 imm{static_cast<u32>(imm20_19)}; 763 u32 imm{static_cast<u32>(imm20_19)};
764 imm <<= 12; 764 imm <<= 12;
765 imm |= negate_imm ? 0x80000000 : 0; 765 imm |= negate_imm ? 0x80000000 : 0;
766 return imm; 766 return imm;
767 } 767 }
768 768
769 u32 GetImm20_32() const { 769 [[nodiscard]] u32 GetImm20_32() const {
770 return static_cast<u32>(imm20_32); 770 return static_cast<u32>(imm20_32);
771 } 771 }
772 772
773 s32 GetSignedImm20_20() const { 773 [[nodiscard]] s32 GetSignedImm20_20() const {
774 u32 immediate = static_cast<u32>(imm20_19 | (negate_imm << 19)); 774 const auto immediate = static_cast<u32>(imm20_19 | (negate_imm << 19));
775 // Sign extend the 20-bit value. 775 // Sign extend the 20-bit value.
776 u32 mask = 1U << (20 - 1); 776 const auto mask = 1U << (20 - 1);
777 return static_cast<s32>((immediate ^ mask) - mask); 777 return static_cast<s32>((immediate ^ mask) - mask);
778 } 778 }
779 } alu; 779 } alu;
@@ -857,7 +857,7 @@ union Instruction {
857 BitField<56, 1, u64> second_negate; 857 BitField<56, 1, u64> second_negate;
858 BitField<30, 9, u64> second; 858 BitField<30, 9, u64> second;
859 859
860 u32 PackImmediates() const { 860 [[nodiscard]] u32 PackImmediates() const {
861 // Immediates are half floats shifted. 861 // Immediates are half floats shifted.
862 constexpr u32 imm_shift = 6; 862 constexpr u32 imm_shift = 6;
863 return static_cast<u32>((first << imm_shift) | (second << (16 + imm_shift))); 863 return static_cast<u32>((first << imm_shift) | (second << (16 + imm_shift)));
@@ -1033,7 +1033,7 @@ union Instruction {
1033 BitField<28, 2, AtomicType> type; 1033 BitField<28, 2, AtomicType> type;
1034 BitField<30, 22, s64> offset; 1034 BitField<30, 22, s64> offset;
1035 1035
1036 s32 GetImmediateOffset() const { 1036 [[nodiscard]] s32 GetImmediateOffset() const {
1037 return static_cast<s32>(offset << 2); 1037 return static_cast<s32>(offset << 2);
1038 } 1038 }
1039 } atoms; 1039 } atoms;
@@ -1215,7 +1215,7 @@ union Instruction {
1215 BitField<39, 4, u64> rounding; 1215 BitField<39, 4, u64> rounding;
1216 // H0, H1 extract for F16 missing 1216 // H0, H1 extract for F16 missing
1217 BitField<41, 1, u64> selector; // Guessed as some games set it, TODO: reverse this value 1217 BitField<41, 1, u64> selector; // Guessed as some games set it, TODO: reverse this value
1218 F2fRoundingOp GetRoundingMode() const { 1218 [[nodiscard]] F2fRoundingOp GetRoundingMode() const {
1219 constexpr u64 rounding_mask = 0x0B; 1219 constexpr u64 rounding_mask = 0x0B;
1220 return static_cast<F2fRoundingOp>(rounding.Value() & rounding_mask); 1220 return static_cast<F2fRoundingOp>(rounding.Value() & rounding_mask);
1221 } 1221 }
@@ -1239,15 +1239,15 @@ union Instruction {
1239 BitField<54, 1, u64> aoffi_flag; 1239 BitField<54, 1, u64> aoffi_flag;
1240 BitField<55, 3, TextureProcessMode> process_mode; 1240 BitField<55, 3, TextureProcessMode> process_mode;
1241 1241
1242 bool IsComponentEnabled(std::size_t component) const { 1242 [[nodiscard]] bool IsComponentEnabled(std::size_t component) const {
1243 return ((1ull << component) & component_mask) != 0; 1243 return ((1ULL << component) & component_mask) != 0;
1244 } 1244 }
1245 1245
1246 TextureProcessMode GetTextureProcessMode() const { 1246 [[nodiscard]] TextureProcessMode GetTextureProcessMode() const {
1247 return process_mode; 1247 return process_mode;
1248 } 1248 }
1249 1249
1250 bool UsesMiscMode(TextureMiscMode mode) const { 1250 [[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
1251 switch (mode) { 1251 switch (mode) {
1252 case TextureMiscMode::DC: 1252 case TextureMiscMode::DC:
1253 return dc_flag != 0; 1253 return dc_flag != 0;
@@ -1271,15 +1271,15 @@ union Instruction {
1271 BitField<36, 1, u64> aoffi_flag; 1271 BitField<36, 1, u64> aoffi_flag;
1272 BitField<37, 3, TextureProcessMode> process_mode; 1272 BitField<37, 3, TextureProcessMode> process_mode;
1273 1273
1274 bool IsComponentEnabled(std::size_t component) const { 1274 [[nodiscard]] bool IsComponentEnabled(std::size_t component) const {
1275 return ((1ULL << component) & component_mask) != 0; 1275 return ((1ULL << component) & component_mask) != 0;
1276 } 1276 }
1277 1277
1278 TextureProcessMode GetTextureProcessMode() const { 1278 [[nodiscard]] TextureProcessMode GetTextureProcessMode() const {
1279 return process_mode; 1279 return process_mode;
1280 } 1280 }
1281 1281
1282 bool UsesMiscMode(TextureMiscMode mode) const { 1282 [[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
1283 switch (mode) { 1283 switch (mode) {
1284 case TextureMiscMode::DC: 1284 case TextureMiscMode::DC:
1285 return dc_flag != 0; 1285 return dc_flag != 0;
@@ -1299,7 +1299,7 @@ union Instruction {
1299 BitField<31, 4, u64> component_mask; 1299 BitField<31, 4, u64> component_mask;
1300 BitField<49, 1, u64> nodep_flag; 1300 BitField<49, 1, u64> nodep_flag;
1301 1301
1302 bool UsesMiscMode(TextureMiscMode mode) const { 1302 [[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
1303 switch (mode) { 1303 switch (mode) {
1304 case TextureMiscMode::NODEP: 1304 case TextureMiscMode::NODEP:
1305 return nodep_flag != 0; 1305 return nodep_flag != 0;
@@ -1309,7 +1309,7 @@ union Instruction {
1309 return false; 1309 return false;
1310 } 1310 }
1311 1311
1312 bool IsComponentEnabled(std::size_t component) const { 1312 [[nodiscard]] bool IsComponentEnabled(std::size_t component) const {
1313 return ((1ULL << component) & component_mask) != 0; 1313 return ((1ULL << component) & component_mask) != 0;
1314 } 1314 }
1315 } txq; 1315 } txq;
@@ -1321,11 +1321,11 @@ union Instruction {
1321 BitField<35, 1, u64> ndv_flag; 1321 BitField<35, 1, u64> ndv_flag;
1322 BitField<49, 1, u64> nodep_flag; 1322 BitField<49, 1, u64> nodep_flag;
1323 1323
1324 bool IsComponentEnabled(std::size_t component) const { 1324 [[nodiscard]] bool IsComponentEnabled(std::size_t component) const {
1325 return ((1ull << component) & component_mask) != 0; 1325 return ((1ULL << component) & component_mask) != 0;
1326 } 1326 }
1327 1327
1328 bool UsesMiscMode(TextureMiscMode mode) const { 1328 [[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
1329 switch (mode) { 1329 switch (mode) {
1330 case TextureMiscMode::NDV: 1330 case TextureMiscMode::NDV:
1331 return (ndv_flag != 0); 1331 return (ndv_flag != 0);
@@ -1347,7 +1347,7 @@ union Instruction {
1347 BitField<54, 2, u64> offset_mode; 1347 BitField<54, 2, u64> offset_mode;
1348 BitField<56, 2, u64> component; 1348 BitField<56, 2, u64> component;
1349 1349
1350 bool UsesMiscMode(TextureMiscMode mode) const { 1350 [[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
1351 switch (mode) { 1351 switch (mode) {
1352 case TextureMiscMode::NDV: 1352 case TextureMiscMode::NDV:
1353 return ndv_flag != 0; 1353 return ndv_flag != 0;
@@ -1373,7 +1373,7 @@ union Instruction {
1373 BitField<33, 2, u64> offset_mode; 1373 BitField<33, 2, u64> offset_mode;
1374 BitField<37, 2, u64> component; 1374 BitField<37, 2, u64> component;
1375 1375
1376 bool UsesMiscMode(TextureMiscMode mode) const { 1376 [[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
1377 switch (mode) { 1377 switch (mode) {
1378 case TextureMiscMode::NDV: 1378 case TextureMiscMode::NDV:
1379 return ndv_flag != 0; 1379 return ndv_flag != 0;
@@ -1399,7 +1399,7 @@ union Instruction {
1399 BitField<52, 2, u64> component; 1399 BitField<52, 2, u64> component;
1400 BitField<55, 1, u64> fp16_flag; 1400 BitField<55, 1, u64> fp16_flag;
1401 1401
1402 bool UsesMiscMode(TextureMiscMode mode) const { 1402 [[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
1403 switch (mode) { 1403 switch (mode) {
1404 case TextureMiscMode::DC: 1404 case TextureMiscMode::DC:
1405 return dc_flag != 0; 1405 return dc_flag != 0;
@@ -1422,16 +1422,20 @@ union Instruction {
1422 BitField<53, 4, u64> texture_info; 1422 BitField<53, 4, u64> texture_info;
1423 BitField<59, 1, u64> fp32_flag; 1423 BitField<59, 1, u64> fp32_flag;
1424 1424
1425 TextureType GetTextureType() const { 1425 [[nodiscard]] TextureType GetTextureType() const {
1426 // The TEXS instruction has a weird encoding for the texture type. 1426 // The TEXS instruction has a weird encoding for the texture type.
1427 if (texture_info == 0) 1427 if (texture_info == 0) {
1428 return TextureType::Texture1D; 1428 return TextureType::Texture1D;
1429 if (texture_info >= 1 && texture_info <= 9) 1429 }
1430 if (texture_info >= 1 && texture_info <= 9) {
1430 return TextureType::Texture2D; 1431 return TextureType::Texture2D;
1431 if (texture_info >= 10 && texture_info <= 11) 1432 }
1433 if (texture_info >= 10 && texture_info <= 11) {
1432 return TextureType::Texture3D; 1434 return TextureType::Texture3D;
1433 if (texture_info >= 12 && texture_info <= 13) 1435 }
1436 if (texture_info >= 12 && texture_info <= 13) {
1434 return TextureType::TextureCube; 1437 return TextureType::TextureCube;
1438 }
1435 1439
1436 LOG_CRITICAL(HW_GPU, "Unhandled texture_info: {}", 1440 LOG_CRITICAL(HW_GPU, "Unhandled texture_info: {}",
1437 static_cast<u32>(texture_info.Value())); 1441 static_cast<u32>(texture_info.Value()));
@@ -1439,7 +1443,7 @@ union Instruction {
1439 return TextureType::Texture1D; 1443 return TextureType::Texture1D;
1440 } 1444 }
1441 1445
1442 TextureProcessMode GetTextureProcessMode() const { 1446 [[nodiscard]] TextureProcessMode GetTextureProcessMode() const {
1443 switch (texture_info) { 1447 switch (texture_info) {
1444 case 0: 1448 case 0:
1445 case 2: 1449 case 2:
@@ -1458,7 +1462,7 @@ union Instruction {
1458 return TextureProcessMode::None; 1462 return TextureProcessMode::None;
1459 } 1463 }
1460 1464
1461 bool UsesMiscMode(TextureMiscMode mode) const { 1465 [[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
1462 switch (mode) { 1466 switch (mode) {
1463 case TextureMiscMode::DC: 1467 case TextureMiscMode::DC:
1464 return (texture_info >= 4 && texture_info <= 6) || texture_info == 9; 1468 return (texture_info >= 4 && texture_info <= 6) || texture_info == 9;
@@ -1470,16 +1474,16 @@ union Instruction {
1470 return false; 1474 return false;
1471 } 1475 }
1472 1476
1473 bool IsArrayTexture() const { 1477 [[nodiscard]] bool IsArrayTexture() const {
1474 // TEXS only supports Texture2D arrays. 1478 // TEXS only supports Texture2D arrays.
1475 return texture_info >= 7 && texture_info <= 9; 1479 return texture_info >= 7 && texture_info <= 9;
1476 } 1480 }
1477 1481
1478 bool HasTwoDestinations() const { 1482 [[nodiscard]] bool HasTwoDestinations() const {
1479 return gpr28.Value() != Register::ZeroIndex; 1483 return gpr28.Value() != Register::ZeroIndex;
1480 } 1484 }
1481 1485
1482 bool IsComponentEnabled(std::size_t component) const { 1486 [[nodiscard]] bool IsComponentEnabled(std::size_t component) const {
1483 static constexpr std::array<std::array<u32, 8>, 4> mask_lut{{ 1487 static constexpr std::array<std::array<u32, 8>, 4> mask_lut{{
1484 {}, 1488 {},
1485 {0x1, 0x2, 0x4, 0x8, 0x3, 0x9, 0xa, 0xc}, 1489 {0x1, 0x2, 0x4, 0x8, 0x3, 0x9, 0xa, 0xc},
@@ -1506,7 +1510,7 @@ union Instruction {
1506 BitField<54, 1, u64> cl; 1510 BitField<54, 1, u64> cl;
1507 BitField<55, 1, u64> process_mode; 1511 BitField<55, 1, u64> process_mode;
1508 1512
1509 TextureProcessMode GetTextureProcessMode() const { 1513 [[nodiscard]] TextureProcessMode GetTextureProcessMode() const {
1510 return process_mode == 0 ? TextureProcessMode::LZ : TextureProcessMode::LL; 1514 return process_mode == 0 ? TextureProcessMode::LZ : TextureProcessMode::LL;
1511 } 1515 }
1512 } tld; 1516 } tld;
@@ -1516,7 +1520,7 @@ union Instruction {
1516 BitField<53, 4, u64> texture_info; 1520 BitField<53, 4, u64> texture_info;
1517 BitField<59, 1, u64> fp32_flag; 1521 BitField<59, 1, u64> fp32_flag;
1518 1522
1519 TextureType GetTextureType() const { 1523 [[nodiscard]] TextureType GetTextureType() const {
1520 // The TLDS instruction has a weird encoding for the texture type. 1524 // The TLDS instruction has a weird encoding for the texture type.
1521 if (texture_info <= 1) { 1525 if (texture_info <= 1) {
1522 return TextureType::Texture1D; 1526 return TextureType::Texture1D;
@@ -1535,13 +1539,14 @@ union Instruction {
1535 return TextureType::Texture1D; 1539 return TextureType::Texture1D;
1536 } 1540 }
1537 1541
1538 TextureProcessMode GetTextureProcessMode() const { 1542 [[nodiscard]] TextureProcessMode GetTextureProcessMode() const {
1539 if (texture_info == 1 || texture_info == 5 || texture_info == 12) 1543 if (texture_info == 1 || texture_info == 5 || texture_info == 12) {
1540 return TextureProcessMode::LL; 1544 return TextureProcessMode::LL;
1545 }
1541 return TextureProcessMode::LZ; 1546 return TextureProcessMode::LZ;
1542 } 1547 }
1543 1548
1544 bool UsesMiscMode(TextureMiscMode mode) const { 1549 [[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
1545 switch (mode) { 1550 switch (mode) {
1546 case TextureMiscMode::AOFFI: 1551 case TextureMiscMode::AOFFI:
1547 return texture_info == 12 || texture_info == 4; 1552 return texture_info == 12 || texture_info == 4;
@@ -1555,7 +1560,7 @@ union Instruction {
1555 return false; 1560 return false;
1556 } 1561 }
1557 1562
1558 bool IsArrayTexture() const { 1563 [[nodiscard]] bool IsArrayTexture() const {
1559 // TEXS only supports Texture2D arrays. 1564 // TEXS only supports Texture2D arrays.
1560 return texture_info == 8; 1565 return texture_info == 8;
1561 } 1566 }
@@ -1567,7 +1572,7 @@ union Instruction {
1567 BitField<35, 1, u64> aoffi_flag; 1572 BitField<35, 1, u64> aoffi_flag;
1568 BitField<49, 1, u64> nodep_flag; 1573 BitField<49, 1, u64> nodep_flag;
1569 1574
1570 bool UsesMiscMode(TextureMiscMode mode) const { 1575 [[nodiscard]] bool UsesMiscMode(TextureMiscMode mode) const {
1571 switch (mode) { 1576 switch (mode) {
1572 case TextureMiscMode::AOFFI: 1577 case TextureMiscMode::AOFFI:
1573 return aoffi_flag != 0; 1578 return aoffi_flag != 0;
@@ -1591,7 +1596,7 @@ union Instruction {
1591 BitField<20, 3, StoreType> store_data_layout; 1596 BitField<20, 3, StoreType> store_data_layout;
1592 BitField<20, 4, u64> component_mask_selector; 1597 BitField<20, 4, u64> component_mask_selector;
1593 1598
1594 bool IsComponentEnabled(std::size_t component) const { 1599 [[nodiscard]] bool IsComponentEnabled(std::size_t component) const {
1595 ASSERT(mode == SurfaceDataMode::P); 1600 ASSERT(mode == SurfaceDataMode::P);
1596 constexpr u8 R = 0b0001; 1601 constexpr u8 R = 0b0001;
1597 constexpr u8 G = 0b0010; 1602 constexpr u8 G = 0b0010;
@@ -1604,7 +1609,7 @@ union Instruction {
1604 return std::bitset<4>{mask.at(component_mask_selector)}.test(component); 1609 return std::bitset<4>{mask.at(component_mask_selector)}.test(component);
1605 } 1610 }
1606 1611
1607 StoreType GetStoreDataLayout() const { 1612 [[nodiscard]] StoreType GetStoreDataLayout() const {
1608 ASSERT(mode == SurfaceDataMode::D_BA); 1613 ASSERT(mode == SurfaceDataMode::D_BA);
1609 return store_data_layout; 1614 return store_data_layout;
1610 } 1615 }
@@ -1622,14 +1627,15 @@ union Instruction {
1622 BitField<20, 24, u64> target; 1627 BitField<20, 24, u64> target;
1623 BitField<5, 1, u64> constant_buffer; 1628 BitField<5, 1, u64> constant_buffer;
1624 1629
1625 s32 GetBranchTarget() const { 1630 [[nodiscard]] s32 GetBranchTarget() const {
1626 // Sign extend the branch target offset 1631 // Sign extend the branch target offset
1627 u32 mask = 1U << (24 - 1); 1632 const auto mask = 1U << (24 - 1);
1628 u32 value = static_cast<u32>(target); 1633 const auto target_value = static_cast<u32>(target);
1634 constexpr auto instruction_size = static_cast<s32>(sizeof(Instruction));
1635
1629 // The branch offset is relative to the next instruction and is stored in bytes, so 1636 // The branch offset is relative to the next instruction and is stored in bytes, so
1630 // divide it by the size of an instruction and add 1 to it. 1637 // divide it by the size of an instruction and add 1 to it.
1631 return static_cast<s32>((value ^ mask) - mask) / static_cast<s32>(sizeof(Instruction)) + 1638 return static_cast<s32>((target_value ^ mask) - mask) / instruction_size + 1;
1632 1;
1633 } 1639 }
1634 } bra; 1640 } bra;
1635 1641
@@ -1637,14 +1643,15 @@ union Instruction {
1637 BitField<20, 24, u64> target; 1643 BitField<20, 24, u64> target;
1638 BitField<5, 1, u64> constant_buffer; 1644 BitField<5, 1, u64> constant_buffer;
1639 1645
1640 s32 GetBranchExtend() const { 1646 [[nodiscard]] s32 GetBranchExtend() const {
1641 // Sign extend the branch target offset 1647 // Sign extend the branch target offset
1642 u32 mask = 1U << (24 - 1); 1648 const auto mask = 1U << (24 - 1);
1643 u32 value = static_cast<u32>(target); 1649 const auto target_value = static_cast<u32>(target);
1650 constexpr auto instruction_size = static_cast<s32>(sizeof(Instruction));
1651
1644 // The branch offset is relative to the next instruction and is stored in bytes, so 1652 // The branch offset is relative to the next instruction and is stored in bytes, so
1645 // divide it by the size of an instruction and add 1 to it. 1653 // divide it by the size of an instruction and add 1 to it.
1646 return static_cast<s32>((value ^ mask) - mask) / static_cast<s32>(sizeof(Instruction)) + 1654 return static_cast<s32>((target_value ^ mask) - mask) / instruction_size + 1;
1647 1;
1648 } 1655 }
1649 } brx; 1656 } brx;
1650 1657
@@ -1697,7 +1704,7 @@ union Instruction {
1697 BitField<50, 1, u64> is_op_b_register; 1704 BitField<50, 1, u64> is_op_b_register;
1698 BitField<51, 3, VmnmxOperation> operation; 1705 BitField<51, 3, VmnmxOperation> operation;
1699 1706
1700 VmnmxType SourceFormatA() const { 1707 [[nodiscard]] VmnmxType SourceFormatA() const {
1701 switch (src_format_a) { 1708 switch (src_format_a) {
1702 case 0b11: 1709 case 0b11:
1703 return VmnmxType::Bits32; 1710 return VmnmxType::Bits32;
@@ -1708,7 +1715,7 @@ union Instruction {
1708 } 1715 }
1709 } 1716 }
1710 1717
1711 VmnmxType SourceFormatB() const { 1718 [[nodiscard]] VmnmxType SourceFormatB() const {
1712 switch (src_format_b) { 1719 switch (src_format_b) {
1713 case 0b11: 1720 case 0b11:
1714 return VmnmxType::Bits32; 1721 return VmnmxType::Bits32;
@@ -1739,7 +1746,7 @@ union Instruction {
1739 BitField<20, 14, u64> shifted_offset; 1746 BitField<20, 14, u64> shifted_offset;
1740 BitField<34, 5, u64> index; 1747 BitField<34, 5, u64> index;
1741 1748
1742 u64 GetOffset() const { 1749 [[nodiscard]] u64 GetOffset() const {
1743 return shifted_offset * 4; 1750 return shifted_offset * 4;
1744 } 1751 }
1745 } cbuf34; 1752 } cbuf34;
@@ -1748,7 +1755,7 @@ union Instruction {
1748 BitField<20, 16, s64> offset; 1755 BitField<20, 16, s64> offset;
1749 BitField<36, 5, u64> index; 1756 BitField<36, 5, u64> index;
1750 1757
1751 s64 GetOffset() const { 1758 [[nodiscard]] s64 GetOffset() const {
1752 return offset; 1759 return offset;
1753 } 1760 }
1754 } cbuf36; 1761 } cbuf36;
@@ -1997,29 +2004,29 @@ public:
1997 2004
1998 /// Returns whether an opcode has an execution predicate field or not (ie, whether it can be 2005 /// Returns whether an opcode has an execution predicate field or not (ie, whether it can be
1999 /// conditionally executed). 2006 /// conditionally executed).
2000 static bool IsPredicatedInstruction(Id opcode) { 2007 [[nodiscard]] static bool IsPredicatedInstruction(Id opcode) {
2001 // TODO(Subv): Add the rest of unpredicated instructions. 2008 // TODO(Subv): Add the rest of unpredicated instructions.
2002 return opcode != Id::SSY && opcode != Id::PBK; 2009 return opcode != Id::SSY && opcode != Id::PBK;
2003 } 2010 }
2004 2011
2005 class Matcher { 2012 class Matcher {
2006 public: 2013 public:
2007 constexpr Matcher(const char* const name, u16 mask, u16 expected, Id id, Type type) 2014 constexpr Matcher(const char* const name_, u16 mask_, u16 expected_, Id id_, Type type_)
2008 : name{name}, mask{mask}, expected{expected}, id{id}, type{type} {} 2015 : name{name_}, mask{mask_}, expected{expected_}, id{id_}, type{type_} {}
2009 2016
2010 constexpr const char* GetName() const { 2017 [[nodiscard]] constexpr const char* GetName() const {
2011 return name; 2018 return name;
2012 } 2019 }
2013 2020
2014 constexpr u16 GetMask() const { 2021 [[nodiscard]] constexpr u16 GetMask() const {
2015 return mask; 2022 return mask;
2016 } 2023 }
2017 2024
2018 constexpr Id GetId() const { 2025 [[nodiscard]] constexpr Id GetId() const {
2019 return id; 2026 return id;
2020 } 2027 }
2021 2028
2022 constexpr Type GetType() const { 2029 [[nodiscard]] constexpr Type GetType() const {
2023 return type; 2030 return type;
2024 } 2031 }
2025 2032
@@ -2028,7 +2035,7 @@ public:
2028 * @param instruction The instruction to test 2035 * @param instruction The instruction to test
2029 * @returns true if the given instruction matches. 2036 * @returns true if the given instruction matches.
2030 */ 2037 */
2031 constexpr bool Matches(u16 instruction) const { 2038 [[nodiscard]] constexpr bool Matches(u16 instruction) const {
2032 return (instruction & mask) == expected; 2039 return (instruction & mask) == expected;
2033 } 2040 }
2034 2041
@@ -2040,7 +2047,8 @@ public:
2040 Type type; 2047 Type type;
2041 }; 2048 };
2042 2049
2043 static std::optional<std::reference_wrapper<const Matcher>> Decode(Instruction instr) { 2050 using DecodeResult = std::optional<std::reference_wrapper<const Matcher>>;
2051 [[nodiscard]] static DecodeResult Decode(Instruction instr) {
2044 static const auto table{GetDecodeTable()}; 2052 static const auto table{GetDecodeTable()};
2045 2053
2046 const auto matches_instruction = [instr](const auto& matcher) { 2054 const auto matches_instruction = [instr](const auto& matcher) {
@@ -2062,7 +2070,7 @@ private:
2062 * A '0' in a bitstring indicates that a zero must be present at that bit position. 2070 * A '0' in a bitstring indicates that a zero must be present at that bit position.
2063 * A '1' in a bitstring indicates that a one must be present at that bit position. 2071 * A '1' in a bitstring indicates that a one must be present at that bit position.
2064 */ 2072 */
2065 static constexpr auto GetMaskAndExpect(const char* const bitstring) { 2073 [[nodiscard]] static constexpr auto GetMaskAndExpect(const char* const bitstring) {
2066 u16 mask = 0, expect = 0; 2074 u16 mask = 0, expect = 0;
2067 for (std::size_t i = 0; i < opcode_bitsize; i++) { 2075 for (std::size_t i = 0; i < opcode_bitsize; i++) {
2068 const std::size_t bit_position = opcode_bitsize - i - 1; 2076 const std::size_t bit_position = opcode_bitsize - i - 1;
@@ -2084,14 +2092,14 @@ private:
2084 2092
2085 public: 2093 public:
2086 /// Creates a matcher that can match and parse instructions based on bitstring. 2094 /// Creates a matcher that can match and parse instructions based on bitstring.
2087 static constexpr auto GetMatcher(const char* const bitstring, Id op, Type type, 2095 [[nodiscard]] static constexpr auto GetMatcher(const char* const bitstring, Id op,
2088 const char* const name) { 2096 Type type, const char* const name) {
2089 const auto [mask, expected] = GetMaskAndExpect(bitstring); 2097 const auto [mask, expected] = GetMaskAndExpect(bitstring);
2090 return Matcher(name, mask, expected, op, type); 2098 return Matcher(name, mask, expected, op, type);
2091 } 2099 }
2092 }; 2100 };
2093 2101
2094 static std::vector<Matcher> GetDecodeTable() { 2102 [[nodiscard]] static std::vector<Matcher> GetDecodeTable() {
2095 std::vector<Matcher> table = { 2103 std::vector<Matcher> table = {
2096#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name) 2104#define INST(bitstring, op, type, name) Detail::GetMatcher(bitstring, op, type, name)
2097 INST("111000110011----", Id::KIL, Type::Flow, "KIL"), 2105 INST("111000110011----", Id::KIL, Type::Flow, "KIL"),
diff --git a/src/video_core/renderer_opengl/gl_rasterizer.cpp b/src/video_core/renderer_opengl/gl_rasterizer.cpp
index 36bf92808..cdcde7c59 100644
--- a/src/video_core/renderer_opengl/gl_rasterizer.cpp
+++ b/src/video_core/renderer_opengl/gl_rasterizer.cpp
@@ -1579,10 +1579,6 @@ void RasterizerOpenGL::SyncAlphaTest() {
1579 flags[Dirty::AlphaTest] = false; 1579 flags[Dirty::AlphaTest] = false;
1580 1580
1581 const auto& regs = maxwell3d.regs; 1581 const auto& regs = maxwell3d.regs;
1582 if (regs.alpha_test_enabled && regs.rt_control.count > 1) {
1583 LOG_WARNING(Render_OpenGL, "Alpha testing with more than one render target is not tested");
1584 }
1585
1586 if (regs.alpha_test_enabled) { 1582 if (regs.alpha_test_enabled) {
1587 glEnable(GL_ALPHA_TEST); 1583 glEnable(GL_ALPHA_TEST);
1588 glAlphaFunc(MaxwellToGL::ComparisonOp(regs.alpha_test_func), regs.alpha_test_ref); 1584 glAlphaFunc(MaxwellToGL::ComparisonOp(regs.alpha_test_func), regs.alpha_test_ref);
diff --git a/src/yuzu/configuration/configure_input_player.cpp b/src/yuzu/configuration/configure_input_player.cpp
index 72640f5e7..56ab32a35 100644
--- a/src/yuzu/configuration/configure_input_player.cpp
+++ b/src/yuzu/configuration/configure_input_player.cpp
@@ -1137,7 +1137,7 @@ void ConfigureInputPlayer::CreateProfile() {
1137 return; 1137 return;
1138 } 1138 }
1139 1139
1140 if (!profiles->IsProfileNameValid(profile_name.toStdString())) { 1140 if (!InputProfiles::IsProfileNameValid(profile_name.toStdString())) {
1141 QMessageBox::critical(this, tr("Create Input Profile"), 1141 QMessageBox::critical(this, tr("Create Input Profile"),
1142 tr("The given profile name is not valid!")); 1142 tr("The given profile name is not valid!"));
1143 return; 1143 return;