[nvdrv] ZBC table implement stubs (#83)
All checks were successful
eden-build / source (push) Successful in 6m32s
eden-build / linux (push) Successful in 27m5s
eden-build / windows (msvc) (push) Successful in 30m4s
eden-build / android (push) Successful in 32m46s

Reviewed-on: https://git.eden-emu.dev/eden-emu/eden/pulls/83

This commit introduces an implementation for `ZBCSetTable` in `nvhost_ctrl_gpu`, which is invoked by games and system services to configure default clear values for depth, stencil, and color attachments on the GPU, allowing better instructions on how the ZCull Block Compression expects to work within the emulated GPU.

This is an important step for compatibility with titles or system modules that expect ZBC configuration support.
Co-authored-by: lizzie <lizzie@eden-emu.dev>
Co-committed-by: lizzie <lizzie@eden-emu.dev>
This commit is contained in:
lizzie 2025-07-21 04:35:43 +02:00 committed by crueter
parent e8e0d7fa20
commit 12a690e15f
No known key found for this signature in database
GPG key ID: 425ACD2D4830EBC6
2 changed files with 101 additions and 4 deletions

View file

@ -35,6 +35,7 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8>
return WrapFixed(this, &nvhost_ctrl_gpu::ZBCSetTable, input, output);
case 0x4:
return WrapFixed(this, &nvhost_ctrl_gpu::ZBCQueryTable, input, output);
//deviation
case 0x5:
return WrapFixed(this, &nvhost_ctrl_gpu::GetCharacteristics1, input, output);
case 0x6:
@ -50,7 +51,29 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span<const u8>
}
break;
}
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X}", command.raw);
// still unimplemented
std::string_view friendly_name = [raw = command.raw]() {
switch (raw) {
case 0x0d: return "INVAL_ICACHE";
case 0x0e: return "SET_MMU_DEBUG_MODE ";
case 0x0f: return "SET_SM_DEBUG_MODE";
case 0x10: return "WAIT_FOR_PAUSE";
case 0x11: return "GET_TPC_EXCEPTION_EN_STATUS";
case 0x12: return "NUM_VSMS";
case 0x13: return "VSMS_MAPPING";
case 0x14: return "ZBC_GET_ACTIVE_SLOT_MASK";
case 0x15: return "PMU_GET_GPU_LOAD";
case 0x16: return "SET_CG_CONTROLS";
case 0x17: return "GET_CG_CONTROLS";
case 0x18: return "SET_PG_CONTROLS";
case 0x19: return "GET_PG_CONTROLS";
case 0x1A: return "PMU_GET_ELPG_RESIDENCY_GATING";
case 0x1B: return "GET_ERROR_CHANNEL_USER_DATA";
case 0x1D: return "GET_CPU_TIME_CORRELATION_INFO";
default: return "UNKNOWN";
}
}();
UNIMPLEMENTED_MSG("Unimplemented ioctl={:08X} {}", command.raw, friendly_name);
return NvResult::NotImplemented;
}
@ -230,18 +253,70 @@ NvResult nvhost_ctrl_gpu::ZCullGetInfo(IoctlNvgpuGpuZcullGetInfoArgs& params) {
}
NvResult nvhost_ctrl_gpu::ZBCSetTable(IoctlZbcSetTable& params) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
LOG_DEBUG(Service_NVDRV, "called");
ZbcEntry entry = {};
std::memset(&entry, 0, sizeof(entry));
// TODO(ogniK): What does this even actually do?
// TODO(myself): This thing I guess
if (params.type == 1) {
for (auto i = 0; i < 4; ++i) {
entry.color_ds[i] = params.color_ds[i];
entry.color_l2[i] = params.color_l2[i];
}
ASSERT(this->max_color_entries < 16);
this->color_entries[this->max_color_entries] = entry;
++this->max_color_entries;
} else if (params.type == 2) {
entry.depth = params.depth;
ASSERT(this->max_depth_entries < 16);
this->depth_entries[this->max_depth_entries] = entry;
++this->max_depth_entries;
}
return NvResult::Success;
}
NvResult nvhost_ctrl_gpu::ZBCQueryTable(IoctlZbcQueryTable& params) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
LOG_DEBUG(Service_NVDRV, "called");
struct ZbcQueryParams {
u32_le color_ds[4];
u32_le color_l2[4];
u32_le depth;
u32_le ref_cnt;
u32_le format;
u32_le type;
u32_le index_size;
} entry = {};
std::memset(&entry, 0, sizeof(entry));
auto const index = params.index_size;
if (params.type == 0) { //no
entry.index_size = 15;
} else if (params.type == 1) { //color
ASSERT(index < 16);
for (auto i = 0; i < 4; ++i) {
params.color_ds[i] = this->color_entries[index].color_ds[i];
params.color_l2[i] = this->color_entries[index].color_l2[i];
}
// TODO: Only if no error thrown (otherwise dont modify)
params.format = this->color_entries[index].format;
//params.ref_cnt = this->color_entries[index].ref_cnt;
} else if (params.type == 2) { //depth
ASSERT(index < 16);
params.depth = this->depth_entries[index].depth;
// TODO: Only if no error thrown (otherwise dont modify)
params.format = this->depth_entries[index].format;
//params.ref_cnt = this->depth_entries[index].ref_cnt;
} else {
UNREACHABLE();
}
return NvResult::Success;
}
NvResult nvhost_ctrl_gpu::FlushL2(IoctlFlushL2& params) {
LOG_WARNING(Service_NVDRV, "(STUBBED) called");
LOG_DEBUG(Service_NVDRV, "called 0x{:X}", params.flush);
// if ((params.flush & 0x01) != 0) //l2 flush
// /* we dont emulate l2 */;
// if ((params.flush & 0x04) != 0) //fb flush
// /* we dont emulate fb */;
return NvResult::Success;
}

View file

@ -151,6 +151,16 @@ private:
};
static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size");
struct IoctlGetCpuTimeCorrelationInfo {
struct {
u64_le cpu_timestamp;
u64_le gpu_timestamp;
} samples[16];
u32_le count;
u32_le source_id;
};
static_assert(sizeof(IoctlGetCpuTimeCorrelationInfo) == 264);
NvResult GetCharacteristics1(IoctlCharacteristics& params);
NvResult GetCharacteristics3(IoctlCharacteristics& params,
std::span<IoctlGpuCharacteristics> gpu_characteristics);
@ -171,6 +181,18 @@ private:
// Events
Kernel::KEvent* error_notifier_event;
Kernel::KEvent* unknown_event;
struct ZbcEntry {
u32_le color_ds[4];
u32_le color_l2[4];
u32_le depth;
u32_le type;
u32_le format;
};
std::array<ZbcEntry, 16> color_entries;
std::array<ZbcEntry, 16> depth_entries;
u8 max_color_entries;
u8 max_depth_entries;
};
} // namespace Service::Nvidia::Devices