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 76a07f22b..432f66554 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.cpp @@ -13,6 +13,57 @@ namespace Service::Nvidia::Devices { +// ZBC helper functions for GPU clearing operations +namespace ZBC { + std::optional> GetColor(u32 format, u32 type) { + return ZBCManager::Instance().GetZBCColor(format, type); + } + + std::optional GetDepth(u32 format, u32 type) { + return ZBCManager::Instance().GetZBCDepth(format, type); + } +} + +// ZBCManager implementation +std::optional> ZBCManager::GetZBCColor(u32 format, u32 type) const { + std::scoped_lock lock{zbc_table_mutex}; + const auto key = std::make_pair(format, type); + const auto it = zbc_table.find(key); + if (it != zbc_table.end()) { + return it->second.color_ds; + } + return std::nullopt; +} + +std::optional ZBCManager::GetZBCDepth(u32 format, u32 type) const { + std::scoped_lock lock{zbc_table_mutex}; + const auto key = std::make_pair(format, type); + const auto it = zbc_table.find(key); + if (it != zbc_table.end()) { + return it->second.depth; + } + return std::nullopt; +} + +void ZBCManager::StoreZBCEntry(u32 format, u32 type, const std::array& color_ds, + const std::array& color_l2, u32 depth) { + std::scoped_lock lock{zbc_table_mutex}; + + ZBCEntry entry; + entry.color_ds = color_ds; + entry.color_l2 = color_l2; + entry.depth = depth; + entry.format = format; + entry.type = type; + entry.ref_count = 1; + + const auto key = std::make_pair(format, type); + zbc_table[key] = entry; + + LOG_DEBUG(Service_NVDRV, "Global ZBCManager: Stored entry format=0x{:X}, type=0x{:X}, depth=0x{:X}", + format, type, depth); +} + nvhost_ctrl_gpu::nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_) : nvdevice{system_}, events_interface{events_interface_} { error_notifier_event = events_interface.CreateEvent("CtrlGpuErrorNotifier"); @@ -90,6 +141,46 @@ NvResult nvhost_ctrl_gpu::Ioctl3(DeviceFD fd, Ioctl command, std::span void nvhost_ctrl_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {} void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {} +// ZBC table management methods +std::optional> nvhost_ctrl_gpu::GetZBCColor(u32 format, u32 type) const { + return ZBCManager::Instance().GetZBCColor(format, type); +} + +std::optional nvhost_ctrl_gpu::GetZBCDepth(u32 format, u32 type) const { + return ZBCManager::Instance().GetZBCDepth(format, type); +} + +void nvhost_ctrl_gpu::StoreZBCEntry(const IoctlZbcSetTable& params) { + // Store in both local table and global manager + std::scoped_lock lock{zbc_table_mutex}; + + ZBCEntry entry; + std::memcpy(entry.color_ds.data(), params.color_ds, sizeof(params.color_ds)); + std::memcpy(entry.color_l2.data(), params.color_l2, sizeof(params.color_l2)); + entry.depth = params.depth; + entry.format = params.format; + entry.type = params.type; + entry.ref_count = 1; + + const auto key = std::make_pair(params.format, params.type); + zbc_table[key] = entry; + + // Also store in global ZBCManager for GPU access + ZBCManager::Instance().StoreZBCEntry(params.format, params.type, entry.color_ds, entry.color_l2, params.depth); + + LOG_DEBUG(Service_NVDRV, "Stored ZBC entry: format=0x{:X}, type=0x{:X}, depth=0x{:X}", + params.format, params.type, params.depth); +} + +std::optional nvhost_ctrl_gpu::FindZBCEntry(u32 format, u32 type) const { + const auto key = std::make_pair(format, type); + const auto it = zbc_table.find(key); + if (it != zbc_table.end()) { + return it->second; + } + return std::nullopt; +} + NvResult nvhost_ctrl_gpu::GetCharacteristics1(IoctlCharacteristics& params) { LOG_DEBUG(Service_NVDRV, "called"); params.gc.arch = 0x120; @@ -246,17 +337,44 @@ NvResult nvhost_ctrl_gpu::ZBCSetTable(IoctlZbcSetTable& params) { return NvResult::BadParameter; } + // Store the ZBC entry in our table for later use during GPU clearing operations + StoreZBCEntry(params); + // Log the color values for debugging LOG_DEBUG(Service_NVDRV, "ZBC color_ds: [0x{:08X}, 0x{:08X}, 0x{:08X}, 0x{:08X}]", params.color_ds[0], params.color_ds[1], params.color_ds[2], params.color_ds[3]); LOG_DEBUG(Service_NVDRV, "ZBC color_l2: [0x{:08X}, 0x{:08X}, 0x{:08X}, 0x{:08X}]", - params.color_l2[0], params.color_l2[1], params.color_l2[2], params.color_l2[3]); + params.color_ds[0], params.color_ds[1], params.color_ds[2], params.color_ds[3]); return NvResult::Success; } NvResult nvhost_ctrl_gpu::ZBCQueryTable(IoctlZbcQueryTable& params) { - LOG_WARNING(Service_NVDRV, "(STUBBED) called"); + LOG_DEBUG(Service_NVDRV, "called, format=0x{:X}, type=0x{:X}", params.format, params.type); + + // Query ZBC table entry + const auto entry = FindZBCEntry(params.format, params.type); + if (entry) { + std::memcpy(params.color_ds, entry->color_ds.data(), sizeof(params.color_ds)); + std::memcpy(params.color_l2, entry->color_l2.data(), sizeof(params.color_l2)); + params.depth = entry->depth; + params.ref_cnt = entry->ref_count; + params.format = entry->format; + params.type = entry->type; + params.index_size = 1; // Entry found + LOG_DEBUG(Service_NVDRV, "ZBC query successful, ref_count={}", entry->ref_count); + } else { + // Clear output if entry not found + std::memset(params.color_ds, 0, sizeof(params.color_ds)); + std::memset(params.color_l2, 0, sizeof(params.color_l2)); + params.depth = 0; + params.ref_cnt = 0; + params.format = params.format; // Keep original format + params.type = params.type; // Keep original type + params.index_size = 0; // No entry found + LOG_DEBUG(Service_NVDRV, "ZBC query: entry not found"); + } + 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 d2ab05b21..66c8e2815 100644 --- a/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h +++ b/src/core/hle/service/nvdrv/devices/nvhost_ctrl_gpu.h @@ -1,14 +1,19 @@ // SPDX-FileCopyrightText: Copyright 2018 yuzu Emulator Project +// SPDX-FileCopyrightText: Copyright 2025 citron Emulator Project // SPDX-License-Identifier: GPL-2.0-or-later #pragma once +#include +#include +#include +#include +#include #include -#include "common/common_funcs.h" #include "common/common_types.h" -#include "common/swap.h" #include "core/hle/service/nvdrv/devices/nvdevice.h" +#include "core/hle/service/nvdrv/nvdata.h" namespace Service::Nvidia { class EventInterface; @@ -16,6 +21,49 @@ class EventInterface; namespace Service::Nvidia::Devices { +// Global ZBC manager for GPU memory management integration +class ZBCManager { +public: + static ZBCManager& Instance() { + static ZBCManager instance; + return instance; + } + + // ZBC table entry structure + struct ZBCEntry { + std::array color_ds; + std::array color_l2; + u32 depth; + u32 format; + u32 type; + u32 ref_count; + }; + + // ZBC table access methods for GPU clearing operations + std::optional> GetZBCColor(u32 format, u32 type) const; + std::optional GetZBCDepth(u32 format, u32 type) const; + + // Store ZBC entry (called by nvhost_ctrl_gpu) + void StoreZBCEntry(u32 format, u32 type, const std::array& color_ds, + const std::array& color_l2, u32 depth); + +private: + ZBCManager() = default; + ~ZBCManager() = default; + ZBCManager(const ZBCManager&) = delete; + ZBCManager& operator=(const ZBCManager&) = delete; + + mutable std::mutex zbc_table_mutex; + std::map, ZBCEntry> zbc_table; // Key: (format, type) +}; + +// Forward declaration for external access +namespace ZBC { + // Helper functions for GPU clearing operations + std::optional> GetColor(u32 format, u32 type); + std::optional GetDepth(u32 format, u32 type); +} + class nvhost_ctrl_gpu final : public nvdevice { public: explicit nvhost_ctrl_gpu(Core::System& system_, EventInterface& events_interface_); @@ -25,53 +73,57 @@ public: std::span output) override; NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span input, std::span inline_input, std::span output) override; - NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, std::span output, - std::span inline_output) override; + NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span input, + std::span output, std::span inline_output) override; void OnOpen(NvCore::SessionId session_id, DeviceFD fd) override; void OnClose(DeviceFD fd) override; Kernel::KEvent* QueryEvent(u32 event_id) override; + // ZBC table management methods + std::optional> GetZBCColor(u32 format, u32 type) const; + std::optional GetZBCDepth(u32 format, u32 type) const; + private: struct IoctlGpuCharacteristics { - u32_le arch; // 0x120 (NVGPU_GPU_ARCH_GM200) - u32_le impl; // 0xB (NVGPU_GPU_IMPL_GM20B) - u32_le rev; // 0xA1 (Revision A1) - u32_le num_gpc; // 0x1 - u64_le l2_cache_size; // 0x40000 - u64_le on_board_video_memory_size; // 0x0 (not used) - u32_le num_tpc_per_gpc; // 0x2 - u32_le bus_type; // 0x20 (NVGPU_GPU_BUS_TYPE_AXI) - u32_le big_page_size; // 0x20000 - u32_le compression_page_size; // 0x20000 - u32_le pde_coverage_bit_count; // 0x1B - u32_le available_big_page_sizes; // 0x30000 - u32_le gpc_mask; // 0x1 - u32_le sm_arch_sm_version; // 0x503 (Maxwell Generation 5.0.3?) - u32_le sm_arch_spa_version; // 0x503 (Maxwell Generation 5.0.3?) - u32_le sm_arch_warp_count; // 0x80 - u32_le gpu_va_bit_count; // 0x28 - u32_le reserved; // NULL - u64_le flags; // 0x55 - u32_le twod_class; // 0x902D (FERMI_TWOD_A) - u32_le threed_class; // 0xB197 (MAXWELL_B) - u32_le compute_class; // 0xB1C0 (MAXWELL_COMPUTE_B) - u32_le gpfifo_class; // 0xB06F (MAXWELL_CHANNEL_GPFIFO_A) - u32_le inline_to_memory_class; // 0xA140 (KEPLER_INLINE_TO_MEMORY_B) - u32_le dma_copy_class; // 0xB0B5 (MAXWELL_DMA_COPY_A) - u32_le max_fbps_count; // 0x1 - u32_le fbp_en_mask; // 0x0 (disabled) - u32_le max_ltc_per_fbp; // 0x2 - u32_le max_lts_per_ltc; // 0x1 - u32_le max_tex_per_tpc; // 0x0 (not supported) - u32_le max_gpc_count; // 0x1 - u32_le rop_l2_en_mask_0; // 0x21D70 (fuse_status_opt_rop_l2_fbp_r) - u32_le rop_l2_en_mask_1; // 0x0 - u64_le chipname; // 0x6230326D67 ("gm20b") - u64_le gr_compbit_store_base_hw; // 0x0 (not supported) + u32_le arch; + u32_le impl; + u32_le rev; + u32_le num_gpc; + u64_le l2_cache_size; + u64_le on_board_video_memory_size; + u32_le num_tpc_per_gpc; + u32_le bus_type; + u32_le big_page_size; + u32_le compression_page_size; + u32_le pde_coverage_bit_count; + u32_le available_big_page_sizes; + u32_le gpc_mask; + u32_le sm_arch_sm_version; + u32_le sm_arch_spa_version; + u32_le sm_arch_warp_count; + u32_le gpu_va_bit_count; + u32_le reserved; + u64_le flags; + u32_le twod_class; + u32_le threed_class; + u32_le compute_class; + u32_le gpfifo_class; + u32_le inline_to_memory_class; + u32_le dma_copy_class; + u32_le max_fbps_count; + u32_le fbp_en_mask; + u32_le max_ltc_per_fbp; + u32_le max_lts_per_ltc; + u32_le max_tex_per_tpc; + u32_le max_gpc_count; + u32_le rop_l2_en_mask_0; + u32_le rop_l2_en_mask_1; + u64_le chipname; + u32_le gr_compbit_store_base_hw; }; - static_assert(sizeof(IoctlGpuCharacteristics) == 160, + static_assert(sizeof(IoctlGpuCharacteristics) == 0xA0, "IoctlGpuCharacteristics is incorrect size"); struct IoctlCharacteristics { @@ -151,6 +203,24 @@ private: }; static_assert(sizeof(IoctlGetGpuTime) == 0x10, "IoctlGetGpuTime is incorrect size"); + // ZBC table entry structure + struct ZBCEntry { + std::array color_ds; + std::array color_l2; + u32 depth; + u32 format; + u32 type; + u32 ref_count; + }; + + // ZBC table storage + mutable std::mutex zbc_table_mutex; + std::map, ZBCEntry> zbc_table; // Key: (format, type) + + // ZBC table management + void StoreZBCEntry(const IoctlZbcSetTable& params); + std::optional FindZBCEntry(u32 format, u32 type) const; + NvResult GetCharacteristics1(IoctlCharacteristics& params); NvResult GetCharacteristics3(IoctlCharacteristics& params, std::span gpu_characteristics);