diff options
Diffstat (limited to 'src')
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | 130 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/devices/nvhost_gpu.h | 19 | ||||
| -rw-r--r-- | src/core/hle/service/nvdrv/nvdrv.cpp | 3 |
3 files changed, 106 insertions, 46 deletions
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp index f1966ac0e..2b9a8722c 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.cpp | |||
| @@ -7,14 +7,17 @@ | |||
| 7 | #include "common/logging/log.h" | 7 | #include "common/logging/log.h" |
| 8 | #include "core/core.h" | 8 | #include "core/core.h" |
| 9 | #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" | 9 | #include "core/hle/service/nvdrv/devices/nvhost_gpu.h" |
| 10 | #include "core/hle/service/nvdrv/syncpoint_manager.h" | ||
| 10 | #include "core/memory.h" | 11 | #include "core/memory.h" |
| 11 | #include "video_core/gpu.h" | 12 | #include "video_core/gpu.h" |
| 12 | #include "video_core/memory_manager.h" | 13 | #include "video_core/memory_manager.h" |
| 13 | 14 | ||
| 14 | namespace Service::Nvidia::Devices { | 15 | namespace Service::Nvidia::Devices { |
| 15 | 16 | ||
| 16 | nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev) | 17 | nvhost_gpu::nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, |
| 17 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)) {} | 18 | SyncpointManager& syncpoint_manager) |
| 19 | : nvdevice(system), nvmap_dev(std::move(nvmap_dev)), syncpoint_manager{syncpoint_manager} {} | ||
| 20 | |||
| 18 | nvhost_gpu::~nvhost_gpu() = default; | 21 | nvhost_gpu::~nvhost_gpu() = default; |
| 19 | 22 | ||
| 20 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 23 | u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| @@ -126,10 +129,9 @@ u32 nvhost_gpu::AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& ou | |||
| 126 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, | 129 | params.num_entries, params.flags, params.unk0, params.unk1, params.unk2, |
| 127 | params.unk3); | 130 | params.unk3); |
| 128 | 131 | ||
| 129 | auto& gpu = system.GPU(); | 132 | params.fence_out.id = syncpoint_manager.AllocateSyncpoint(); |
| 130 | params.fence_out.id = assigned_syncpoints; | 133 | params.fence_out.value = syncpoint_manager.RefreshSyncpoint(params.fence_out.id); |
| 131 | params.fence_out.value = gpu.GetSyncpointValue(assigned_syncpoints); | 134 | |
| 132 | assigned_syncpoints++; | ||
| 133 | std::memcpy(output.data(), ¶ms, output.size()); | 135 | std::memcpy(output.data(), ¶ms, output.size()); |
| 134 | return 0; | 136 | return 0; |
| 135 | } | 137 | } |
| @@ -145,39 +147,97 @@ u32 nvhost_gpu::AllocateObjectContext(const std::vector<u8>& input, std::vector< | |||
| 145 | return 0; | 147 | return 0; |
| 146 | } | 148 | } |
| 147 | 149 | ||
| 148 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { | 150 | static std::vector<Tegra::CommandHeader> BuildWaitCommandList(Fence fence) { |
| 149 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 151 | return { |
| 150 | UNIMPLEMENTED(); | 152 | Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, |
| 153 | Tegra::SubmissionMode::Increasing), | ||
| 154 | {fence.value}, | ||
| 155 | Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1, | ||
| 156 | Tegra::SubmissionMode::Increasing), | ||
| 157 | Tegra::GPU::FenceAction::Build(Tegra::GPU::FenceOperation::Acquire, fence.id), | ||
| 158 | }; | ||
| 159 | } | ||
| 160 | |||
| 161 | static std::vector<Tegra::CommandHeader> BuildIncrementCommandList(Fence fence, u32 add_increment) { | ||
| 162 | std::vector<Tegra::CommandHeader> result{ | ||
| 163 | Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceValue, 1, | ||
| 164 | Tegra::SubmissionMode::Increasing), | ||
| 165 | {}}; | ||
| 166 | |||
| 167 | for (u32 count = 0; count < add_increment; ++count) { | ||
| 168 | result.emplace_back(Tegra::BuildCommandHeader(Tegra::BufferMethods::FenceAction, 1, | ||
| 169 | Tegra::SubmissionMode::Increasing)); | ||
| 170 | result.emplace_back( | ||
| 171 | Tegra::GPU::FenceAction::Build(Tegra::GPU::FenceOperation::Increment, fence.id)); | ||
| 151 | } | 172 | } |
| 152 | IoctlSubmitGpfifo params{}; | ||
| 153 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | ||
| 154 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, | ||
| 155 | params.num_entries, params.flags.raw); | ||
| 156 | 173 | ||
| 157 | ASSERT_MSG(input.size() == sizeof(IoctlSubmitGpfifo) + | 174 | return result; |
| 158 | params.num_entries * sizeof(Tegra::CommandListHeader), | 175 | } |
| 159 | "Incorrect input size"); | ||
| 160 | 176 | ||
| 161 | Tegra::CommandList entries(params.num_entries); | 177 | static std::vector<Tegra::CommandHeader> BuildIncrementWithWfiCommandList(Fence fence, |
| 162 | std::memcpy(entries.data(), &input[sizeof(IoctlSubmitGpfifo)], | 178 | u32 add_increment) { |
| 163 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 179 | std::vector<Tegra::CommandHeader> result{ |
| 180 | Tegra::BuildCommandHeader(Tegra::BufferMethods::WaitForInterrupt, 1, | ||
| 181 | Tegra::SubmissionMode::Increasing), | ||
| 182 | {}}; | ||
| 183 | const std::vector<Tegra::CommandHeader> increment{ | ||
| 184 | BuildIncrementCommandList(fence, add_increment)}; | ||
| 185 | |||
| 186 | result.insert(result.end(), increment.begin(), increment.end()); | ||
| 187 | |||
| 188 | return result; | ||
| 189 | } | ||
| 164 | 190 | ||
| 165 | UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); | 191 | u32 nvhost_gpu::SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, |
| 166 | UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); | 192 | Tegra::CommandList&& entries) { |
| 193 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, | ||
| 194 | params.num_entries, params.flags.raw); | ||
| 167 | 195 | ||
| 168 | auto& gpu = system.GPU(); | 196 | auto& gpu = system.GPU(); |
| 169 | u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id); | 197 | if (params.flags.add_wait.Value() && |
| 170 | if (params.flags.increment.Value()) { | 198 | !syncpoint_manager.IsSyncpointExpired(params.fence_out.id, params.fence_out.value)) { |
| 171 | params.fence_out.value += current_syncpoint_value; | 199 | gpu.PushGPUEntries(Tegra::CommandList{BuildWaitCommandList(params.fence_out)}); |
| 200 | } | ||
| 201 | |||
| 202 | if (params.flags.add_increment.Value() || params.flags.increment.Value()) { | ||
| 203 | const u32 increment_value = params.flags.increment.Value() ? params.fence_out.value : 0; | ||
| 204 | params.fence_out.value = syncpoint_manager.IncreaseSyncpoint( | ||
| 205 | params.fence_out.id, params.AddIncrementValue() + increment_value); | ||
| 172 | } else { | 206 | } else { |
| 173 | params.fence_out.value = current_syncpoint_value; | 207 | params.fence_out.value = syncpoint_manager.GetSyncpointMax(params.fence_out.id); |
| 174 | } | 208 | } |
| 209 | |||
| 210 | entries.RefreshIntegrityChecks(gpu); | ||
| 175 | gpu.PushGPUEntries(std::move(entries)); | 211 | gpu.PushGPUEntries(std::move(entries)); |
| 176 | 212 | ||
| 213 | if (params.flags.add_increment.Value()) { | ||
| 214 | if (params.flags.suppress_wfi) { | ||
| 215 | gpu.PushGPUEntries(Tegra::CommandList{ | ||
| 216 | BuildIncrementCommandList(params.fence_out, params.AddIncrementValue())}); | ||
| 217 | } else { | ||
| 218 | gpu.PushGPUEntries(Tegra::CommandList{ | ||
| 219 | BuildIncrementWithWfiCommandList(params.fence_out, params.AddIncrementValue())}); | ||
| 220 | } | ||
| 221 | } | ||
| 222 | |||
| 177 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); | 223 | std::memcpy(output.data(), ¶ms, sizeof(IoctlSubmitGpfifo)); |
| 178 | return 0; | 224 | return 0; |
| 179 | } | 225 | } |
| 180 | 226 | ||
| 227 | u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output) { | ||
| 228 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | ||
| 229 | UNIMPLEMENTED(); | ||
| 230 | } | ||
| 231 | IoctlSubmitGpfifo params{}; | ||
| 232 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | ||
| 233 | |||
| 234 | Tegra::CommandList entries(params.num_entries); | ||
| 235 | std::memcpy(entries.command_lists.data(), &input[sizeof(IoctlSubmitGpfifo)], | ||
| 236 | params.num_entries * sizeof(Tegra::CommandListHeader)); | ||
| 237 | |||
| 238 | return SubmitGPFIFOImpl(params, output, std::move(entries)); | ||
| 239 | } | ||
| 240 | |||
| 181 | u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, | 241 | u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, |
| 182 | const std::vector<u8>& input2, IoctlVersion version) { | 242 | const std::vector<u8>& input2, IoctlVersion version) { |
| 183 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { | 243 | if (input.size() < sizeof(IoctlSubmitGpfifo)) { |
| @@ -185,31 +245,17 @@ u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, | |||
| 185 | } | 245 | } |
| 186 | IoctlSubmitGpfifo params{}; | 246 | IoctlSubmitGpfifo params{}; |
| 187 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); | 247 | std::memcpy(¶ms, input.data(), sizeof(IoctlSubmitGpfifo)); |
| 188 | LOG_TRACE(Service_NVDRV, "called, gpfifo={:X}, num_entries={:X}, flags={:X}", params.address, | ||
| 189 | params.num_entries, params.flags.raw); | ||
| 190 | 248 | ||
| 191 | Tegra::CommandList entries(params.num_entries); | 249 | Tegra::CommandList entries(params.num_entries); |
| 192 | if (version == IoctlVersion::Version2) { | 250 | if (version == IoctlVersion::Version2) { |
| 193 | std::memcpy(entries.data(), input2.data(), | 251 | std::memcpy(entries.command_lists.data(), input2.data(), |
| 194 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 252 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 195 | } else { | 253 | } else { |
| 196 | system.Memory().ReadBlock(params.address, entries.data(), | 254 | system.Memory().ReadBlock(params.address, entries.command_lists.data(), |
| 197 | params.num_entries * sizeof(Tegra::CommandListHeader)); | 255 | params.num_entries * sizeof(Tegra::CommandListHeader)); |
| 198 | } | 256 | } |
| 199 | UNIMPLEMENTED_IF(params.flags.add_wait.Value() != 0); | ||
| 200 | UNIMPLEMENTED_IF(params.flags.add_increment.Value() != 0); | ||
| 201 | 257 | ||
| 202 | auto& gpu = system.GPU(); | 258 | return SubmitGPFIFOImpl(params, output, std::move(entries)); |
| 203 | u32 current_syncpoint_value = gpu.GetSyncpointValue(params.fence_out.id); | ||
| 204 | if (params.flags.increment.Value()) { | ||
| 205 | params.fence_out.value += current_syncpoint_value; | ||
| 206 | } else { | ||
| 207 | params.fence_out.value = current_syncpoint_value; | ||
| 208 | } | ||
| 209 | gpu.PushGPUEntries(std::move(entries)); | ||
| 210 | |||
| 211 | std::memcpy(output.data(), ¶ms, output.size()); | ||
| 212 | return 0; | ||
| 213 | } | 259 | } |
| 214 | 260 | ||
| 215 | u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { | 261 | u32 nvhost_gpu::GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output) { |
diff --git a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h index 2ac74743f..80054510f 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_gpu.h | |||
| @@ -11,6 +11,11 @@ | |||
| 11 | #include "common/swap.h" | 11 | #include "common/swap.h" |
| 12 | #include "core/hle/service/nvdrv/devices/nvdevice.h" | 12 | #include "core/hle/service/nvdrv/devices/nvdevice.h" |
| 13 | #include "core/hle/service/nvdrv/nvdata.h" | 13 | #include "core/hle/service/nvdrv/nvdata.h" |
| 14 | #include "video_core/dma_pusher.h" | ||
| 15 | |||
| 16 | namespace Service::Nvidia { | ||
| 17 | class SyncpointManager; | ||
| 18 | } | ||
| 14 | 19 | ||
| 15 | namespace Service::Nvidia::Devices { | 20 | namespace Service::Nvidia::Devices { |
| 16 | 21 | ||
| @@ -21,7 +26,8 @@ constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b); | |||
| 21 | 26 | ||
| 22 | class nvhost_gpu final : public nvdevice { | 27 | class nvhost_gpu final : public nvdevice { |
| 23 | public: | 28 | public: |
| 24 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev); | 29 | explicit nvhost_gpu(Core::System& system, std::shared_ptr<nvmap> nvmap_dev, |
| 30 | SyncpointManager& syncpoint_manager); | ||
| 25 | ~nvhost_gpu() override; | 31 | ~nvhost_gpu() override; |
| 26 | 32 | ||
| 27 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, | 33 | u32 ioctl(Ioctl command, const std::vector<u8>& input, const std::vector<u8>& input2, |
| @@ -162,10 +168,15 @@ private: | |||
| 162 | u32_le raw; | 168 | u32_le raw; |
| 163 | BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list | 169 | BitField<0, 1, u32_le> add_wait; // append a wait sync_point to the list |
| 164 | BitField<1, 1, u32_le> add_increment; // append an increment to the list | 170 | BitField<1, 1, u32_le> add_increment; // append an increment to the list |
| 165 | BitField<2, 1, u32_le> new_hw_format; // Mostly ignored | 171 | BitField<2, 1, u32_le> new_hw_format; // mostly ignored |
| 172 | BitField<4, 1, u32_le> suppress_wfi; // suppress wait for interrupt | ||
| 166 | BitField<8, 1, u32_le> increment; // increment the returned fence | 173 | BitField<8, 1, u32_le> increment; // increment the returned fence |
| 167 | } flags; | 174 | } flags; |
| 168 | Fence fence_out; // returned new fence object for others to wait on | 175 | Fence fence_out; // returned new fence object for others to wait on |
| 176 | |||
| 177 | u32 AddIncrementValue() const { | ||
| 178 | return flags.add_increment.Value() << 1; | ||
| 179 | } | ||
| 169 | }; | 180 | }; |
| 170 | static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence), | 181 | static_assert(sizeof(IoctlSubmitGpfifo) == 16 + sizeof(Fence), |
| 171 | "IoctlSubmitGpfifo is incorrect size"); | 182 | "IoctlSubmitGpfifo is incorrect size"); |
| @@ -190,6 +201,8 @@ private: | |||
| 190 | u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); | 201 | u32 SetChannelPriority(const std::vector<u8>& input, std::vector<u8>& output); |
| 191 | u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); | 202 | u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); |
| 192 | u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); | 203 | u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); |
| 204 | u32 SubmitGPFIFOImpl(IoctlSubmitGpfifo& params, std::vector<u8>& output, | ||
| 205 | Tegra::CommandList&& entries); | ||
| 193 | u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); | 206 | u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); |
| 194 | u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, | 207 | u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output, |
| 195 | const std::vector<u8>& input2, IoctlVersion version); | 208 | const std::vector<u8>& input2, IoctlVersion version); |
| @@ -198,7 +211,7 @@ private: | |||
| 198 | u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); | 211 | u32 ChannelSetTimeslice(const std::vector<u8>& input, std::vector<u8>& output); |
| 199 | 212 | ||
| 200 | std::shared_ptr<nvmap> nvmap_dev; | 213 | std::shared_ptr<nvmap> nvmap_dev; |
| 201 | u32 assigned_syncpoints{}; | 214 | SyncpointManager& syncpoint_manager; |
| 202 | }; | 215 | }; |
| 203 | 216 | ||
| 204 | } // namespace Service::Nvidia::Devices | 217 | } // namespace Service::Nvidia::Devices |
diff --git a/src/core/hle/service/nvdrv/nvdrv.cpp b/src/core/hle/service/nvdrv/nvdrv.cpp index 2e52f8bd6..a46755cdc 100644 --- a/src/core/hle/service/nvdrv/nvdrv.cpp +++ b/src/core/hle/service/nvdrv/nvdrv.cpp | |||
| @@ -47,7 +47,8 @@ Module::Module(Core::System& system) : syncpoint_manager{system.GPU()} { | |||
| 47 | } | 47 | } |
| 48 | auto nvmap_dev = std::make_shared<Devices::nvmap>(system); | 48 | auto nvmap_dev = std::make_shared<Devices::nvmap>(system); |
| 49 | devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev); | 49 | devices["/dev/nvhost-as-gpu"] = std::make_shared<Devices::nvhost_as_gpu>(system, nvmap_dev); |
| 50 | devices["/dev/nvhost-gpu"] = std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev); | 50 | devices["/dev/nvhost-gpu"] = |
| 51 | std::make_shared<Devices::nvhost_gpu>(system, nvmap_dev, syncpoint_manager); | ||
| 51 | devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(system); | 52 | devices["/dev/nvhost-ctrl-gpu"] = std::make_shared<Devices::nvhost_ctrl_gpu>(system); |
| 52 | devices["/dev/nvmap"] = nvmap_dev; | 53 | devices["/dev/nvmap"] = nvmap_dev; |
| 53 | devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev); | 54 | devices["/dev/nvdisp_disp0"] = std::make_shared<Devices::nvdisp_disp0>(system, nvmap_dev); |