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) {
return SubmitGPFIFO(input, output);
}
if (command.cmd == NVGPU_IOCTL_CHANNEL_KICKOFF_PB) {
return KickoffPB(input, output);
}
}
UNIMPLEMENTED_MSG("Unimplemented ioctl");
@ -127,14 +130,37 @@ u32 nvhost_gpu::SubmitGPFIFO(const std::vector<u8>& input, std::vector<u8>& outp
IoctlSubmitGpfifo params{};
std::memcpy(&params, input.data(), sizeof(IoctlSubmitGpfifo));
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>();
entries.resize(params.num_entries);
std::memcpy(&entries[0], &input.data()[sizeof(IoctlSubmitGpfifo)],
params.num_entries * sizeof(IoctlGpfifoEntry));
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);
}
params.fence_out.id = 0;

View file

@ -15,6 +15,7 @@ namespace Service::Nvidia::Devices {
class nvmap;
constexpr u32 NVGPU_IOCTL_MAGIC('H');
constexpr u32 NVGPU_IOCTL_CHANNEL_SUBMIT_GPFIFO(0x8);
constexpr u32 NVGPU_IOCTL_CHANNEL_KICKOFF_PB(0x1b);
class nvhost_gpu final : public nvdevice {
public:
@ -158,14 +159,14 @@ private:
BitField<31, 1, u32_le> unk2;
};
VAddr Address() const {
return (static_cast<VAddr>(gpu_va_hi) << 32) | entry0;
Tegra::GPUVAddr Address() const {
return (static_cast<Tegra::GPUVAddr>(gpu_va_hi) << 32) | entry0;
}
};
static_assert(sizeof(IoctlGpfifoEntry) == 8, "IoctlGpfifoEntry is incorrect size");
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 flags;
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 AllocateObjectContext(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 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"},
{9, nullptr, "DumpGraphicsMemoryInfo"},
{10, nullptr, "InitializeDevtools"},
{11, nullptr, "Ioctl2"},
{11, &NVDRV::Ioctl, "Ioctl2"},
{12, nullptr, "Ioctl3"},
{13, &NVDRV::FinishInitialize, "FinishInitialize"},
};