GPU: Implement the NVGPU_IOCTL_CHANNEL_KICKOFF_PB ioctl2 command.

This behaves quite similarly to the SubmitGPFIFO command. Referenced from Ryujinx.
Many thanks to @gdkchan for investigating this!
This commit is contained in:
Subv 2018-07-21 15:50:02 -05:00
parent 0f20fa5a1e
commit 5c49e56d41
3 changed files with 34 additions and 6 deletions

View file

@ -42,6 +42,9 @@ u32 nvhost_gpu::ioctl(Ioctl command, const std::vector<u8>& input, std::vector<u
if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) { if (command.cmd == NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO) {
return SubmitGPFIFO(input, output); return SubmitGPFIFO(input, output);
} }
if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) {
return KickoffPB(input, output);
}
} }
UNIMPLEMENTED_MSG("Unimplemented ioctl"); UNIMPLEMENTED_MSG("Unimplemented ioctl");
@ -127,14 +130,37 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
IoctlSubmitGpfifo params{}; IoctlSubmitGpfifo params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo)); std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}", LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
params.gpfifo, params.num_entries, params.flags); params.address, params.num_entries, params.flags);
auto entries = std::vector<IoctlGpfifoEntry>(); auto entries = std::vector<IoctlGpfifoEntry>();
entries.resize(params.num_entries); entries.resize(params.num_entries);
std::memcpy(&entries[0], &input.data()[sizeof(IoctlSubmitGpfifo)], std::memcpy(&entries[0], &input.data()[sizeof(IoctlSubmitGpfifo)],
params.num_entries * sizeof(IoctlGpfifoEntry)); params.num_entries * sizeof(IoctlGpfifoEntry));
for (auto entry : entries) { for (auto entry : entries) {
VAddr va_addr = entry.Address(); Tegra::GPUVAddr va_addr = entry.Address();
Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz);
}
params.fence_out.id = 0;
params.fence_out.value = 0;
std::memcpy(output.data(), &params, output.size());
return 0;
}
u32 nvhost_gpu::KickoffPB(const std::vector<u8>& input, std::vector<u8>& output) {
if (input.size() < sizeof(IoctlSubmitGpfifo)) {
UNIMPLEMENTED();
}
IoctlSubmitGpfifo params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
LOG_WARNING(Service_NVDRV, "(STUBBED) called, gpfifo={:X}, num_entries={:X}, flags={:X}",
params.address, params.num_entries, params.flags);
std::vector<IoctlGpfifoEntry> entries(params.num_entries);
Memory::ReadBlock(params.address, entries.data(),
params.num_entries * sizeof(IoctlGpfifoEntry));
for (auto entry : entries) {
Tegra::GPUVAddr va_addr = entry.Address();
Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz); Core::System::GetInstance().GPU().ProcessCommandList(va_addr, entry.sz);
} }
params.fence_out.id = 0; params.fence_out.id = 0;

View file

@ -15,6 +15,7 @@ namespace Service::Nvidia::Devices {
class nvmap; class nvmap;
constexpr u32 NVGPU_IOCTL_MAGIC('H'); constexpr u32 NVGPU_IOCTL_MAGIC('H');
constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8); constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8);
constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b);
class nvhost_gpu final : public nvdevice { class nvhost_gpu final : public nvdevice {
public: public:
@ -158,14 +159,14 @@ private:
BitField<31, 1, u32_le> unk2; BitField<31, 1, u32_le> unk2;
}; };
VAddr Address() const { Tegra::GPUVAddr Address() const {
return (static_cast<VAddr>(gpu_va_hi) << 32) | entry0; return (static_cast<Tegra::GPUVAddr>(gpu_va_hi) << 32) | entry0;
} }
}; };
static_assert(sizeof(IoctlGpfifoEntry) == 8, "IoctlGpfifoEntry is incorrect size"); static_assert(sizeof(IoctlGpfifoEntry) == 8, "IoctlGpfifoEntry is incorrect size");
struct IoctlSubmitGpfifo { struct IoctlSubmitGpfifo {
u64_le gpfifo; // (ignored) pointer to gpfifo fence structs u64_le address; // pointer to gpfifo entry structs
u32_le num_entries; // number of fence objects being submitted u32_le num_entries; // number of fence objects being submitted
u32_le flags; u32_le flags;
IoctlFence fence_out; // returned new fence object for others to wait on IoctlFence fence_out; // returned new fence object for others to wait on
@ -193,6 +194,7 @@ private:
u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output); u32 AllocGPFIFOEx2(const std::vector<u8>& input, std::vector<u8>& output);
u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output); u32 AllocateObjectContext(const std::vector<u8>& input, std::vector<u8>& output);
u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output); u32 SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& output);
u32 KickoffPB(const std::vector<u8>& input, std::vector<u8>& output);
u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output); u32 GetWaitbase(const std::vector<u8>& input, std::vector<u8>& output);
u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output); u32 ChannelSetTimeout(const std::vector<u8>& input, std::vector<u8>& output);

View file

@ -101,7 +101,7 @@ NVDRV::NVDRV(std::shared_ptr<Module> nvdrv, const char* name)
{8, &NVDRV::SetClientPID, "SetClientPID"}, {8, &NVDRV::SetClientPID, "SetClientPID"},
{9, nullptr, "DumpGraphicsMemoryInfo"}, {9, nullptr, "DumpGraphicsMemoryInfo"},
{10, nullptr, "InitializeDevtools"}, {10, nullptr, "InitializeDevtools"},
{11, nullptr, "Ioctl2"}, {11, &NVDRV::Ioctl, "Ioctl2"},
{12, nullptr, "Ioctl3"}, {12, nullptr, "Ioctl3"},
{13, &NVDRV::FinishInitialize, "FinishInitialize"}, {13, &NVDRV::FinishInitialize, "FinishInitialize"},
}; };