diff options
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/CMakeLists.txt | 2 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec.cpp | 100 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec.h | 71 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.cpp | 234 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_nvdec_common.h | 168 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_vic.cpp | 90 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_vic.h | 88 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvmap.h | 1 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.cpp | 4 | ||||
| -rw-r--r-- | src/core/settings.cpp | 2 | ||||
| -rw-r--r-- | src/core/settings.h | 1 | ||||
| -rw-r--r-- | src/core/telemetry_session.cpp | 2 |
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 | ||
| 11 | namespace Service::Nvidia::Devices { | 12 | namespace Service::Nvidia::Devices { |
| 12 | 13 | ||
| 13 | nvhost_nvdec::nvhost_nvdec(Core::System& system) : nvdevice(system) {} | 14 | nvhost_nvdec::nvhost_nvdec(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) |
| 15 | : nvhost_nvdec_common(system, std::move(nvmap_dev)) {} | ||
| 14 | nvhost_nvdec::~nvhost_nvdec() = default; | 16 | nvhost_nvdec::~nvhost_nvdec() = default; |
| 15 | 17 | ||
| 16 | u32 nvhost_nvdec::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 18 | u32 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 | |||
| 43 | u32 nvhost_nvdec::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 44 | IoctlSetNvmapFD params{}; | ||
| 45 | std::memcpy(¶ms, 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 | |||
| 52 | u32 nvhost_nvdec::Submit(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 53 | IoctlSubmit params{}; | ||
| 54 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmit)); | ||
| 55 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | ||
| 56 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmit)); | ||
| 57 | return 0; | ||
| 58 | } | ||
| 59 | |||
| 60 | u32 nvhost_nvdec::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 61 | IoctlGetSyncpoint params{}; | ||
| 62 | std::memcpy(¶ms, 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(), ¶ms, sizeof(IoctlGetSyncpoint)); | ||
| 66 | return 0; | ||
| 67 | } | ||
| 68 | |||
| 69 | u32 nvhost_nvdec::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 70 | IoctlGetWaitbase params{}; | ||
| 71 | std::memcpy(¶ms, 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(), ¶ms, sizeof(IoctlGetWaitbase)); | ||
| 75 | return 0; | ||
| 76 | } | ||
| 77 | |||
| 78 | u32 nvhost_nvdec::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 79 | IoctlMapBuffer params{}; | ||
| 80 | std::memcpy(¶ms, 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(), ¶ms, sizeof(IoctlMapBuffer)); | ||
| 86 | return 0; | ||
| 87 | } | ||
| 88 | |||
| 89 | u32 nvhost_nvdec::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 90 | IoctlMapBufferEx params{}; | ||
| 91 | std::memcpy(¶ms, 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(), ¶ms, sizeof(IoctlMapBufferEx)); | ||
| 97 | return 0; | ||
| 98 | } | ||
| 99 | |||
| 100 | u32 nvhost_nvdec::UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 101 | IoctlUnmapBufferEx params{}; | ||
| 102 | std::memcpy(¶ms, input.data(), sizeof(IoctlUnmapBufferEx)); | ||
| 103 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | ||
| 104 | std::memcpy(output.data(), ¶ms, 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 | ||
| 12 | namespace Service::Nvidia::Devices { | 10 | namespace Service::Nvidia::Devices { |
| 13 | 11 | ||
| 14 | class nvhost_nvdec final : public nvdevice { | 12 | class nvhost_nvdec final : public nvhost_nvdec_common { |
| 15 | public: | 13 | public: |
| 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 | |||
| 18 | namespace Service::Nvidia::Devices { | ||
| 19 | |||
| 20 | namespace { | ||
| 21 | // Splice vectors will copy count amount of type T from the input vector into the dst vector. | ||
| 22 | template <typename T> | ||
| 23 | std::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 | ||
| 31 | template <typename T> | ||
| 32 | std::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 | |||
| 39 | namespace NvErrCodes { | ||
| 40 | constexpr u32 Success{}; | ||
| 41 | constexpr u32 OutOfMemory{static_cast<u32>(-12)}; | ||
| 42 | constexpr u32 InvalidInput{static_cast<u32>(-22)}; | ||
| 43 | } // namespace NvErrCodes | ||
| 44 | |||
| 45 | nvhost_nvdec_common::nvhost_nvdec_common(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | ||
| 46 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | ||
| 47 | nvhost_nvdec_common::~nvhost_nvdec_common() = default; | ||
| 48 | |||
| 49 | u32 nvhost_nvdec_common::SetNVMAPfd(const std::vector<u8>& input) { | ||
| 50 | IoctlSetNvmapFD params{}; | ||
| 51 | std::memcpy(¶ms, 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 | |||
| 58 | u32 nvhost_nvdec_common::Submit(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 59 | IoctlSubmit params{}; | ||
| 60 | std::memcpy(¶ms, 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(), ¶ms, 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 | |||
| 111 | u32 nvhost_nvdec_common::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 112 | IoctlGetSyncpoint params{}; | ||
| 113 | std::memcpy(¶ms, 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(), ¶ms, sizeof(IoctlGetSyncpoint)); | ||
| 120 | |||
| 121 | return NvErrCodes::Success; | ||
| 122 | } | ||
| 123 | |||
| 124 | u32 nvhost_nvdec_common::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 125 | IoctlGetWaitbase params{}; | ||
| 126 | std::memcpy(¶ms, input.data(), sizeof(IoctlGetWaitbase)); | ||
| 127 | params.value = 0; // Seems to be hard coded at 0 | ||
| 128 | std::memcpy(output.data(), ¶ms, sizeof(IoctlGetWaitbase)); | ||
| 129 | return 0; | ||
| 130 | } | ||
| 131 | |||
| 132 | u32 nvhost_nvdec_common::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 133 | IoctlMapBuffer params{}; | ||
| 134 | std::memcpy(¶ms, 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(), ¶ms, 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(), ¶ms, 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 | |||
| 171 | u32 nvhost_nvdec_common::UnmapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 172 | IoctlMapBuffer params{}; | ||
| 173 | std::memcpy(¶ms, 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(), ¶ms, 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 | |||
| 199 | u32 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 | |||
| 205 | std::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 | |||
| 216 | void 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 | |||
| 221 | std::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 | |||
| 13 | namespace Service::Nvidia::Devices { | ||
| 14 | class nvmap; | ||
| 15 | |||
| 16 | class nvhost_nvdec_common : public nvdevice { | ||
| 17 | public: | ||
| 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 | |||
| 25 | protected: | ||
| 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 | ||
| 11 | namespace Service::Nvidia::Devices { | 12 | namespace Service::Nvidia::Devices { |
| 13 | nvhost_vic::nvhost_vic(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | ||
| 14 | : nvhost_nvdec_common(system, std::move(nvmap_dev)) {} | ||
| 12 | 15 | ||
| 13 | nvhost_vic::nvhost_vic(Core::System& system) : nvdevice(system) {} | ||
| 14 | nvhost_vic::~nvhost_vic() = default; | 16 | nvhost_vic::~nvhost_vic() = default; |
| 15 | 17 | ||
| 16 | u32 nvhost_vic::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 18 | u32 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 | |||
| 43 | u32 nvhost_vic::SetNVMAPfd(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 44 | IoctlSetNvmapFD params{}; | ||
| 45 | std::memcpy(¶ms, 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 | |||
| 52 | u32 nvhost_vic::Submit(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 53 | IoctlSubmit params{}; | ||
| 54 | std::memcpy(¶ms, 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(), ¶ms, sizeof(IoctlSubmit)); | ||
| 61 | return 0; | ||
| 62 | } | ||
| 63 | |||
| 64 | u32 nvhost_vic::GetSyncpoint(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 65 | IoctlGetSyncpoint params{}; | ||
| 66 | std::memcpy(¶ms, 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(), ¶ms, sizeof(IoctlGetSyncpoint)); | ||
| 70 | return 0; | ||
| 71 | } | ||
| 72 | |||
| 73 | u32 nvhost_vic::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 74 | IoctlGetWaitbase params{}; | ||
| 75 | std::memcpy(¶ms, 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(), ¶ms, sizeof(IoctlGetWaitbase)); | ||
| 79 | return 0; | ||
| 80 | } | ||
| 81 | |||
| 82 | u32 nvhost_vic::MapBuffer(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 83 | IoctlMapBuffer params{}; | ||
| 84 | std::memcpy(¶ms, 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(), ¶ms, sizeof(IoctlMapBuffer)); | ||
| 90 | return 0; | ||
| 91 | } | ||
| 92 | |||
| 93 | u32 nvhost_vic::MapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 94 | IoctlMapBufferEx params{}; | ||
| 95 | std::memcpy(¶ms, 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(), ¶ms, sizeof(IoctlMapBufferEx)); | ||
| 101 | return 0; | ||
| 102 | } | ||
| 103 | |||
| 104 | u32 nvhost_vic::UnmapBufferEx(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 105 | IoctlUnmapBufferEx params{}; | ||
| 106 | std::memcpy(¶ms, input.data(), sizeof(IoctlUnmapBufferEx)); | ||
| 107 | LOG_WARNING(Service_NVDRV, "(STUBBED) called"); | ||
| 108 | std::memcpy(output.data(), ¶ms, 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 | ||
| 13 | namespace Service::Nvidia::Devices { | 9 | namespace Service::Nvidia::Devices { |
| 10 | class nvmap; | ||
| 14 | 11 | ||
| 15 | class nvhost_vic final : public nvdevice { | 12 | class nvhost_vic final : public nvhost_nvdec_common { |
| 16 | public: | 13 | public: |
| 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 | ||
| 59 | Module::~Module() = default; | 59 | Module::~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()); |