mirror of
https://git.citron-emu.org/citron/emulator
synced 2026-01-07 10:23:53 +00:00
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:
@@ -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;
|
||||
}
|
||||
|
||||
|
||||
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user