summaryrefslogtreecommitdiff
path: root/src/core
diff options
context:
space:
mode:
Diffstat (limited to 'src/core')
-rw-r--r--src/core/CMakeLists.txt2
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp100
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec.h71
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp234
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h168
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.cpp90
-rw-r--r--src/core/hle/service/nvdrv/devices/nvhost_vic.h88
-rw-r--r--src/core/hle/service/nvdrv/devices/nvmap.h1
-rw-r--r--src/core/hle/service/nvdrv/nvdrv.cpp4
-rw-r--r--src/core/settings.cpp2
-rw-r--r--src/core/settings.h1
-rw-r--r--src/core/telemetry_session.cpp2
12 files changed, 475 insertions, 288 deletions
diff --git a/src/core/CMakeLists.txt b/src/core/CMakeLists.txt
index db1c9fdef..e0f207f3e 100644
--- a/src/core/CMakeLists.txt
+++ b/src/core/CMakeLists.txt
@@ -439,6 +439,8 @@ add_library(core STATIC
439 hle/service/nvdrv/devices/nvhost_gpu.h 439 hle/service/nvdrv/devices/nvhost_gpu.h
440 hle/service/nvdrv/devices/nvhost_nvdec.cpp 440 hle/service/nvdrv/devices/nvhost_nvdec.cpp
441 hle/service/nvdrv/devices/nvhost_nvdec.h 441 hle/service/nvdrv/devices/nvhost_nvdec.h
442 hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
443 hle/service/nvdrv/devices/nvhost_nvdec_common.h
442 hle/service/nvdrv/devices/nvhost_nvjpg.cpp 444 hle/service/nvdrv/devices/nvhost_nvjpg.cpp
443 hle/service/nvdrv/devices/nvhost_nvjpg.h 445 hle/service/nvdrv/devices/nvhost_nvjpg.h
444 hle/service/nvdrv/devices/nvhost_vic.cpp 446 hle/service/nvdrv/devices/nvhost_vic.cpp
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
index fcb612864..b6df48360 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp
@@ -2,15 +2,17 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6
7#include "common/assert.h" 5#include "common/assert.h"
8#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h"
9#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h" 8#include "core/hle/service/nvdrv/devices/nvhost_nvdec.h"
9#include "video_core/memory_manager.h"
10#include "video_core/renderer_base.h"
10 11
11namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
12 13
13nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {} 14nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
15 : nvhost_nvdec_common(system, std::move(nvmap_dev)) {}
14nvhost_nvdec::~nvhost_nvdec() = default; 16nvhost_nvdec::~nvhost_nvdec() = default;
15 17
16u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 18u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -21,7 +23,7 @@ u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::
21 23
22 switch (static_cast<IoctlCommand>(command.raw)) { 24 switch (static_cast<IoctlCommand>(command.raw)) {
23 case IoctlCommand::IocSetNVMAPfdCommand: 25 case IoctlCommand::IocSetNVMAPfdCommand:
24 return SetNVMAPfd(input, output); 26 return SetNVMAPfd(input);
25 case IoctlCommand::IocSubmit: 27 case IoctlCommand::IocSubmit:
26 return Submit(input, output); 28 return Submit(input, output);
27 case IoctlCommand::IocGetSyncpoint: 29 case IoctlCommand::IocGetSyncpoint:
@@ -29,79 +31,29 @@ u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::
29 case IoctlCommand::IocGetWaitbase: 31 case IoctlCommand::IocGetWaitbase:
30 return GetWaitbase(input, output); 32 return GetWaitbase(input, output);
31 case IoctlCommand::IocMapBuffer: 33 case IoctlCommand::IocMapBuffer:
32 return MapBuffer(input, output); 34 case IoctlCommand::IocMapBuffer2:
35 case IoctlCommand::IocMapBuffer3:
33 case IoctlCommand::IocMapBufferEx: 36 case IoctlCommand::IocMapBufferEx:
34 return MapBufferEx(input, output); 37 return MapBuffer(input, output);
35 case IoctlCommand::IocUnmapBufferEx: 38 case IoctlCommand::IocUnmapBufferEx: {
36 return UnmapBufferEx(input, output); 39 // This command is sent when the video stream has ended, flush all video contexts
40 // This is usually sent in the folowing order: vic, nvdec, vic.
41 // Inform the GPU to clear any remaining nvdec buffers when this is detected.
42 LOG_INFO(Service_NVDRV, "NVDEC video stream ended");
43 Tegra::ChCommandHeaderList cmdlist(1);
44 cmdlist[0] = Tegra::ChCommandHeader{0xDEADB33F};
45 system.GPU().PushCommandBuffer(cmdlist);
46 [[fallthrough]]; // fallthrough to unmap buffers
47 };
48 case IoctlCommand::IocUnmapBuffer:
49 case IoctlCommand::IocUnmapBuffer2:
50 case IoctlCommand::IocUnmapBuffer3:
51 return UnmapBuffer(input, output);
52 case IoctlCommand::IocSetSubmitTimeout:
53 return SetSubmitTimeout(input, output);
37 } 54 }
38 55
39 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 56 UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw);
40 return 0;
41}
42
43u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
44 IoctlSetNvmapFD params{};
45 std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
46 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
47
48 nvmap_fd = params.nvmap_fd;
49 return 0;
50}
51
52u32 nvhost_nvdec::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
53 IoctlSubmit params{};
54 std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
55 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
56 std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
57 return 0;
58}
59
60u32 nvhost_nvdec::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
61 IoctlGetSyncpoint params{};
62 std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
63 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
64 params.value = 0; // Seems to be hard coded at 0
65 std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
66 return 0;
67}
68
69u32 nvhost_nvdec::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
70 IoctlGetWaitbase params{};
71 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
72 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
73 params.value = 0; // Seems to be hard coded at 0
74 std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
75 return 0;
76}
77
78u32 nvhost_nvdec::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
79 IoctlMapBuffer params{};
80 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
81 LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
82 params.address_1);
83 params.address_1 = 0;
84 params.address_2 = 0;
85 std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
86 return 0;
87}
88
89u32 nvhost_nvdec::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
90 IoctlMapBufferEx params{};
91 std::memcpy(&params, input.data(), sizeof(IoctlMapBufferEx));
92 LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
93 params.address_1);
94 params.address_1 = 0;
95 params.address_2 = 0;
96 std::memcpy(output.data(), &params, sizeof(IoctlMapBufferEx));
97 return 0;
98}
99
100u32 nvhost_nvdec::UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
101 IoctlUnmapBufferEx params{};
102 std::memcpy(&params, input.data(), sizeof(IoctlUnmapBufferEx));
103 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
104 std::memcpy(output.data(), &params, sizeof(IoctlUnmapBufferEx));
105 return 0; 57 return 0;
106} 58}
107 59
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
index 4332db118..102777ddd 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec.h
@@ -4,16 +4,14 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <vector> 7#include <memory>
8#include "common/common_types.h" 8#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
9#include "common/swap.h"
10#include "core/hle/service/nvdrv/devices/nvdevice.h"
11 9
12namespace Service::Nvidia::Devices { 10namespace Service::Nvidia::Devices {
13 11
14class nvhost_nvdec final : public nvdevice { 12class nvhost_nvdec final : public nvhost_nvdec_common {
15public: 13public:
16 explicit nvhost_nvdec(Core::System& system); 14 explicit nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
17 ~nvhost_nvdec() override; 15 ~nvhost_nvdec() override;
18 16
19 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 17 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -27,62 +25,15 @@ private:
27 IocGetSyncpoint = 0xC0080002, 25 IocGetSyncpoint = 0xC0080002,
28 IocGetWaitbase = 0xC0080003, 26 IocGetWaitbase = 0xC0080003,
29 IocMapBuffer = 0xC01C0009, 27 IocMapBuffer = 0xC01C0009,
28 IocMapBuffer2 = 0xC16C0009,
29 IocMapBuffer3 = 0xC15C0009,
30 IocMapBufferEx = 0xC0A40009, 30 IocMapBufferEx = 0xC0A40009,
31 IocUnmapBufferEx = 0xC0A4000A, 31 IocUnmapBuffer = 0xC0A4000A,
32 IocUnmapBuffer2 = 0xC16C000A,
33 IocUnmapBufferEx = 0xC01C000A,
34 IocUnmapBuffer3 = 0xC15C000A,
35 IocSetSubmitTimeout = 0x40040007,
32 }; 36 };
33
34 struct IoctlSetNvmapFD {
35 u32_le nvmap_fd;
36 };
37 static_assert(sizeof(IoctlSetNvmapFD) == 0x4, "IoctlSetNvmapFD is incorrect size");
38
39 struct IoctlSubmit {
40 INSERT_PADDING_BYTES(0x40); // TODO(DarkLordZach): RE this structure
41 };
42 static_assert(sizeof(IoctlSubmit) == 0x40, "IoctlSubmit has incorrect size");
43
44 struct IoctlGetSyncpoint {
45 u32 unknown; // seems to be ignored? Nintendo added this
46 u32 value;
47 };
48 static_assert(sizeof(IoctlGetSyncpoint) == 0x08, "IoctlGetSyncpoint has incorrect size");
49
50 struct IoctlGetWaitbase {
51 u32 unknown; // seems to be ignored? Nintendo added this
52 u32 value;
53 };
54 static_assert(sizeof(IoctlGetWaitbase) == 0x08, "IoctlGetWaitbase has incorrect size");
55
56 struct IoctlMapBuffer {
57 u32 unknown;
58 u32 address_1;
59 u32 address_2;
60 INSERT_PADDING_BYTES(0x10); // TODO(DarkLordZach): RE this structure
61 };
62 static_assert(sizeof(IoctlMapBuffer) == 0x1C, "IoctlMapBuffer is incorrect size");
63
64 struct IoctlMapBufferEx {
65 u32 unknown;
66 u32 address_1;
67 u32 address_2;
68 INSERT_PADDING_BYTES(0x98); // TODO(DarkLordZach): RE this structure
69 };
70 static_assert(sizeof(IoctlMapBufferEx) == 0xA4, "IoctlMapBufferEx has incorrect size");
71
72 struct IoctlUnmapBufferEx {
73 INSERT_PADDING_BYTES(0xA4); // TODO(DarkLordZach): RE this structure
74 };
75 static_assert(sizeof(IoctlUnmapBufferEx) == 0xA4, "IoctlUnmapBufferEx has incorrect size");
76
77 u32_le nvmap_fd{};
78
79 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
80 u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
81 u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
82 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
83 u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
84 u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
85 u32 UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
86}; 37};
87 38
88} // namespace Service::Nvidia::Devices 39} // 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
new file mode 100644
index 000000000..85792495f
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp
@@ -0,0 +1,234 @@
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 <algorithm>
6#include <cstring>
7
8#include "common/assert.h"
9#include "common/common_types.h"
10#include "common/logging/log.h"
11#include "core/core.h"
12#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
13#include "core/hle/service/nvdrv/devices/nvmap.h"
14#include "core/memory.h"
15#include "video_core/memory_manager.h"
16#include "video_core/renderer_base.h"
17
18namespace Service::Nvidia::Devices {
19
20namespace {
21// Splice vectors will copy count amount of type T from the input vector into the dst vector.
22template <typename T>
23std::size_t SpliceVectors(const std::vector<u8>& input, std::vector<T>& dst, std::size_t count,
24 std::size_t offset) {
25 std::memcpy(dst.data(), input.data() + offset, count * sizeof(T));
26 offset += count * sizeof(T);
27 return offset;
28}
29
30// Write vectors will write data to the output buffer
31template <typename T>
32std::size_t WriteVectors(std::vector<u8>& dst, const std::vector<T>& src, std::size_t offset) {
33 std::memcpy(dst.data() + offset, src.data(), src.size() * sizeof(T));
34 offset += src.size() * sizeof(T);
35 return offset;
36}
37} // Anonymous namespace
38
39namespace NvErrCodes {
40constexpr u32 Success{};
41constexpr 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)
46 : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {}
47nvhost_nvdec_common::~nvhost_nvdec_common() = default;
48
49u32 nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) {
50 IoctlSetNvmapFD params{};
51 std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
52 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
53
54 nvmap_fd = params.nvmap_fd;
55 return 0;
56}
57
58u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
59 IoctlSubmit params{};
60 std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
61 LOG_DEBUG(Service_NVDRV, "called NVDEC Submit, cmd_buffer_count={}", params.cmd_buffer_count);
62
63 // Instantiate param buffers
64 std::size_t offset = sizeof(IoctlSubmit);
65 std::vector<CommandBuffer> command_buffers(params.cmd_buffer_count);
66 std::vector<Reloc> relocs(params.relocation_count);
67 std::vector<u32> reloc_shifts(params.relocation_count);
68 std::vector<SyncptIncr> syncpt_increments(params.syncpoint_count);
69 std::vector<SyncptIncr> wait_checks(params.syncpoint_count);
70 std::vector<Fence> fences(params.fence_count);
71
72 // Splice input into their respective buffers
73 offset = SpliceVectors(input, command_buffers, params.cmd_buffer_count, offset);
74 offset = SpliceVectors(input, relocs, params.relocation_count, offset);
75 offset = SpliceVectors(input, reloc_shifts, params.relocation_count, offset);
76 offset = SpliceVectors(input, syncpt_increments, params.syncpoint_count, offset);
77 offset = SpliceVectors(input, wait_checks, params.syncpoint_count, offset);
78 offset = SpliceVectors(input, fences, params.fence_count, offset);
79
80 // TODO(ameerj): For async gpu, utilize fences for syncpoint 'max' increment
81
82 auto& gpu = system.GPU();
83
84 for (const auto& cmd_buffer : command_buffers) {
85 auto object = nvmap_dev->GetObject(cmd_buffer.memory_id);
86 ASSERT_OR_EXECUTE(object, return NvErrCodes::InvalidInput;);
87 const auto map = FindBufferMap(object->dma_map_addr);
88 if (!map) {
89 LOG_ERROR(Service_NVDRV, "Tried to submit an invalid offset 0x{:X} dma 0x{:X}",
90 object->addr, object->dma_map_addr);
91 return 0;
92 }
93 Tegra::ChCommandHeaderList cmdlist(cmd_buffer.word_count);
94 gpu.MemoryManager().ReadBlock(map->StartAddr() + cmd_buffer.offset, cmdlist.data(),
95 cmdlist.size() * sizeof(u32));
96 gpu.PushCommandBuffer(cmdlist);
97 }
98
99 std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
100 // Some games expect command_buffers to be written back
101 offset = sizeof(IoctlSubmit);
102 offset = WriteVectors(output, command_buffers, offset);
103 offset = WriteVectors(output, relocs, offset);
104 offset = WriteVectors(output, reloc_shifts, offset);
105 offset = WriteVectors(output, syncpt_increments, offset);
106 offset = WriteVectors(output, wait_checks, offset);
107
108 return NvErrCodes::Success;
109}
110
111u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
112 IoctlGetSyncpoint params{};
113 std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
114 LOG_DEBUG(Service_NVDRV, "called GetSyncpoint, id={}", params.param);
115
116 // We found that implementing this causes deadlocks with async gpu, along with degraded
117 // performance. TODO: RE the nvdec async implementation
118 params.value = 0;
119 std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
120
121 return NvErrCodes::Success;
122}
123
124u32 nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
125 IoctlGetWaitbase params{};
126 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
127 params.value = 0; // Seems to be hard coded at 0
128 std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
129 return 0;
130}
131
132u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
133 IoctlMapBuffer params{};
134 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
135 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
136
137 SpliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
138
139 auto& gpu = system.GPU();
140
141 for (auto& cmf_buff : cmd_buffer_handles) {
142 auto object{nvmap_dev->GetObject(cmf_buff.map_handle)};
143 if (!object) {
144 LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
145 std::memcpy(output.data(), &params, output.size());
146 return NvErrCodes::InvalidInput;
147 }
148 if (object->dma_map_addr == 0) {
149 // NVDEC and VIC memory is in the 32-bit address space
150 // MapAllocate32 will attempt to map a lower 32-bit value in the shared gpu memory space
151 const GPUVAddr low_addr = gpu.MemoryManager().MapAllocate32(object->addr, object->size);
152 object->dma_map_addr = static_cast<u32>(low_addr);
153 // Ensure that the dma_map_addr is indeed in the lower 32-bit address space.
154 ASSERT(object->dma_map_addr == low_addr);
155 }
156 if (!object->dma_map_addr) {
157 LOG_ERROR(Service_NVDRV, "failed to map size={}", object->size);
158 } else {
159 cmf_buff.map_address = object->dma_map_addr;
160 AddBufferMap(object->dma_map_addr, object->size, object->addr,
161 object->status == nvmap::Object::Status::Allocated);
162 }
163 }
164 std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
165 std::memcpy(output.data() + sizeof(IoctlMapBuffer), cmd_buffer_handles.data(),
166 cmd_buffer_handles.size() * sizeof(MapBufferEntry));
167
168 return NvErrCodes::Success;
169}
170
171u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
172 IoctlMapBuffer params{};
173 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
174 std::vector<MapBufferEntry> cmd_buffer_handles(params.num_entries);
175 SpliceVectors(input, cmd_buffer_handles, params.num_entries, sizeof(IoctlMapBuffer));
176
177 auto& gpu = system.GPU();
178
179 for (auto& cmf_buff : cmd_buffer_handles) {
180 const auto object{nvmap_dev->GetObject(cmf_buff.map_handle)};
181 if (!object) {
182 LOG_ERROR(Service_NVDRV, "invalid cmd_buffer nvmap_handle={:X}", cmf_buff.map_handle);
183 std::memcpy(output.data(), &params, output.size());
184 return NvErrCodes::InvalidInput;
185 }
186 if (const auto size{RemoveBufferMap(object->dma_map_addr)}; size) {
187 gpu.MemoryManager().Unmap(object->dma_map_addr, *size);
188 } else {
189 // This occurs quite frequently, however does not seem to impact functionality
190 LOG_DEBUG(Service_NVDRV, "invalid offset=0x{:X} dma=0x{:X}", object->addr,
191 object->dma_map_addr);
192 }
193 object->dma_map_addr = 0;
194 }
195 std::memset(output.data(), 0, output.size());
196 return NvErrCodes::Success;
197}
198
199u32 nvhost_nvdec_common::SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output) {
200 std::memcpy(&submit_timeout, input.data(), input.size());
201 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
202 return NvErrCodes::Success;
203}
204
205std::optional<nvhost_nvdec_common::BufferMap> nvhost_nvdec_common::FindBufferMap(
206 GPUVAddr gpu_addr) const {
207 const auto it = std::find_if(
208 buffer_mappings.begin(), buffer_mappings.upper_bound(gpu_addr), [&](const auto& entry) {
209 return (gpu_addr >= entry.second.StartAddr() && gpu_addr < entry.second.EndAddr());
210 });
211
212 ASSERT(it != buffer_mappings.end());
213 return it->second;
214}
215
216void nvhost_nvdec_common::AddBufferMap(GPUVAddr gpu_addr, std::size_t size, VAddr cpu_addr,
217 bool is_allocated) {
218 buffer_mappings.insert_or_assign(gpu_addr, BufferMap{gpu_addr, size, cpu_addr, is_allocated});
219}
220
221std::optional<std::size_t> nvhost_nvdec_common::RemoveBufferMap(GPUVAddr gpu_addr) {
222 const auto iter{buffer_mappings.find(gpu_addr)};
223 if (iter == buffer_mappings.end()) {
224 return std::nullopt;
225 }
226 std::size_t size = 0;
227 if (iter->second.IsAllocated()) {
228 size = iter->second.Size();
229 }
230 buffer_mappings.erase(iter);
231 return size;
232}
233
234} // namespace Service::Nvidia::Devices
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
new file mode 100644
index 000000000..c249c5349
--- /dev/null
+++ b/src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h
@@ -0,0 +1,168 @@
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 <map>
8#include <vector>
9#include "common/common_types.h"
10#include "common/swap.h"
11#include "core/hle/service/nvdrv/devices/nvdevice.h"
12
13namespace Service::Nvidia::Devices {
14class nvmap;
15
16class nvhost_nvdec_common : public nvdevice {
17public:
18 explicit nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
19 ~nvhost_nvdec_common() override;
20
21 virtual u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
22 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
23 IoctlVersion version) = 0;
24
25protected:
26 class BufferMap final {
27 public:
28 constexpr BufferMap() = default;
29
30 constexpr BufferMap(GPUVAddr start_addr, std::size_t size)
31 : start_addr{start_addr}, end_addr{start_addr + size} {}
32
33 constexpr BufferMap(GPUVAddr start_addr, std::size_t size, VAddr cpu_addr,
34 bool is_allocated)
35 : start_addr{start_addr}, end_addr{start_addr + size}, cpu_addr{cpu_addr},
36 is_allocated{is_allocated} {}
37
38 constexpr VAddr StartAddr() const {
39 return start_addr;
40 }
41
42 constexpr VAddr EndAddr() const {
43 return end_addr;
44 }
45
46 constexpr std::size_t Size() const {
47 return end_addr - start_addr;
48 }
49
50 constexpr VAddr CpuAddr() const {
51 return cpu_addr;
52 }
53
54 constexpr bool IsAllocated() const {
55 return is_allocated;
56 }
57
58 private:
59 GPUVAddr start_addr{};
60 GPUVAddr end_addr{};
61 VAddr cpu_addr{};
62 bool is_allocated{};
63 };
64
65 struct IoctlSetNvmapFD {
66 u32_le nvmap_fd;
67 };
68 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
69
70 struct IoctlSubmitCommandBuffer {
71 u32_le id;
72 u32_le offset;
73 u32_le count;
74 };
75 static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
76 "IoctlSubmitCommandBuffer is incorrect size");
77 struct IoctlSubmit {
78 u32_le cmd_buffer_count;
79 u32_le relocation_count;
80 u32_le syncpoint_count;
81 u32_le fence_count;
82 };
83 static_assert(sizeof(IoctlSubmit) == 0x10, "IoctlSubmit has incorrect size");
84
85 struct CommandBuffer {
86 s32 memory_id;
87 u32 offset;
88 s32 word_count;
89 };
90 static_assert(sizeof(CommandBuffer) == 0xC, "CommandBuffer has incorrect size");
91
92 struct Reloc {
93 s32 cmdbuffer_memory;
94 s32 cmdbuffer_offset;
95 s32 target;
96 s32 target_offset;
97 };
98 static_assert(sizeof(Reloc) == 0x10, "CommandBuffer has incorrect size");
99
100 struct SyncptIncr {
101 u32 id;
102 u32 increments;
103 };
104 static_assert(sizeof(SyncptIncr) == 0x8, "CommandBuffer has incorrect size");
105
106 struct Fence {
107 u32 id;
108 u32 value;
109 };
110 static_assert(sizeof(Fence) == 0x8, "CommandBuffer has incorrect size");
111
112 struct IoctlGetSyncpoint {
113 // Input
114 u32_le param;
115 // Output
116 u32_le value;
117 };
118 static_assert(sizeof(IoctlGetSyncpoint) == 8, "IocGetIdParams has wrong size");
119
120 struct IoctlGetWaitbase {
121 u32_le unknown; // seems to be ignored? Nintendo added this
122 u32_le value;
123 };
124 static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
125
126 struct IoctlMapBuffer {
127 u32_le num_entries;
128 u32_le data_address; // Ignored by the driver.
129 u32_le attach_host_ch_das;
130 };
131 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
132
133 struct IocGetIdParams {
134 // Input
135 u32_le param;
136 // Output
137 u32_le value;
138 };
139 static_assert(sizeof(IocGetIdParams) == 8, "IocGetIdParams has wrong size");
140
141 // Used for mapping and unmapping command buffers
142 struct MapBufferEntry {
143 u32_le map_handle;
144 u32_le map_address;
145 };
146 static_assert(sizeof(IoctlMapBuffer) == 0x0C, "IoctlMapBuffer is incorrect size");
147
148 /// Ioctl command implementations
149 u32 SetNVMAPfd(const std::vector<u8>& input);
150 u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
151 u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
152 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
153 u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
154 u32 UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
155 u32 SetSubmitTimeout(const std::vector<u8>& input, std::vector<u8>& output);
156
157 std::optional<BufferMap> FindBufferMap(GPUVAddr gpu_addr) const;
158 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);
160
161 u32_le nvmap_fd{};
162 u32_le submit_timeout{};
163 std::shared_ptr<nvmap> nvmap_dev;
164
165 // This is expected to be ordered, therefore we must use a map, not unordered_map
166 std::map<GPUVAddr, BufferMap> buffer_mappings;
167};
168}; // 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 9da19ad56..60db54d00 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.cpp
@@ -2,15 +2,17 @@
2// Licensed under GPLv2 or any later version 2// Licensed under GPLv2 or any later version
3// Refer to the license.txt file included. 3// Refer to the license.txt file included.
4 4
5#include <cstring>
6
7#include "common/assert.h" 5#include "common/assert.h"
8#include "common/logging/log.h" 6#include "common/logging/log.h"
7#include "core/core.h"
9#include "core/hle/service/nvdrv/devices/nvhost_vic.h" 8#include "core/hle/service/nvdrv/devices/nvhost_vic.h"
9#include "video_core/memory_manager.h"
10#include "video_core/renderer_base.h"
10 11
11namespace Service::Nvidia::Devices { 12namespace Service::Nvidia::Devices {
13nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev)
14 : nvhost_nvdec_common(system, std::move(nvmap_dev)) {}
12 15
13nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {}
14nvhost_vic::~nvhost_vic() = default; 16nvhost_vic::~nvhost_vic() = default;
15 17
16u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 18u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
@@ -21,7 +23,7 @@ u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve
21 23
22 switch (static_cast<IoctlCommand>(command.raw)) { 24 switch (static_cast<IoctlCommand>(command.raw)) {
23 case IoctlCommand::IocSetNVMAPfdCommand: 25 case IoctlCommand::IocSetNVMAPfdCommand:
24 return SetNVMAPfd(input, output); 26 return SetNVMAPfd(input);
25 case IoctlCommand::IocSubmit: 27 case IoctlCommand::IocSubmit:
26 return Submit(input, output); 28 return Submit(input, output);
27 case IoctlCommand::IocGetSyncpoint: 29 case IoctlCommand::IocGetSyncpoint:
@@ -29,83 +31,19 @@ u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::ve
29 case IoctlCommand::IocGetWaitbase: 31 case IoctlCommand::IocGetWaitbase:
30 return GetWaitbase(input, output); 32 return GetWaitbase(input, output);
31 case IoctlCommand::IocMapBuffer: 33 case IoctlCommand::IocMapBuffer:
32 return MapBuffer(input, output); 34 case IoctlCommand::IocMapBuffer2:
35 case IoctlCommand::IocMapBuffer3:
36 case IoctlCommand::IocMapBuffer4:
33 case IoctlCommand::IocMapBufferEx: 37 case IoctlCommand::IocMapBufferEx:
34 return MapBuffer(input, output); 38 return MapBuffer(input, output);
39 case IoctlCommand::IocUnmapBuffer:
40 case IoctlCommand::IocUnmapBuffer2:
41 case IoctlCommand::IocUnmapBuffer3:
35 case IoctlCommand::IocUnmapBufferEx: 42 case IoctlCommand::IocUnmapBufferEx:
36 return UnmapBufferEx(input, output); 43 return UnmapBuffer(input, output);
37 } 44 }
38 45
39 UNIMPLEMENTED_MSG("Unimplemented ioctl"); 46 UNIMPLEMENTED_MSG("Unimplemented ioctl 0x{:X}", command.raw);
40 return 0;
41}
42
43u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) {
44 IoctlSetNvmapFD params{};
45 std::memcpy(&params, input.data(), sizeof(IoctlSetNvmapFD));
46 LOG_DEBUG(Service_NVDRV, "called, fd={}", params.nvmap_fd);
47
48 nvmap_fd = params.nvmap_fd;
49 return 0;
50}
51
52u32 nvhost_vic::Submit(const std::vector<u8>& input, std::vector<u8>& output) {
53 IoctlSubmit params{};
54 std::memcpy(&params, input.data(), sizeof(IoctlSubmit));
55 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
56
57 // Workaround for Luigi's Mansion 3, as nvhost_vic is not implemented for asynch GPU
58 params.command_buffer = {};
59
60 std::memcpy(output.data(), &params, sizeof(IoctlSubmit));
61 return 0;
62}
63
64u32 nvhost_vic::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) {
65 IoctlGetSyncpoint params{};
66 std::memcpy(&params, input.data(), sizeof(IoctlGetSyncpoint));
67 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
68 params.value = 0; // Seems to be hard coded at 0
69 std::memcpy(output.data(), &params, sizeof(IoctlGetSyncpoint));
70 return 0;
71}
72
73u32 nvhost_vic::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) {
74 IoctlGetWaitbase params{};
75 std::memcpy(&params, input.data(), sizeof(IoctlGetWaitbase));
76 LOG_INFO(Service_NVDRV, "called, unknown=0x{:X}", params.unknown);
77 params.value = 0; // Seems to be hard coded at 0
78 std::memcpy(output.data(), &params, sizeof(IoctlGetWaitbase));
79 return 0;
80}
81
82u32 nvhost_vic::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) {
83 IoctlMapBuffer params{};
84 std::memcpy(&params, input.data(), sizeof(IoctlMapBuffer));
85 LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
86 params.address_1);
87 params.address_1 = 0;
88 params.address_2 = 0;
89 std::memcpy(output.data(), &params, sizeof(IoctlMapBuffer));
90 return 0;
91}
92
93u32 nvhost_vic::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
94 IoctlMapBufferEx params{};
95 std::memcpy(&params, input.data(), sizeof(IoctlMapBufferEx));
96 LOG_WARNING(Service_NVDRV, "(STUBBED) called with address={:08X}{:08X}", params.address_2,
97 params.address_1);
98 params.address_1 = 0;
99 params.address_2 = 0;
100 std::memcpy(output.data(), &params, sizeof(IoctlMapBufferEx));
101 return 0;
102}
103
104u32 nvhost_vic::UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) {
105 IoctlUnmapBufferEx params{};
106 std::memcpy(&params, input.data(), sizeof(IoctlUnmapBufferEx));
107 LOG_WARNING(Service_NVDRV, "(STUBBED) called");
108 std::memcpy(output.data(), &params, sizeof(IoctlUnmapBufferEx));
109 return 0; 47 return 0;
110} 48}
111 49
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_vic.h b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
index a7bb7bbd5..f975b190c 100644
--- a/src/core/hle/service/nvdrv/devices/nvhost_vic.h
+++ b/src/core/hle/service/nvdrv/devices/nvhost_vic.h
@@ -4,19 +4,15 @@
4 4
5#pragma once 5#pragma once
6 6
7#include <array> 7#include "core/hle/service/nvdrv/devices/nvhost_nvdec_common.h"
8#include <vector>
9#include "common/common_types.h"
10#include "common/swap.h"
11#include "core/hle/service/nvdrv/devices/nvdevice.h"
12 8
13namespace Service::Nvidia::Devices { 9namespace Service::Nvidia::Devices {
10class nvmap;
14 11
15class nvhost_vic final : public nvdevice { 12class nvhost_vic final : public nvhost_nvdec_common {
16public: 13public:
17 explicit nvhost_vic(Core::System& system); 14 explicit nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev);
18 ~nvhost_vic() override; 15 ~nvhost_vic();
19
20 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, 16 u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2,
21 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl, 17 std::vector<u8>& output, std::vector<u8>& output2, IoctlCtrl& ctrl,
22 IoctlVersion version) override; 18 IoctlVersion version) override;
@@ -28,74 +24,14 @@ private:
28 IocGetSyncpoint = 0xC0080002, 24 IocGetSyncpoint = 0xC0080002,
29 IocGetWaitbase = 0xC0080003, 25 IocGetWaitbase = 0xC0080003,
30 IocMapBuffer = 0xC01C0009, 26 IocMapBuffer = 0xC01C0009,
27 IocMapBuffer2 = 0xC0340009,
28 IocMapBuffer3 = 0xC0140009,
29 IocMapBuffer4 = 0xC00C0009,
31 IocMapBufferEx = 0xC03C0009, 30 IocMapBufferEx = 0xC03C0009,
32 IocUnmapBufferEx = 0xC03C000A, 31 IocUnmapBuffer = 0xC03C000A,
33 }; 32 IocUnmapBuffer2 = 0xC034000A,
34 33 IocUnmapBuffer3 = 0xC00C000A,
35 struct IoctlSetNvmapFD { 34 IocUnmapBufferEx = 0xC01C000A,
36 u32_le nvmap_fd;
37 };
38 static_assert(sizeof(IoctlSetNvmapFD) == 4, "IoctlSetNvmapFD is incorrect size");
39
40 struct IoctlSubmitCommandBuffer {
41 u32 id;
42 u32 offset;
43 u32 count;
44 };
45 static_assert(sizeof(IoctlSubmitCommandBuffer) == 0xC,
46 "IoctlSubmitCommandBuffer is incorrect size");
47
48 struct IoctlSubmit {
49 u32 command_buffer_count;
50 u32 relocations_count;
51 u32 syncpt_count;
52 u32 wait_count;
53 std::array<IoctlSubmitCommandBuffer, 4> command_buffer;
54 };
55 static_assert(sizeof(IoctlSubmit) == 0x40, "IoctlSubmit is incorrect size");
56
57 struct IoctlGetSyncpoint {
58 u32 unknown; // seems to be ignored? Nintendo added this
59 u32 value;
60 };
61 static_assert(sizeof(IoctlGetSyncpoint) == 0x8, "IoctlGetSyncpoint is incorrect size");
62
63 struct IoctlGetWaitbase {
64 u32 unknown; // seems to be ignored? Nintendo added this
65 u32 value;
66 };
67 static_assert(sizeof(IoctlGetWaitbase) == 0x8, "IoctlGetWaitbase is incorrect size");
68
69 struct IoctlMapBuffer {
70 u32 unknown;
71 u32 address_1;
72 u32 address_2;
73 INSERT_PADDING_BYTES(0x10); // TODO(DarkLordZach): RE this structure
74 };
75 static_assert(sizeof(IoctlMapBuffer) == 0x1C, "IoctlMapBuffer is incorrect size");
76
77 struct IoctlMapBufferEx {
78 u32 unknown;
79 u32 address_1;
80 u32 address_2;
81 INSERT_PADDING_BYTES(0x30); // TODO(DarkLordZach): RE this structure
82 }; 35 };
83 static_assert(sizeof(IoctlMapBufferEx) == 0x3C, "IoctlMapBufferEx is incorrect size");
84
85 struct IoctlUnmapBufferEx {
86 INSERT_PADDING_BYTES(0x3C); // TODO(DarkLordZach): RE this structure
87 };
88 static_assert(sizeof(IoctlUnmapBufferEx) == 0x3C, "IoctlUnmapBufferEx is incorrect size");
89
90 u32_le nvmap_fd{};
91
92 u32 SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output);
93 u32 Submit(const std::vector<u8>& input, std::vector<u8>& output);
94 u32 GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output);
95 u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
96 u32 MapBuffer(const std::vector<u8>& input, std::vector<u8>& output);
97 u32 MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
98 u32 UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output);
99}; 36};
100
101} // namespace Service::Nvidia::Devices 37} // 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 84624be00..04b9ef540 100644
--- a/src/core/hle/service/nvdrv/devices/nvmap.h
+++ b/src/core/hle/service/nvdrv/devices/nvmap.h
@@ -37,6 +37,7 @@ public:
37 VAddr addr; 37 VAddr addr;
38 Status status; 38 Status status;
39 u32 refcount; 39 u32 refcount;
40 u32 dma_map_addr;
40 }; 41 };
41 42
42 std::shared_ptr<Object> GetObject(u32 handle) const { 43 std::shared_ptr<Object> GetObject(u32 handle) const {
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp
index 197c77db0..803c1a984 100644
--- a/src/core/hle/service/nvdrv/nvdrv.cpp
+++ b/src/core/hle/service/nvdrv/nvdrv.cpp
@@ -51,9 +51,9 @@ Module::Module(Core::System& system) {
51 devices["/dev/nvmap"] = nvmap_dev; 51 devices["/dev/nvmap"] = nvmap_dev;
52 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev); 52 devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev);
53 devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(system, events_interface); 53 devices["/dev/nvhost-ctrl"] = std::make_shared<Devices::nvhost_ctrl>(system, events_interface);
54 devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system); 54 devices["/dev/nvhost-nvdec"] = std::make_shared<Devices::nvhost_nvdec>(system, nvmap_dev);
55 devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system); 55 devices["/dev/nvhost-nvjpg"] = std::make_shared<Devices::nvhost_nvjpg>(system);
56 devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system); 56 devices["/dev/nvhost-vic"] = std::make_shared<Devices::nvhost_vic>(system, nvmap_dev);
57} 57}
58 58
59Module::~Module() = default; 59Module::~Module() = default;
diff --git a/src/core/settings.cpp b/src/core/settings.cpp
index 28d3f9099..e14c02045 100644
--- a/src/core/settings.cpp
+++ b/src/core/settings.cpp
@@ -63,6 +63,7 @@ void LogSettings() {
63 log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue()); 63 log_setting("Renderer_GPUAccuracyLevel", values.gpu_accuracy.GetValue());
64 log_setting("Renderer_UseAsynchronousGpuEmulation", 64 log_setting("Renderer_UseAsynchronousGpuEmulation",
65 values.use_asynchronous_gpu_emulation.GetValue()); 65 values.use_asynchronous_gpu_emulation.GetValue());
66 log_setting("Renderer_UseNvdecEmulation", values.use_nvdec_emulation.GetValue());
66 log_setting("Renderer_UseVsync", values.use_vsync.GetValue()); 67 log_setting("Renderer_UseVsync", values.use_vsync.GetValue());
67 log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue()); 68 log_setting("Renderer_UseAssemblyShaders", values.use_assembly_shaders.GetValue());
68 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue()); 69 log_setting("Renderer_UseAsynchronousShaders", values.use_asynchronous_shaders.GetValue());
@@ -119,6 +120,7 @@ void RestoreGlobalState() {
119 values.use_disk_shader_cache.SetGlobal(true); 120 values.use_disk_shader_cache.SetGlobal(true);
120 values.gpu_accuracy.SetGlobal(true); 121 values.gpu_accuracy.SetGlobal(true);
121 values.use_asynchronous_gpu_emulation.SetGlobal(true); 122 values.use_asynchronous_gpu_emulation.SetGlobal(true);
123 values.use_nvdec_emulation.SetGlobal(true);
122 values.use_vsync.SetGlobal(true); 124 values.use_vsync.SetGlobal(true);
123 values.use_assembly_shaders.SetGlobal(true); 125 values.use_assembly_shaders.SetGlobal(true);
124 values.use_asynchronous_shaders.SetGlobal(true); 126 values.use_asynchronous_shaders.SetGlobal(true);
diff --git a/src/core/settings.h b/src/core/settings.h
index 9834f44bb..604805615 100644
--- a/src/core/settings.h
+++ b/src/core/settings.h
@@ -111,6 +111,7 @@ struct Values {
111 Setting<bool> use_disk_shader_cache; 111 Setting<bool> use_disk_shader_cache;
112 Setting<GPUAccuracy> gpu_accuracy; 112 Setting<GPUAccuracy> gpu_accuracy;
113 Setting<bool> use_asynchronous_gpu_emulation; 113 Setting<bool> use_asynchronous_gpu_emulation;
114 Setting<bool> use_nvdec_emulation;
114 Setting<bool> use_vsync; 115 Setting<bool> use_vsync;
115 Setting<bool> use_assembly_shaders; 116 Setting<bool> use_assembly_shaders;
116 Setting<bool> use_asynchronous_shaders; 117 Setting<bool> use_asynchronous_shaders;
diff --git a/src/core/telemetry_session.cpp b/src/core/telemetry_session.cpp
index da09c0dbc..ebc19e18a 100644
--- a/src/core/telemetry_session.cpp
+++ b/src/core/telemetry_session.cpp
@@ -206,6 +206,8 @@ void TelemetrySession::AddInitialInfo(Loader::AppLoader& app_loader) {
206 TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue())); 206 TranslateGPUAccuracyLevel(Settings::values.gpu_accuracy.GetValue()));
207 AddField(field_type, "Renderer_UseAsynchronousGpuEmulation", 207 AddField(field_type, "Renderer_UseAsynchronousGpuEmulation",
208 Settings::values.use_asynchronous_gpu_emulation.GetValue()); 208 Settings::values.use_asynchronous_gpu_emulation.GetValue());
209 AddField(field_type, "Renderer_UseNvdecEmulation",
210 Settings::values.use_nvdec_emulation.GetValue());
209 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue()); 211 AddField(field_type, "Renderer_UseVsync", Settings::values.use_vsync.GetValue());
210 AddField(field_type, "Renderer_UseAssemblyShaders", 212 AddField(field_type, "Renderer_UseAssemblyShaders",
211 Settings::values.use_assembly_shaders.GetValue()); 213 Settings::values.use_assembly_shaders.GetValue());