From 12a690e15fd28d77e6d4cc970d306f2fe0e99217 Mon Sep 17 00:00:00 2001 From: lizzie Date: Mon, 21 Jul 2025 04:35:43 +0200 Subject: [PATCH] [nvdrv] ZBC table implement stubs (#83) 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 Co-committed-by: lizzie --- .../service/nvdrv/devices/nvhost_ctrl_gpu.cpp | 83 ++++++++++++++++++- .../service/nvdrv/devices/nvhost_ctrl_gpu.h | 22 +++++ 2 files changed, 101 insertions(+), 4 deletions(-) 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 1b8f575586..45a4a402da 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -35,6 +35,7 @@ NvResult nvhost_ctrl_gpu::Ioctl1(DeviceFD fd, Ioctl command, std::span 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 } 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; } 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 d2ab05b214..c36fcbaa69 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -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 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 color_entries; + std::array depth_entries; + u8 max_color_entries; + u8 max_depth_entries; }; } // namespace Service::Nvidia::Devices