Merge branch 'zbc-table-management' into 'master'

nvdrv: Implement ZBC table management with GPU memory integration

See merge request citron/rewrite!54
This commit is contained in:
Zephyron
2025-08-25 08:01:12 +00:00
2 changed files with 230 additions and 42 deletions

View File

@@ -13,6 +13,57 @@
namespace Service::Nvidia::Devices {
// ZBC helper functions for GPU clearing operations
namespace ZBC {
std::optional<std::array<u32, 4>> GetColor(u32 format, u32 type) {
return ZBCManager::Instance().GetZBCColor(format, type);
}
std::optional<u32> GetDepth(u32 format, u32 type) {
return ZBCManager::Instance().GetZBCDepth(format, type);
}
}
// ZBCManager implementation
std::optional<std::array<u32, 4>> 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<u32> 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<u32, 4>& color_ds,
const std::array<u32, 4>& 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<const u8>
void nvhost_ctrl_gpu::OnOpen(NvCore::SessionId session_id, DeviceFD fd) {}
void nvhost_ctrl_gpu::OnClose(DeviceFD fd) {}
// ZBC table management methods
std::optional<std::array<u32, 4>> nvhost_ctrl_gpu::GetZBCColor(u32 format, u32 type) const {
return ZBCManager::Instance().GetZBCColor(format, type);
}
std::optional<u32> 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::ZBCEntry> 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;
}

View File

@@ -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 <array>
#include <map>
#include <memory>
#include <mutex>
#include <span>
#include <vector>
#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<u32, 4> color_ds;
std::array<u32, 4> color_l2;
u32 depth;
u32 format;
u32 type;
u32 ref_count;
};
// ZBC table access methods for GPU clearing operations
std::optional<std::array<u32, 4>> GetZBCColor(u32 format, u32 type) const;
std::optional<u32> GetZBCDepth(u32 format, u32 type) const;
// Store ZBC entry (called by nvhost_ctrl_gpu)
void StoreZBCEntry(u32 format, u32 type, const std::array<u32, 4>& color_ds,
const std::array<u32, 4>& 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<std::pair<u32, u32>, ZBCEntry> zbc_table; // Key: (format, type)
};
// Forward declaration for external access
namespace ZBC {
// Helper functions for GPU clearing operations
std::optional<std::array<u32, 4>> GetColor(u32 format, u32 type);
std::optional<u32> 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<u8> output) override;
NvResult Ioctl2(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::span<const u8> inline_input, std::span<u8> output) override;
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input, std::span<u8> output,
std::span<u8> inline_output) override;
NvResult Ioctl3(DeviceFD fd, Ioctl command, std::span<const u8> input,
std::span<u8> output, std::span<u8> 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<std::array<u32, 4>> GetZBCColor(u32 format, u32 type) const;
std::optional<u32> 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<u32, 4> color_ds;
std::array<u32, 4> color_l2;
u32 depth;
u32 format;
u32 type;
u32 ref_count;
};
// ZBC table storage
mutable std::mutex zbc_table_mutex;
std::map<std::pair<u32, u32>, ZBCEntry> zbc_table; // Key: (format, type)
// ZBC table management
void StoreZBCEntry(const IoctlZbcSetTable& params);
std::optional<ZBCEntry> FindZBCEntry(u32 format, u32 type) const;
NvResult GetCharacteristics1(IoctlCharacteristics& params);
NvResult GetCharacteristics3(IoctlCharacteristics& params,
std::span<IoctlGpuCharacteristics> gpu_characteristics);