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