Compare commits

...

11 Commits

Author SHA1 Message Date
yuzubot
729f72482f Android #170 2023-12-24 00:58:04 +00:00
yuzubot
0ea67a05e2 Merge PR 12394 2023-12-24 00:58:04 +00:00
liamwhite
91290b9be4 Merge pull request #12412 from ameerj/gl-query-prims
OpenGL: Add GL_PRIMITIVES_GENERATED and GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN queries
2023-12-22 11:42:05 -05:00
Fernando S
820f113d9e Merge pull request #12435 from liamwhite/type-check
shader_recompiler: ensure derivatives for textureGrad are f32
2023-12-22 17:41:13 +01:00
Fernando S
373a1ff2ce Merge pull request #12410 from liamwhite/more-mali-null
renderer_vulkan: don't pass null view when nullDescriptor is not supported
2023-12-22 17:40:47 +01:00
Fernando S
4d6b6ba76c Merge pull request #12432 from liamwhite/float-write
shader_recompiler: use float image operations on load/store when required
2023-12-22 17:40:26 +01:00
Liam
4aa713e861 shader_recompiler: ensure derivatives for textureGrad are f32 2023-12-21 19:06:33 -05:00
Liam
9e9aed41be shader_recompiler: use float image operations on load/store when required 2023-12-21 14:34:46 -05:00
Ameer J
61e8c5f798 gl_rasterizer: Less spammy log for unimplemented resets 2023-12-20 11:51:44 -05:00
Ameer J
db8a601cf8 OpenGL: Add GL_PRIMITIVES_GENERATED and GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN queries 2023-12-19 17:32:31 -05:00
Liam
d0a75580da renderer_vulkan: don't pass null view when nullDescriptor is not supported 2023-12-19 15:13:10 -05:00
59 changed files with 1830 additions and 678 deletions

View File

@@ -1,3 +1,12 @@
| Pull Request | Commit | Title | Author | Merged? |
|----|----|----|----|----|
| [12394](https://github.com/yuzu-emu/yuzu//pull/12394) | [`c57ae803a`](https://github.com/yuzu-emu/yuzu//pull/12394/files) | general: properly support multiple memory instances | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break.
-----
<!-- <!--
SPDX-FileCopyrightText: 2018 yuzu Emulator Project SPDX-FileCopyrightText: 2018 yuzu Emulator Project
SPDX-License-Identifier: GPL-2.0-or-later SPDX-License-Identifier: GPL-2.0-or-later

View File

@@ -9,7 +9,7 @@
namespace Core { namespace Core {
void ArmInterface::LogBacktrace(const Kernel::KProcess* process) const { void ArmInterface::LogBacktrace(Kernel::KProcess* process) const {
Kernel::Svc::ThreadContext ctx; Kernel::Svc::ThreadContext ctx;
this->GetContext(ctx); this->GetContext(ctx);

View File

@@ -95,7 +95,7 @@ public:
virtual void SignalInterrupt(Kernel::KThread* thread) = 0; virtual void SignalInterrupt(Kernel::KThread* thread) = 0;
// Stack trace generation. // Stack trace generation.
void LogBacktrace(const Kernel::KProcess* process) const; void LogBacktrace(Kernel::KProcess* process) const;
// Debug functionality. // Debug functionality.
virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0; virtual const Kernel::DebugWatchpoint* HaltedWatchpoint() const = 0;

View File

@@ -79,7 +79,7 @@ constexpr std::array<u64, 2> SegmentBases{
0x7100000000ULL, 0x7100000000ULL,
}; };
void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<BacktraceEntry>& out) { void SymbolicateBacktrace(Kernel::KProcess* process, std::vector<BacktraceEntry>& out) {
auto modules = FindModules(process); auto modules = FindModules(process);
const bool is_64 = process->Is64Bit(); const bool is_64 = process->Is64Bit();
@@ -118,7 +118,7 @@ void SymbolicateBacktrace(const Kernel::KProcess* process, std::vector<Backtrace
} }
} }
std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process, std::vector<BacktraceEntry> GetAArch64Backtrace(Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx) { const Kernel::Svc::ThreadContext& ctx) {
std::vector<BacktraceEntry> out; std::vector<BacktraceEntry> out;
auto& memory = process->GetMemory(); auto& memory = process->GetMemory();
@@ -144,7 +144,7 @@ std::vector<BacktraceEntry> GetAArch64Backtrace(const Kernel::KProcess* process,
return out; return out;
} }
std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process, std::vector<BacktraceEntry> GetAArch32Backtrace(Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx) { const Kernel::Svc::ThreadContext& ctx) {
std::vector<BacktraceEntry> out; std::vector<BacktraceEntry> out;
auto& memory = process->GetMemory(); auto& memory = process->GetMemory();
@@ -173,7 +173,7 @@ std::vector<BacktraceEntry> GetAArch32Backtrace(const Kernel::KProcess* process,
} // namespace } // namespace
std::optional<std::string> GetThreadName(const Kernel::KThread* thread) { std::optional<std::string> GetThreadName(const Kernel::KThread* thread) {
const auto* process = thread->GetOwnerProcess(); auto* process = thread->GetOwnerProcess();
if (process->Is64Bit()) { if (process->Is64Bit()) {
return GetNameFromThreadType64(process->GetMemory(), *thread); return GetNameFromThreadType64(process->GetMemory(), *thread);
} else { } else {
@@ -248,7 +248,7 @@ Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process,
return cur_addr - 1; return cur_addr - 1;
} }
Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) { Loader::AppLoader::Modules FindModules(Kernel::KProcess* process) {
Loader::AppLoader::Modules modules; Loader::AppLoader::Modules modules;
auto& page_table = process->GetPageTable(); auto& page_table = process->GetPageTable();
@@ -312,7 +312,7 @@ Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process) {
return modules; return modules;
} }
Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process) { Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process) {
// Do we have any loaded executable sections? // Do we have any loaded executable sections?
auto modules = FindModules(process); auto modules = FindModules(process);
@@ -337,7 +337,7 @@ void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 addres
} }
} }
std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process, std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx) { const Kernel::Svc::ThreadContext& ctx) {
if (process->Is64Bit()) { if (process->Is64Bit()) {
return GetAArch64Backtrace(process, ctx); return GetAArch64Backtrace(process, ctx);

View File

@@ -14,9 +14,9 @@ std::optional<std::string> GetThreadName(const Kernel::KThread* thread);
std::string_view GetThreadWaitReason(const Kernel::KThread* thread); std::string_view GetThreadWaitReason(const Kernel::KThread* thread);
std::string GetThreadState(const Kernel::KThread* thread); std::string GetThreadState(const Kernel::KThread* thread);
Loader::AppLoader::Modules FindModules(const Kernel::KProcess* process); Loader::AppLoader::Modules FindModules(Kernel::KProcess* process);
Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base); Kernel::KProcessAddress GetModuleEnd(const Kernel::KProcess* process, Kernel::KProcessAddress base);
Kernel::KProcessAddress FindMainModuleEntrypoint(const Kernel::KProcess* process); Kernel::KProcessAddress FindMainModuleEntrypoint(Kernel::KProcess* process);
void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size); void InvalidateInstructionCacheRange(const Kernel::KProcess* process, u64 address, u64 size);
@@ -28,7 +28,7 @@ struct BacktraceEntry {
std::string name; std::string name;
}; };
std::vector<BacktraceEntry> GetBacktraceFromContext(const Kernel::KProcess* process, std::vector<BacktraceEntry> GetBacktraceFromContext(Kernel::KProcess* process,
const Kernel::Svc::ThreadContext& ctx); const Kernel::Svc::ThreadContext& ctx);
std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread); std::vector<BacktraceEntry> GetBacktrace(const Kernel::KThread* thread);

View File

@@ -15,7 +15,7 @@ using namespace Common::Literals;
class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks { class DynarmicCallbacks32 : public Dynarmic::A32::UserCallbacks {
public: public:
explicit DynarmicCallbacks32(ArmDynarmic32& parent, const Kernel::KProcess* process) explicit DynarmicCallbacks32(ArmDynarmic32& parent, Kernel::KProcess* process)
: m_parent{parent}, m_memory(process->GetMemory()), : m_parent{parent}, m_memory(process->GetMemory()),
m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()}, m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
m_check_memory_access{m_debugger_enabled || m_check_memory_access{m_debugger_enabled ||
@@ -169,7 +169,7 @@ public:
ArmDynarmic32& m_parent; ArmDynarmic32& m_parent;
Core::Memory::Memory& m_memory; Core::Memory::Memory& m_memory;
const Kernel::KProcess* m_process{}; Kernel::KProcess* m_process{};
const bool m_debugger_enabled{}; const bool m_debugger_enabled{};
const bool m_check_memory_access{}; const bool m_check_memory_access{};
static constexpr u64 MinimumRunCycles = 10000U; static constexpr u64 MinimumRunCycles = 10000U;
@@ -370,7 +370,7 @@ void ArmDynarmic32::RewindBreakpointInstruction() {
this->SetContext(m_breakpoint_context); this->SetContext(m_breakpoint_context);
} }
ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process, ArmDynarmic32::ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index) DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
: ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor}, : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)), m_cb(std::make_unique<DynarmicCallbacks32>(*this, process)),

View File

@@ -20,7 +20,7 @@ class System;
class ArmDynarmic32 final : public ArmInterface { class ArmDynarmic32 final : public ArmInterface {
public: public:
ArmDynarmic32(System& system, bool uses_wall_clock, const Kernel::KProcess* process, ArmDynarmic32(System& system, bool uses_wall_clock, Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index); DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
~ArmDynarmic32() override; ~ArmDynarmic32() override;

View File

@@ -15,7 +15,7 @@ using namespace Common::Literals;
class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks { class DynarmicCallbacks64 : public Dynarmic::A64::UserCallbacks {
public: public:
explicit DynarmicCallbacks64(ArmDynarmic64& parent, const Kernel::KProcess* process) explicit DynarmicCallbacks64(ArmDynarmic64& parent, Kernel::KProcess* process)
: m_parent{parent}, m_memory(process->GetMemory()), : m_parent{parent}, m_memory(process->GetMemory()),
m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()}, m_process(process), m_debugger_enabled{parent.m_system.DebuggerEnabled()},
m_check_memory_access{m_debugger_enabled || m_check_memory_access{m_debugger_enabled ||
@@ -216,7 +216,7 @@ public:
Core::Memory::Memory& m_memory; Core::Memory::Memory& m_memory;
u64 m_tpidrro_el0{}; u64 m_tpidrro_el0{};
u64 m_tpidr_el0{}; u64 m_tpidr_el0{};
const Kernel::KProcess* m_process{}; Kernel::KProcess* m_process{};
const bool m_debugger_enabled{}; const bool m_debugger_enabled{};
const bool m_check_memory_access{}; const bool m_check_memory_access{};
static constexpr u64 MinimumRunCycles = 10000U; static constexpr u64 MinimumRunCycles = 10000U;
@@ -399,7 +399,7 @@ void ArmDynarmic64::RewindBreakpointInstruction() {
this->SetContext(m_breakpoint_context); this->SetContext(m_breakpoint_context);
} }
ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process, ArmDynarmic64::ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index) DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index)
: ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor}, : ArmInterface{uses_wall_clock}, m_system{system}, m_exclusive_monitor{exclusive_monitor},
m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} { m_cb(std::make_unique<DynarmicCallbacks64>(*this, process)), m_core_index{core_index} {

View File

@@ -25,7 +25,7 @@ class System;
class ArmDynarmic64 final : public ArmInterface { class ArmDynarmic64 final : public ArmInterface {
public: public:
ArmDynarmic64(System& system, bool uses_wall_clock, const Kernel::KProcess* process, ArmDynarmic64(System& system, bool uses_wall_clock, Kernel::KProcess* process,
DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index); DynarmicExclusiveMonitor& exclusive_monitor, std::size_t core_index);
~ArmDynarmic64() override; ~ArmDynarmic64() override;

View File

@@ -28,7 +28,6 @@
#include "core/file_sys/savedata_factory.h" #include "core/file_sys/savedata_factory.h"
#include "core/file_sys/vfs_concat.h" #include "core/file_sys/vfs_concat.h"
#include "core/file_sys/vfs_real.h" #include "core/file_sys/vfs_real.h"
#include "core/gpu_dirty_memory_manager.h"
#include "core/hid/hid_core.h" #include "core/hid/hid_core.h"
#include "core/hle/kernel/k_memory_manager.h" #include "core/hle/kernel/k_memory_manager.h"
#include "core/hle/kernel/k_process.h" #include "core/hle/kernel/k_process.h"
@@ -130,11 +129,8 @@ FileSys::VirtualFile GetGameFileFromPath(const FileSys::VirtualFilesystem& vfs,
struct System::Impl { struct System::Impl {
explicit Impl(System& system) explicit Impl(System& system)
: kernel{system}, fs_controller{system}, memory{system}, hid_core{}, room_network{}, : kernel{system}, fs_controller{system}, hid_core{}, room_network{}, cpu_manager{system},
cpu_manager{system}, reporter{system}, applet_manager{system}, profile_manager{}, reporter{system}, applet_manager{system}, profile_manager{}, time_manager{system} {}
time_manager{system}, gpu_dirty_memory_write_manager{} {
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
}
void Initialize(System& system) { void Initialize(System& system) {
device_memory = std::make_unique<Core::DeviceMemory>(); device_memory = std::make_unique<Core::DeviceMemory>();
@@ -241,17 +237,17 @@ struct System::Impl {
debugger = std::make_unique<Debugger>(system, port); debugger = std::make_unique<Debugger>(system, port);
} }
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) { void InitializeKernel(System& system) {
LOG_DEBUG(Core, "initialized OK"); LOG_DEBUG(Core, "initialized OK");
// Setting changes may require a full system reinitialization (e.g., disabling multicore). // Setting changes may require a full system reinitialization (e.g., disabling multicore).
ReinitializeIfNecessary(system); ReinitializeIfNecessary(system);
memory.SetGPUDirtyManagers(gpu_dirty_memory_write_manager);
kernel.Initialize(); kernel.Initialize();
cpu_manager.Initialize(); cpu_manager.Initialize();
}
SystemResultStatus SetupForApplicationProcess(System& system, Frontend::EmuWindow& emu_window) {
/// Reset all glue registrations /// Reset all glue registrations
arp_manager.ResetAll(); arp_manager.ResetAll();
@@ -300,17 +296,9 @@ struct System::Impl {
return SystemResultStatus::ErrorGetLoader; return SystemResultStatus::ErrorGetLoader;
} }
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)}; InitializeKernel(system);
if (init_result != SystemResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
ShutdownMainProcess();
return init_result;
}
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider); // Create the application process.
// Create the process.
auto main_process = Kernel::KProcess::Create(system.Kernel()); auto main_process = Kernel::KProcess::Create(system.Kernel());
Kernel::KProcess::Register(system.Kernel(), main_process); Kernel::KProcess::Register(system.Kernel(), main_process);
kernel.AppendNewProcess(main_process); kernel.AppendNewProcess(main_process);
@@ -323,7 +311,18 @@ struct System::Impl {
return static_cast<SystemResultStatus>( return static_cast<SystemResultStatus>(
static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result)); static_cast<u32>(SystemResultStatus::ErrorLoader) + static_cast<u32>(load_result));
} }
// Set up the rest of the system.
SystemResultStatus init_result{SetupForApplicationProcess(system, emu_window)};
if (init_result != SystemResultStatus::Success) {
LOG_CRITICAL(Core, "Failed to initialize system (Error {})!",
static_cast<int>(init_result));
ShutdownMainProcess();
return init_result;
}
AddGlueRegistrationForProcess(*app_loader, *main_process); AddGlueRegistrationForProcess(*app_loader, *main_process);
telemetry_session->AddInitialInfo(*app_loader, fs_controller, *content_provider);
// Initialize cheat engine // Initialize cheat engine
if (cheat_engine) { if (cheat_engine) {
@@ -426,7 +425,6 @@ struct System::Impl {
cpu_manager.Shutdown(); cpu_manager.Shutdown();
debugger.reset(); debugger.reset();
kernel.Shutdown(); kernel.Shutdown();
memory.Reset();
Network::RestartSocketOperations(); Network::RestartSocketOperations();
if (auto room_member = room_network.GetRoomMember().lock()) { if (auto room_member = room_network.GetRoomMember().lock()) {
@@ -507,7 +505,6 @@ struct System::Impl {
std::unique_ptr<Tegra::Host1x::Host1x> host1x_core; std::unique_ptr<Tegra::Host1x::Host1x> host1x_core;
std::unique_ptr<Core::DeviceMemory> device_memory; std::unique_ptr<Core::DeviceMemory> device_memory;
std::unique_ptr<AudioCore::AudioCore> audio_core; std::unique_ptr<AudioCore::AudioCore> audio_core;
Core::Memory::Memory memory;
Core::HID::HIDCore hid_core; Core::HID::HIDCore hid_core;
Network::RoomNetwork room_network; Network::RoomNetwork room_network;
@@ -567,9 +564,6 @@ struct System::Impl {
std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{}; std::array<u64, Core::Hardware::NUM_CPU_CORES> dynarmic_ticks{};
std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{}; std::array<MicroProfileToken, Core::Hardware::NUM_CPU_CORES> microprofile_cpu{};
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES>
gpu_dirty_memory_write_manager{};
std::deque<std::vector<u8>> user_channel; std::deque<std::vector<u8>> user_channel;
}; };
@@ -652,29 +646,12 @@ void System::PrepareReschedule(const u32 core_index) {
impl->kernel.PrepareReschedule(core_index); impl->kernel.PrepareReschedule(core_index);
} }
Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() {
const std::size_t core = impl->kernel.GetCurrentHostThreadID();
return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
? core
: Core::Hardware::NUM_CPU_CORES - 1];
}
/// Provides a constant reference to the current gou dirty memory manager.
const Core::GPUDirtyMemoryManager& System::CurrentGPUDirtyMemoryManager() const {
const std::size_t core = impl->kernel.GetCurrentHostThreadID();
return impl->gpu_dirty_memory_write_manager[core < Core::Hardware::NUM_CPU_CORES
? core
: Core::Hardware::NUM_CPU_CORES - 1];
}
size_t System::GetCurrentHostThreadID() const { size_t System::GetCurrentHostThreadID() const {
return impl->kernel.GetCurrentHostThreadID(); return impl->kernel.GetCurrentHostThreadID();
} }
void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) { void System::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
for (auto& manager : impl->gpu_dirty_memory_write_manager) { return this->ApplicationProcess()->GatherGPUDirtyMemory(callback);
manager.Gather(callback);
}
} }
PerfStatsResults System::GetAndResetPerfStats() { PerfStatsResults System::GetAndResetPerfStats() {
@@ -723,20 +700,12 @@ const Kernel::KProcess* System::ApplicationProcess() const {
return impl->kernel.ApplicationProcess(); return impl->kernel.ApplicationProcess();
} }
ExclusiveMonitor& System::Monitor() {
return impl->kernel.GetExclusiveMonitor();
}
const ExclusiveMonitor& System::Monitor() const {
return impl->kernel.GetExclusiveMonitor();
}
Memory::Memory& System::ApplicationMemory() { Memory::Memory& System::ApplicationMemory() {
return impl->memory; return impl->kernel.ApplicationProcess()->GetMemory();
} }
const Core::Memory::Memory& System::ApplicationMemory() const { const Core::Memory::Memory& System::ApplicationMemory() const {
return impl->memory; return impl->kernel.ApplicationProcess()->GetMemory();
} }
Tegra::GPU& System::GPU() { Tegra::GPU& System::GPU() {

View File

@@ -116,7 +116,6 @@ class CpuManager;
class Debugger; class Debugger;
class DeviceMemory; class DeviceMemory;
class ExclusiveMonitor; class ExclusiveMonitor;
class GPUDirtyMemoryManager;
class PerfStats; class PerfStats;
class Reporter; class Reporter;
class SpeedLimiter; class SpeedLimiter;
@@ -225,12 +224,6 @@ public:
/// Prepare the core emulation for a reschedule /// Prepare the core emulation for a reschedule
void PrepareReschedule(u32 core_index); void PrepareReschedule(u32 core_index);
/// Provides a reference to the gou dirty memory manager.
[[nodiscard]] Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager();
/// Provides a constant reference to the current gou dirty memory manager.
[[nodiscard]] const Core::GPUDirtyMemoryManager& CurrentGPUDirtyMemoryManager() const;
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback); void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
[[nodiscard]] size_t GetCurrentHostThreadID() const; [[nodiscard]] size_t GetCurrentHostThreadID() const;
@@ -250,12 +243,6 @@ public:
/// Gets a const reference to the underlying CPU manager /// Gets a const reference to the underlying CPU manager
[[nodiscard]] const CpuManager& GetCpuManager() const; [[nodiscard]] const CpuManager& GetCpuManager() const;
/// Gets a reference to the exclusive monitor
[[nodiscard]] ExclusiveMonitor& Monitor();
/// Gets a constant reference to the exclusive monitor
[[nodiscard]] const ExclusiveMonitor& Monitor() const;
/// Gets a mutable reference to the system memory instance. /// Gets a mutable reference to the system memory instance.
[[nodiscard]] Core::Memory::Memory& ApplicationMemory(); [[nodiscard]] Core::Memory::Memory& ApplicationMemory();

View File

@@ -166,6 +166,10 @@ u32 ProgramMetadata::GetSystemResourceSize() const {
return npdm_header.system_resource_size; return npdm_header.system_resource_size;
} }
PoolPartition ProgramMetadata::GetPoolPartition() const {
return acid_header.pool_partition;
}
const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const { const ProgramMetadata::KernelCapabilityDescriptors& ProgramMetadata::GetKernelCapabilities() const {
return aci_kernel_capabilities; return aci_kernel_capabilities;
} }
@@ -201,7 +205,7 @@ void ProgramMetadata::Print() const {
// Begin ACID printing (potential perms, signed) // Begin ACID printing (potential perms, signed)
LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data()); LOG_DEBUG(Service_FS, "Magic: {:.4}", acid_header.magic.data());
LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags); LOG_DEBUG(Service_FS, "Flags: 0x{:02X}", acid_header.flags);
LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.is_retail ? "YES" : "NO"); LOG_DEBUG(Service_FS, " > Is Retail: {}", acid_header.production_flag ? "YES" : "NO");
LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min); LOG_DEBUG(Service_FS, "Title ID Min: 0x{:016X}", acid_header.title_id_min);
LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max); LOG_DEBUG(Service_FS, "Title ID Max: 0x{:016X}", acid_header.title_id_max);
LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions); LOG_DEBUG(Service_FS, "Filesystem Access: 0x{:016X}\n", acid_file_access.permissions);

View File

@@ -34,6 +34,13 @@ enum class ProgramFilePermission : u64 {
Everything = 1ULL << 63, Everything = 1ULL << 63,
}; };
enum class PoolPartition : u32 {
Application = 0,
Applet = 1,
System = 2,
SystemNonSecure = 3,
};
/** /**
* Helper which implements an interface to parse Program Description Metadata (NPDM) * Helper which implements an interface to parse Program Description Metadata (NPDM)
* Data can either be loaded from a file path or with data and an offset into it. * Data can either be loaded from a file path or with data and an offset into it.
@@ -72,6 +79,7 @@ public:
u64 GetTitleID() const; u64 GetTitleID() const;
u64 GetFilesystemPermissions() const; u64 GetFilesystemPermissions() const;
u32 GetSystemResourceSize() const; u32 GetSystemResourceSize() const;
PoolPartition GetPoolPartition() const;
const KernelCapabilityDescriptors& GetKernelCapabilities() const; const KernelCapabilityDescriptors& GetKernelCapabilities() const;
const std::array<u8, 0x10>& GetName() const { const std::array<u8, 0x10>& GetName() const {
return npdm_header.application_name; return npdm_header.application_name;
@@ -116,8 +124,9 @@ private:
union { union {
u32 flags; u32 flags;
BitField<0, 1, u32> is_retail; BitField<0, 1, u32> production_flag;
BitField<1, 31, u32> flags_unk; BitField<1, 1, u32> unqualified_approval;
BitField<2, 4, PoolPartition> pool_partition;
}; };
u64_le title_id_min; u64_le title_id_min;
u64_le title_id_max; u64_le title_id_max;

View File

@@ -4,6 +4,7 @@
#include "core/arm/exclusive_monitor.h" #include "core/arm/exclusive_monitor.h"
#include "core/core.h" #include "core/core.h"
#include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_address_arbiter.h"
#include "core/hle/kernel/k_process.h"
#include "core/hle/kernel/k_scheduler.h" #include "core/hle/kernel/k_scheduler.h"
#include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h" #include "core/hle/kernel/k_scoped_scheduler_lock_and_sleep.h"
#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread.h"
@@ -26,9 +27,9 @@ bool ReadFromUser(KernelCore& kernel, s32* out, KProcessAddress address) {
return true; return true;
} }
bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address, s32 value) { bool DecrementIfLessThan(KernelCore& kernel, s32* out, KProcessAddress address, s32 value) {
auto& monitor = system.Monitor(); auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); const auto current_core = kernel.CurrentPhysicalCoreIndex();
// NOTE: If scheduler lock is not held here, interrupt disable is required. // NOTE: If scheduler lock is not held here, interrupt disable is required.
// KScopedInterruptDisable di; // KScopedInterruptDisable di;
@@ -66,10 +67,10 @@ bool DecrementIfLessThan(Core::System& system, s32* out, KProcessAddress address
return true; return true;
} }
bool UpdateIfEqual(Core::System& system, s32* out, KProcessAddress address, s32 value, bool UpdateIfEqual(KernelCore& kernel, s32* out, KProcessAddress address, s32 value,
s32 new_value) { s32 new_value) {
auto& monitor = system.Monitor(); auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); const auto current_core = kernel.CurrentPhysicalCoreIndex();
// NOTE: If scheduler lock is not held here, interrupt disable is required. // NOTE: If scheduler lock is not held here, interrupt disable is required.
// KScopedInterruptDisable di; // KScopedInterruptDisable di;
@@ -159,7 +160,7 @@ Result KAddressArbiter::SignalAndIncrementIfEqual(uint64_t addr, s32 value, s32
// Check the userspace value. // Check the userspace value.
s32 user_value{}; s32 user_value{};
R_UNLESS(UpdateIfEqual(m_system, std::addressof(user_value), addr, value, value + 1), R_UNLESS(UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, value + 1),
ResultInvalidCurrentMemory); ResultInvalidCurrentMemory);
R_UNLESS(user_value == value, ResultInvalidState); R_UNLESS(user_value == value, ResultInvalidState);
@@ -219,7 +220,7 @@ Result KAddressArbiter::SignalAndModifyByWaitingCountIfEqual(uint64_t addr, s32
s32 user_value{}; s32 user_value{};
bool succeeded{}; bool succeeded{};
if (value != new_value) { if (value != new_value) {
succeeded = UpdateIfEqual(m_system, std::addressof(user_value), addr, value, new_value); succeeded = UpdateIfEqual(m_kernel, std::addressof(user_value), addr, value, new_value);
} else { } else {
succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
} }
@@ -262,7 +263,7 @@ Result KAddressArbiter::WaitIfLessThan(uint64_t addr, s32 value, bool decrement,
s32 user_value{}; s32 user_value{};
bool succeeded{}; bool succeeded{};
if (decrement) { if (decrement) {
succeeded = DecrementIfLessThan(m_system, std::addressof(user_value), addr, value); succeeded = DecrementIfLessThan(m_kernel, std::addressof(user_value), addr, value);
} else { } else {
succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr); succeeded = ReadFromUser(m_kernel, std::addressof(user_value), addr);
} }

View File

@@ -58,9 +58,8 @@ Result KClientPort::CreateSession(KClientSession** out) {
KSession* session{}; KSession* session{};
// Reserve a new session from the resource limit. // Reserve a new session from the resource limit.
//! FIXME: we are reserving this from the wrong resource limit! KScopedResourceReservation session_reservation(GetCurrentProcessPointer(m_kernel),
KScopedResourceReservation session_reservation( LimitableResource::SessionCountMax);
m_kernel.ApplicationProcess()->GetResourceLimit(), LimitableResource::SessionCountMax);
R_UNLESS(session_reservation.Succeeded(), ResultLimitReached); R_UNLESS(session_reservation.Succeeded(), ResultLimitReached);
// Allocate a session normally. // Allocate a session normally.

View File

@@ -28,10 +28,10 @@ bool WriteToUser(KernelCore& kernel, KProcessAddress address, const u32* p) {
return true; return true;
} }
bool UpdateLockAtomic(Core::System& system, u32* out, KProcessAddress address, u32 if_zero, bool UpdateLockAtomic(KernelCore& kernel, u32* out, KProcessAddress address, u32 if_zero,
u32 new_orr_mask) { u32 new_orr_mask) {
auto& monitor = system.Monitor(); auto& monitor = GetCurrentProcess(kernel).GetExclusiveMonitor();
const auto current_core = system.Kernel().CurrentPhysicalCoreIndex(); const auto current_core = kernel.CurrentPhysicalCoreIndex();
u32 expected{}; u32 expected{};
@@ -208,7 +208,7 @@ void KConditionVariable::SignalImpl(KThread* thread) {
// TODO(bunnei): We should call CanAccessAtomic(..) here. // TODO(bunnei): We should call CanAccessAtomic(..) here.
can_access = true; can_access = true;
if (can_access) [[likely]] { if (can_access) [[likely]] {
UpdateLockAtomic(m_system, std::addressof(prev_tag), address, own_tag, UpdateLockAtomic(m_kernel, std::addressof(prev_tag), address, own_tag,
Svc::HandleWaitMask); Svc::HandleWaitMask);
} }
} }

View File

@@ -30,7 +30,7 @@ public:
public: public:
explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {} explicit KHandleTable(KernelCore& kernel) : m_kernel(kernel) {}
Result Initialize(s32 size) { Result Initialize(KProcess* owner, s32 size) {
// Check that the table size is valid. // Check that the table size is valid.
R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory); R_UNLESS(size <= static_cast<s32>(MaxTableSize), ResultOutOfMemory);
@@ -44,6 +44,7 @@ public:
m_next_linear_id = MinLinearId; m_next_linear_id = MinLinearId;
m_count = 0; m_count = 0;
m_free_head_index = -1; m_free_head_index = -1;
m_owner = owner;
// Free all entries. // Free all entries.
for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) { for (s32 i = 0; i < static_cast<s32>(m_table_size); ++i) {
@@ -90,8 +91,8 @@ public:
// Handle pseudo-handles. // Handle pseudo-handles.
if constexpr (std::derived_from<KProcess, T>) { if constexpr (std::derived_from<KProcess, T>) {
if (handle == Svc::PseudoHandle::CurrentProcess) { if (handle == Svc::PseudoHandle::CurrentProcess) {
//! FIXME: this is the wrong process! // TODO: this should be the current process
auto* const cur_process = m_kernel.ApplicationProcess(); auto* const cur_process = m_owner;
ASSERT(cur_process != nullptr); ASSERT(cur_process != nullptr);
return cur_process; return cur_process;
} }
@@ -301,6 +302,7 @@ private:
private: private:
KernelCore& m_kernel; KernelCore& m_kernel;
KProcess* m_owner{};
std::array<EntryInfo, MaxTableSize> m_entry_infos{}; std::array<EntryInfo, MaxTableSize> m_entry_infos{};
std::array<KAutoObject*, MaxTableSize> m_objects{}; std::array<KAutoObject*, MaxTableSize> m_objects{};
mutable KSpinLock m_lock; mutable KSpinLock m_lock;

View File

@@ -306,12 +306,16 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params, const KPa
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge); False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
params.code_address, params.code_num_pages * PageSize, params.code_address, params.code_num_pages * PageSize,
m_system_resource, res_limit, this->GetMemory(), 0)); m_system_resource, res_limit, m_memory, 0));
} }
ON_RESULT_FAILURE_2 { ON_RESULT_FAILURE_2 {
m_page_table.Finalize(); m_page_table.Finalize();
}; };
// Ensure our memory is initialized.
m_memory.SetCurrentPageTable(*this);
m_memory.SetGPUDirtyManagers(m_dirty_memory_managers);
// Ensure we can insert the code region. // Ensure we can insert the code region.
R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize, R_UNLESS(m_page_table.CanContain(params.code_address, params.code_num_pages * PageSize,
KMemoryState::Code), KMemoryState::Code),
@@ -399,12 +403,16 @@ Result KProcess::Initialize(const Svc::CreateProcessParameter& params,
False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge); False(params.flags & Svc::CreateProcessFlag::DisableDeviceAddressSpaceMerge);
R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool, R_TRY(m_page_table.Initialize(as_type, enable_aslr, enable_das_merge, !enable_aslr, pool,
params.code_address, code_size, m_system_resource, res_limit, params.code_address, code_size, m_system_resource, res_limit,
this->GetMemory(), aslr_space_start)); m_memory, aslr_space_start));
} }
ON_RESULT_FAILURE_2 { ON_RESULT_FAILURE_2 {
m_page_table.Finalize(); m_page_table.Finalize();
}; };
// Ensure our memory is initialized.
m_memory.SetCurrentPageTable(*this);
m_memory.SetGPUDirtyManagers(m_dirty_memory_managers);
// Ensure we can insert the code region. // Ensure we can insert the code region.
R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code), R_UNLESS(m_page_table.CanContain(params.code_address, code_size, KMemoryState::Code),
ResultInvalidMemoryRegion); ResultInvalidMemoryRegion);
@@ -1094,8 +1102,7 @@ void KProcess::UnpinThread(KThread* thread) {
Result KProcess::GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids, Result KProcess::GetThreadList(s32* out_num_threads, KProcessAddress out_thread_ids,
s32 max_out_count) { s32 max_out_count) {
// TODO: use current memory reference auto& memory = this->GetMemory();
auto& memory = m_kernel.System().ApplicationMemory();
// Lock the list. // Lock the list.
KScopedLightLock lk(m_list_lock); KScopedLightLock lk(m_list_lock);
@@ -1128,14 +1135,15 @@ void KProcess::Switch(KProcess* cur_process, KProcess* next_process) {}
KProcess::KProcess(KernelCore& kernel) KProcess::KProcess(KernelCore& kernel)
: KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel}, : KAutoObjectWithSlabHeapAndContainer(kernel), m_page_table{kernel}, m_state_lock{kernel},
m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()}, m_list_lock{kernel}, m_cond_var{kernel.System()}, m_address_arbiter{kernel.System()},
m_handle_table{kernel} {} m_handle_table{kernel}, m_dirty_memory_managers{},
m_exclusive_monitor{}, m_memory{kernel.System()} {}
KProcess::~KProcess() = default; KProcess::~KProcess() = default;
Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size, Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std::size_t code_size,
KProcessAddress aslr_space_start, bool is_hbl) { KProcessAddress aslr_space_start, bool is_hbl) {
// Create a resource limit for the process. // Create a resource limit for the process.
const auto physical_memory_size = const auto pool = static_cast<KMemoryManager::Pool>(metadata.GetPoolPartition());
m_kernel.MemoryManager().GetSize(Kernel::KMemoryManager::Pool::Application); const auto physical_memory_size = m_kernel.MemoryManager().GetSize(pool);
auto* res_limit = auto* res_limit =
Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size); Kernel::CreateResourceLimitForProcess(m_kernel.System(), physical_memory_size);
@@ -1146,8 +1154,10 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
Svc::CreateProcessFlag flag{}; Svc::CreateProcessFlag flag{};
u64 code_address{}; u64 code_address{};
// We are an application. // Determine if we are an application.
if (pool == KMemoryManager::Pool::Application) {
flag |= Svc::CreateProcessFlag::IsApplication; flag |= Svc::CreateProcessFlag::IsApplication;
}
// If we are 64-bit, create as such. // If we are 64-bit, create as such.
if (metadata.Is64BitProgram()) { if (metadata.Is64BitProgram()) {
@@ -1196,8 +1206,8 @@ Result KProcess::LoadFromMetadata(const FileSys::ProgramMetadata& metadata, std:
std::memcpy(params.name.data(), name.data(), sizeof(params.name)); std::memcpy(params.name.data(), name.data(), sizeof(params.name));
// Initialize for application process. // Initialize for application process.
R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit, R_TRY(this->Initialize(params, metadata.GetKernelCapabilities(), res_limit, pool,
KMemoryManager::Pool::Application, aslr_space_start)); aslr_space_start));
// Assign remaining properties. // Assign remaining properties.
m_is_hbl = is_hbl; m_is_hbl = is_hbl;
@@ -1223,7 +1233,7 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite); ReprotectSegment(code_set.DataSegment(), Svc::MemoryPermission::ReadWrite);
#ifdef HAS_NCE #ifdef HAS_NCE
if (Settings::IsNceEnabled()) { if (this->IsApplication() && Settings::IsNceEnabled()) {
auto& buffer = m_kernel.System().DeviceMemory().buffer; auto& buffer = m_kernel.System().DeviceMemory().buffer;
const auto& code = code_set.CodeSegment(); const auto& code = code_set.CodeSegment();
const auto& patch = code_set.PatchSegment(); const auto& patch = code_set.PatchSegment();
@@ -1235,10 +1245,11 @@ void KProcess::LoadModule(CodeSet code_set, KProcessAddress base_addr) {
} }
void KProcess::InitializeInterfaces() { void KProcess::InitializeInterfaces() {
this->GetMemory().SetCurrentPageTable(*this); m_exclusive_monitor =
Core::MakeExclusiveMonitor(this->GetMemory(), Core::Hardware::NUM_CPU_CORES);
#ifdef HAS_NCE #ifdef HAS_NCE
if (this->Is64Bit() && Settings::IsNceEnabled()) { if (this->IsApplication() && Settings::IsNceEnabled()) {
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i); m_arm_interfaces[i] = std::make_unique<Core::ArmNce>(m_kernel.System(), true, i);
} }
@@ -1248,13 +1259,13 @@ void KProcess::InitializeInterfaces() {
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>( m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic64>(
m_kernel.System(), m_kernel.IsMulticore(), this, m_kernel.System(), m_kernel.IsMulticore(), this,
static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i); static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i);
} }
} else { } else {
for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (size_t i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>( m_arm_interfaces[i] = std::make_unique<Core::ArmDynarmic32>(
m_kernel.System(), m_kernel.IsMulticore(), this, m_kernel.System(), m_kernel.IsMulticore(), this,
static_cast<Core::DynarmicExclusiveMonitor&>(m_kernel.GetExclusiveMonitor()), i); static_cast<Core::DynarmicExclusiveMonitor&>(*m_exclusive_monitor), i);
} }
} }
} }
@@ -1305,9 +1316,10 @@ bool KProcess::RemoveWatchpoint(KProcessAddress addr, u64 size, DebugWatchpointT
return true; return true;
} }
Core::Memory::Memory& KProcess::GetMemory() const { void KProcess::GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback) {
// TODO: per-process memory for (auto& manager : m_dirty_memory_managers) {
return m_kernel.System().ApplicationMemory(); manager.Gather(callback);
}
} }
} // namespace Kernel } // namespace Kernel

View File

@@ -7,6 +7,7 @@
#include "core/arm/arm_interface.h" #include "core/arm/arm_interface.h"
#include "core/file_sys/program_metadata.h" #include "core/file_sys/program_metadata.h"
#include "core/gpu_dirty_memory_manager.h"
#include "core/hle/kernel/code_set.h" #include "core/hle/kernel/code_set.h"
#include "core/hle/kernel/k_address_arbiter.h" #include "core/hle/kernel/k_address_arbiter.h"
#include "core/hle/kernel/k_capabilities.h" #include "core/hle/kernel/k_capabilities.h"
@@ -17,6 +18,7 @@
#include "core/hle/kernel/k_system_resource.h" #include "core/hle/kernel/k_system_resource.h"
#include "core/hle/kernel/k_thread.h" #include "core/hle/kernel/k_thread.h"
#include "core/hle/kernel/k_thread_local_page.h" #include "core/hle/kernel/k_thread_local_page.h"
#include "core/memory.h"
namespace Kernel { namespace Kernel {
@@ -126,6 +128,9 @@ private:
#ifdef HAS_NCE #ifdef HAS_NCE
std::unordered_map<u64, u64> m_post_handlers{}; std::unordered_map<u64, u64> m_post_handlers{};
#endif #endif
std::array<Core::GPUDirtyMemoryManager, Core::Hardware::NUM_CPU_CORES> m_dirty_memory_managers;
std::unique_ptr<Core::ExclusiveMonitor> m_exclusive_monitor;
Core::Memory::Memory m_memory;
private: private:
Result StartTermination(); Result StartTermination();
@@ -502,7 +507,15 @@ public:
void InitializeInterfaces(); void InitializeInterfaces();
Core::Memory::Memory& GetMemory() const; Core::Memory::Memory& GetMemory() {
return m_memory;
}
void GatherGPUDirtyMemory(std::function<void(VAddr, size_t)>& callback);
Core::ExclusiveMonitor& GetExclusiveMonitor() const {
return *m_exclusive_monitor;
}
public: public:
// Overridden parent functions. // Overridden parent functions.
@@ -539,7 +552,7 @@ private:
Result InitializeHandleTable(s32 size) { Result InitializeHandleTable(s32 size) {
// Try to initialize the handle table. // Try to initialize the handle table.
R_TRY(m_handle_table.Initialize(size)); R_TRY(m_handle_table.Initialize(this, size));
// We succeeded, so note that we did. // We succeeded, so note that we did.
m_is_handle_table_initialized = true; m_is_handle_table_initialized = true;

File diff suppressed because it is too large Load Diff

View File

@@ -49,14 +49,21 @@ public:
bool IsSignaled() const override; bool IsSignaled() const override;
void OnClientClosed(); void OnClientClosed();
/// TODO: flesh these out to match the real kernel
Result OnRequest(KSessionRequest* request); Result OnRequest(KSessionRequest* request);
Result SendReply(bool is_hle = false); Result SendReply(uintptr_t server_message, uintptr_t server_buffer_size,
Result ReceiveRequest(std::shared_ptr<Service::HLERequestContext>* out_context = nullptr, KPhysicalAddress server_message_paddr, bool is_hle = false);
Result ReceiveRequest(uintptr_t server_message, uintptr_t server_buffer_size,
KPhysicalAddress server_message_paddr,
std::shared_ptr<Service::HLERequestContext>* out_context = nullptr,
std::weak_ptr<Service::SessionRequestManager> manager = {}); std::weak_ptr<Service::SessionRequestManager> manager = {});
Result SendReplyHLE() { Result SendReplyHLE() {
return SendReply(true); R_RETURN(this->SendReply(0, 0, 0, true));
}
Result ReceiveRequestHLE(std::shared_ptr<Service::HLERequestContext>* out_context,
std::weak_ptr<Service::SessionRequestManager> manager) {
R_RETURN(this->ReceiveRequest(0, 0, 0, out_context, manager));
} }
private: private:

View File

@@ -33,8 +33,7 @@ void KSession::Initialize(KClientPort* client_port, uintptr_t name) {
m_name = name; m_name = name;
// Set our owner process. // Set our owner process.
//! FIXME: this is the wrong process! m_process = GetCurrentProcessPointer(m_kernel);
m_process = m_kernel.ApplicationProcess();
m_process->Open(); m_process->Open();
// Set our port. // Set our port.

View File

@@ -1422,8 +1422,7 @@ s32 GetCurrentCoreId(KernelCore& kernel) {
} }
Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) { Core::Memory::Memory& GetCurrentMemory(KernelCore& kernel) {
// TODO: per-process memory return GetCurrentProcess(kernel).GetMemory();
return kernel.System().ApplicationMemory();
} }
KScopedDisableDispatch::~KScopedDisableDispatch() { KScopedDisableDispatch::~KScopedDisableDispatch() {

View File

@@ -314,11 +314,7 @@ public:
m_current_core_id = core; m_current_core_id = core;
} }
KProcess* GetOwnerProcess() { KProcess* GetOwnerProcess() const {
return m_parent;
}
const KProcess* GetOwnerProcess() const {
return m_parent; return m_parent;
} }

View File

@@ -68,8 +68,6 @@ struct KernelCore::Impl {
global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel); global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(kernel);
global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel); global_scheduler_context = std::make_unique<Kernel::GlobalSchedulerContext>(kernel);
global_handle_table = std::make_unique<Kernel::KHandleTable>(kernel);
global_handle_table->Initialize(KHandleTable::MaxTableSize);
is_phantom_mode_for_singlecore = false; is_phantom_mode_for_singlecore = false;
@@ -121,13 +119,8 @@ struct KernelCore::Impl {
next_user_process_id = KProcess::ProcessIdMin; next_user_process_id = KProcess::ProcessIdMin;
next_thread_id = 1; next_thread_id = 1;
global_handle_table->Finalize();
global_handle_table.reset();
preemption_event = nullptr; preemption_event = nullptr;
exclusive_monitor.reset();
// Cleanup persistent kernel objects // Cleanup persistent kernel objects
auto CleanupObject = [](KAutoObject* obj) { auto CleanupObject = [](KAutoObject* obj) {
if (obj) { if (obj) {
@@ -191,8 +184,6 @@ struct KernelCore::Impl {
} }
void InitializePhysicalCores() { void InitializePhysicalCores() {
exclusive_monitor =
Core::MakeExclusiveMonitor(system.ApplicationMemory(), Core::Hardware::NUM_CPU_CORES);
for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) { for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
const s32 core{static_cast<s32>(i)}; const s32 core{static_cast<s32>(i)};
@@ -791,10 +782,6 @@ struct KernelCore::Impl {
std::shared_ptr<Core::Timing::EventType> preemption_event; std::shared_ptr<Core::Timing::EventType> preemption_event;
// This is the kernel's handle table or supervisor handle table which
// stores all the objects in place.
std::unique_ptr<KHandleTable> global_handle_table;
std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container; std::unique_ptr<KAutoObjectWithListContainer> global_object_list_container;
std::unique_ptr<KObjectNameGlobalData> object_name_global_data; std::unique_ptr<KObjectNameGlobalData> object_name_global_data;
@@ -805,7 +792,6 @@ struct KernelCore::Impl {
std::mutex server_lock; std::mutex server_lock;
std::vector<std::unique_ptr<Service::ServerManager>> server_managers; std::vector<std::unique_ptr<Service::ServerManager>> server_managers;
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores; std::array<std::unique_ptr<Kernel::PhysicalCore>, Core::Hardware::NUM_CPU_CORES> cores;
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others // Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
@@ -882,10 +868,6 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() {
return impl->system_resource_limit; return impl->system_resource_limit;
} }
KScopedAutoObject<KThread> KernelCore::RetrieveThreadFromGlobalHandleTable(Handle handle) const {
return impl->global_handle_table->GetObject<KThread>(handle);
}
void KernelCore::AppendNewProcess(KProcess* process) { void KernelCore::AppendNewProcess(KProcess* process) {
impl->process_list.push_back(process); impl->process_list.push_back(process);
} }
@@ -959,14 +941,6 @@ Kernel::KHardwareTimer& KernelCore::HardwareTimer() {
return *impl->hardware_timer; return *impl->hardware_timer;
} }
Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() {
return *impl->exclusive_monitor;
}
const Core::ExclusiveMonitor& KernelCore::GetExclusiveMonitor() const {
return *impl->exclusive_monitor;
}
KAutoObjectWithListContainer& KernelCore::ObjectListContainer() { KAutoObjectWithListContainer& KernelCore::ObjectListContainer() {
return *impl->global_object_list_container; return *impl->global_object_list_container;
} }
@@ -1030,14 +1004,6 @@ u64 KernelCore::CreateNewUserProcessID() {
return impl->next_user_process_id++; return impl->next_user_process_id++;
} }
KHandleTable& KernelCore::GlobalHandleTable() {
return *impl->global_handle_table;
}
const KHandleTable& KernelCore::GlobalHandleTable() const {
return *impl->global_handle_table;
}
void KernelCore::RegisterCoreThread(std::size_t core_id) { void KernelCore::RegisterCoreThread(std::size_t core_id) {
impl->RegisterCoreThread(core_id); impl->RegisterCoreThread(core_id);
} }

View File

@@ -116,9 +116,6 @@ public:
/// Retrieves a shared pointer to the system resource limit instance. /// Retrieves a shared pointer to the system resource limit instance.
KResourceLimit* GetSystemResourceLimit(); KResourceLimit* GetSystemResourceLimit();
/// Retrieves a shared pointer to a Thread instance within the thread wakeup handle table.
KScopedAutoObject<KThread> RetrieveThreadFromGlobalHandleTable(Handle handle) const;
/// Adds the given shared pointer to an internal list of active processes. /// Adds the given shared pointer to an internal list of active processes.
void AppendNewProcess(KProcess* process); void AppendNewProcess(KProcess* process);
@@ -170,10 +167,6 @@ public:
/// Stops execution of 'id' core, in order to reschedule a new thread. /// Stops execution of 'id' core, in order to reschedule a new thread.
void PrepareReschedule(std::size_t id); void PrepareReschedule(std::size_t id);
Core::ExclusiveMonitor& GetExclusiveMonitor();
const Core::ExclusiveMonitor& GetExclusiveMonitor() const;
KAutoObjectWithListContainer& ObjectListContainer(); KAutoObjectWithListContainer& ObjectListContainer();
const KAutoObjectWithListContainer& ObjectListContainer() const; const KAutoObjectWithListContainer& ObjectListContainer() const;

View File

@@ -18,13 +18,13 @@ public:
static constexpr inline u64 NullTag = 0; static constexpr inline u64 NullTag = 0;
public: public:
enum class ReceiveListCountType : u32 { enum ReceiveListCountType : u32 {
None = 0, ReceiveListCountType_None = 0,
ToMessageBuffer = 1, ReceiveListCountType_ToMessageBuffer = 1,
ToSingleBuffer = 2, ReceiveListCountType_ToSingleBuffer = 2,
CountOffset = 2, ReceiveListCountType_CountOffset = 2,
CountMax = 13, ReceiveListCountType_CountMax = 13,
}; };
private: private:
@@ -591,16 +591,16 @@ public:
// Add the size of the receive list. // Add the size of the receive list.
const auto count = hdr.GetReceiveListCount(); const auto count = hdr.GetReceiveListCount();
switch (count) { switch (count) {
case MessageHeader::ReceiveListCountType::None: case MessageHeader::ReceiveListCountType_None:
break; break;
case MessageHeader::ReceiveListCountType::ToMessageBuffer: case MessageHeader::ReceiveListCountType_ToMessageBuffer:
break; break;
case MessageHeader::ReceiveListCountType::ToSingleBuffer: case MessageHeader::ReceiveListCountType_ToSingleBuffer:
msg_size += ReceiveListEntry::GetDataSize(); msg_size += ReceiveListEntry::GetDataSize();
break; break;
default: default:
msg_size += (static_cast<s32>(count) - msg_size += (static_cast<s32>(count) -
static_cast<s32>(MessageHeader::ReceiveListCountType::CountOffset)) * static_cast<s32>(MessageHeader::ReceiveListCountType_CountOffset)) *
ReceiveListEntry::GetDataSize(); ReceiveListEntry::GetDataSize();
break; break;
} }

View File

@@ -118,7 +118,6 @@ Result GetInfo(Core::System& system, u64* result, InfoType info_id_type, Handle
R_SUCCEED(); R_SUCCEED();
case InfoType::IsApplication: case InfoType::IsApplication:
LOG_WARNING(Kernel_SVC, "(STUBBED) Assuming process is application");
*result = process->IsApplication(); *result = process->IsApplication();
R_SUCCEED(); R_SUCCEED();

View File

@@ -48,8 +48,7 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
}; };
// Send the reply. // Send the reply.
R_TRY(session->SendReply()); R_TRY(session->SendReply(message, buffer_size, message_paddr));
// R_TRY(session->SendReply(message, buffer_size, message_paddr));
} }
// Receive a message. // Receive a message.
@@ -85,8 +84,7 @@ Result ReplyAndReceiveImpl(KernelCore& kernel, int32_t* out_index, uintptr_t mes
if (R_SUCCEEDED(result)) { if (R_SUCCEEDED(result)) {
KServerSession* session = objs[index]->DynamicCast<KServerSession*>(); KServerSession* session = objs[index]->DynamicCast<KServerSession*>();
if (session != nullptr) { if (session != nullptr) {
// result = session->ReceiveRequest(message, buffer_size, message_paddr); result = session->ReceiveRequest(message, buffer_size, message_paddr);
result = session->ReceiveRequest();
if (ResultNotFound == result) { if (ResultNotFound == result) {
continue; continue;
} }

View File

@@ -38,7 +38,9 @@ constexpr Result ResultInvalidState{ErrorModule::Kernel, 125};
constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126}; constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126};
constexpr Result ResultPortClosed{ErrorModule::Kernel, 131}; constexpr Result ResultPortClosed{ErrorModule::Kernel, 131};
constexpr Result ResultLimitReached{ErrorModule::Kernel, 132}; constexpr Result ResultLimitReached{ErrorModule::Kernel, 132};
constexpr Result ResultReceiveListBroken{ErrorModule::Kernel, 258};
constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259}; constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259};
constexpr Result ResultMessageTooLarge{ErrorModule::Kernel, 260};
constexpr Result ResultInvalidId{ErrorModule::Kernel, 519}; constexpr Result ResultInvalidId{ErrorModule::Kernel, 519};
} // namespace Kernel } // namespace Kernel

View File

@@ -89,7 +89,7 @@ static void GenerateErrorReport(Core::System& system, Result error_code, const F
crash_report += fmt::format(" ESR: {:016x}\n", info.esr); crash_report += fmt::format(" ESR: {:016x}\n", info.esr);
crash_report += fmt::format(" FAR: {:016x}\n", info.far); crash_report += fmt::format(" FAR: {:016x}\n", info.far);
crash_report += "\nBacktrace:\n"; crash_report += "\nBacktrace:\n";
for (size_t i = 0; i < info.backtrace_size; i++) { for (u32 i = 0; i < std::min<u32>(info.backtrace_size, 32); i++) {
crash_report += crash_report +=
fmt::format(" Backtrace[{:02d}]: {:016x}\n", i, info.backtrace[i]); fmt::format(" Backtrace[{:02d}]: {:016x}\n", i, info.backtrace[i]);
} }

View File

@@ -151,8 +151,8 @@ public:
if (manager->IsDomain()) { if (manager->IsDomain()) {
context->AddDomainObject(std::move(iface)); context->AddDomainObject(std::move(iface));
} else { } else {
kernel.ApplicationProcess()->GetResourceLimit()->Reserve( ASSERT(Kernel::GetCurrentProcess(kernel).GetResourceLimit()->Reserve(
Kernel::LimitableResource::SessionCountMax, 1); Kernel::LimitableResource::SessionCountMax, 1));
auto* session = Kernel::KSession::Create(kernel); auto* session = Kernel::KSession::Create(kernel);
session->Initialize(nullptr, 0); session->Initialize(nullptr, 0);

View File

@@ -47,7 +47,7 @@ ServerManager::~ServerManager() {
m_stopped.Wait(); m_stopped.Wait();
m_threads.clear(); m_threads.clear();
// Clean up ports. // Clean up server ports.
for (const auto& [port, handler] : m_ports) { for (const auto& [port, handler] : m_ports) {
port->Close(); port->Close();
} }
@@ -97,22 +97,15 @@ Result ServerManager::RegisterNamedService(const std::string& service_name,
u32 max_sessions) { u32 max_sessions) {
ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects); ASSERT(m_sessions.size() + m_ports.size() < MaximumWaitObjects);
// Add the new server to sm:. // Add the new server to sm: and get the moved server port.
ASSERT(R_SUCCEEDED( Kernel::KServerPort* server_port{};
m_system.ServiceManager().RegisterService(service_name, max_sessions, handler_factory))); R_ASSERT(m_system.ServiceManager().RegisterService(std::addressof(server_port), service_name,
max_sessions, handler_factory));
// Get the registered port.
Kernel::KPort* port{};
ASSERT(
R_SUCCEEDED(m_system.ServiceManager().GetServicePort(std::addressof(port), service_name)));
// Open a new reference to the server port.
port->GetServerPort().Open();
// Begin tracking the server port. // Begin tracking the server port.
{ {
std::scoped_lock ll{m_list_mutex}; std::scoped_lock ll{m_list_mutex};
m_ports.emplace(std::addressof(port->GetServerPort()), std::move(handler_factory)); m_ports.emplace(server_port, std::move(handler_factory));
} }
// Signal the wakeup event. // Signal the wakeup event.
@@ -372,7 +365,7 @@ Result ServerManager::OnSessionEvent(Kernel::KServerSession* session,
// Try to receive a message. // Try to receive a message.
std::shared_ptr<HLERequestContext> context; std::shared_ptr<HLERequestContext> context;
rc = session->ReceiveRequest(&context, manager); rc = session->ReceiveRequestHLE(&context, manager);
// If the session has been closed, we're done. // If the session has been closed, we're done.
if (rc == Kernel::ResultSessionClosed) { if (rc == Kernel::ResultSessionClosed) {

View File

@@ -507,6 +507,14 @@ void SET_SYS::SetTvSettings(HLERequestContext& ctx) {
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
} }
void SET_SYS::GetDebugModeFlag(HLERequestContext& ctx) {
LOG_DEBUG(Service_SET, "called");
IPC::ResponseBuilder rb{ctx, 3};
rb.Push(ResultSuccess);
rb.Push<u32>(0);
}
void SET_SYS::GetQuestFlag(HLERequestContext& ctx) { void SET_SYS::GetQuestFlag(HLERequestContext& ctx) {
LOG_WARNING(Service_SET, "(STUBBED) called"); LOG_WARNING(Service_SET, "(STUBBED) called");
@@ -926,7 +934,7 @@ SET_SYS::SET_SYS(Core::System& system_) : ServiceFramework{system_, "set:sys"},
{59, &SET_SYS::SetNetworkSystemClockContext, "SetNetworkSystemClockContext"}, {59, &SET_SYS::SetNetworkSystemClockContext, "SetNetworkSystemClockContext"},
{60, &SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled, "IsUserSystemClockAutomaticCorrectionEnabled"}, {60, &SET_SYS::IsUserSystemClockAutomaticCorrectionEnabled, "IsUserSystemClockAutomaticCorrectionEnabled"},
{61, &SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled, "SetUserSystemClockAutomaticCorrectionEnabled"}, {61, &SET_SYS::SetUserSystemClockAutomaticCorrectionEnabled, "SetUserSystemClockAutomaticCorrectionEnabled"},
{62, nullptr, "GetDebugModeFlag"}, {62, &SET_SYS::GetDebugModeFlag, "GetDebugModeFlag"},
{63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"}, {63, &SET_SYS::GetPrimaryAlbumStorage, "GetPrimaryAlbumStorage"},
{64, nullptr, "SetPrimaryAlbumStorage"}, {64, nullptr, "SetPrimaryAlbumStorage"},
{65, nullptr, "GetUsb30EnableFlag"}, {65, nullptr, "GetUsb30EnableFlag"},
@@ -1143,6 +1151,8 @@ void SET_SYS::StoreSettings() {
} }
void SET_SYS::StoreSettingsThreadFunc(std::stop_token stop_token) { void SET_SYS::StoreSettingsThreadFunc(std::stop_token stop_token) {
Common::SetCurrentThreadName("SettingsStore");
while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) { while (Common::StoppableTimedWait(stop_token, std::chrono::minutes(1))) {
std::scoped_lock l{m_save_needed_mutex}; std::scoped_lock l{m_save_needed_mutex};
if (!std::exchange(m_save_needed, false)) { if (!std::exchange(m_save_needed, false)) {

View File

@@ -98,6 +98,7 @@ private:
void GetSettingsItemValue(HLERequestContext& ctx); void GetSettingsItemValue(HLERequestContext& ctx);
void GetTvSettings(HLERequestContext& ctx); void GetTvSettings(HLERequestContext& ctx);
void SetTvSettings(HLERequestContext& ctx); void SetTvSettings(HLERequestContext& ctx);
void GetDebugModeFlag(HLERequestContext& ctx);
void GetQuestFlag(HLERequestContext& ctx); void GetQuestFlag(HLERequestContext& ctx);
void GetDeviceTimeZoneLocationName(HLERequestContext& ctx); void GetDeviceTimeZoneLocationName(HLERequestContext& ctx);
void SetDeviceTimeZoneLocationName(HLERequestContext& ctx); void SetDeviceTimeZoneLocationName(HLERequestContext& ctx);

View File

@@ -29,8 +29,7 @@ ServiceManager::ServiceManager(Kernel::KernelCore& kernel_) : kernel{kernel_} {
ServiceManager::~ServiceManager() { ServiceManager::~ServiceManager() {
for (auto& [name, port] : service_ports) { for (auto& [name, port] : service_ports) {
port->GetClientPort().Close(); port->Close();
port->GetServerPort().Close();
} }
if (deferral_event) { if (deferral_event) {
@@ -50,8 +49,8 @@ static Result ValidateServiceName(const std::string& name) {
return ResultSuccess; return ResultSuccess;
} }
Result ServiceManager::RegisterService(std::string name, u32 max_sessions, Result ServiceManager::RegisterService(Kernel::KServerPort** out_server_port, std::string name,
SessionRequestHandlerFactory handler) { u32 max_sessions, SessionRequestHandlerFactory handler) {
R_TRY(ValidateServiceName(name)); R_TRY(ValidateServiceName(name));
std::scoped_lock lk{lock}; std::scoped_lock lk{lock};
@@ -66,13 +65,17 @@ Result ServiceManager::RegisterService(std::string name, u32 max_sessions,
// Register the port. // Register the port.
Kernel::KPort::Register(kernel, port); Kernel::KPort::Register(kernel, port);
service_ports.emplace(name, port); service_ports.emplace(name, std::addressof(port->GetClientPort()));
registered_services.emplace(name, handler); registered_services.emplace(name, handler);
if (deferral_event) { if (deferral_event) {
deferral_event->Signal(); deferral_event->Signal();
} }
return ResultSuccess; // Set our output.
*out_server_port = std::addressof(port->GetServerPort());
// We succeeded.
R_SUCCEED();
} }
Result ServiceManager::UnregisterService(const std::string& name) { Result ServiceManager::UnregisterService(const std::string& name) {
@@ -91,7 +94,8 @@ Result ServiceManager::UnregisterService(const std::string& name) {
return ResultSuccess; return ResultSuccess;
} }
Result ServiceManager::GetServicePort(Kernel::KPort** out_port, const std::string& name) { Result ServiceManager::GetServicePort(Kernel::KClientPort** out_client_port,
const std::string& name) {
R_TRY(ValidateServiceName(name)); R_TRY(ValidateServiceName(name));
std::scoped_lock lk{lock}; std::scoped_lock lk{lock};
@@ -101,7 +105,7 @@ Result ServiceManager::GetServicePort(Kernel::KPort** out_port, const std::strin
return Service::SM::ResultNotRegistered; return Service::SM::ResultNotRegistered;
} }
*out_port = it->second; *out_client_port = it->second;
return ResultSuccess; return ResultSuccess;
} }
@@ -172,8 +176,8 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques
std::string name(PopServiceName(rp)); std::string name(PopServiceName(rp));
// Find the named port. // Find the named port.
Kernel::KPort* port{}; Kernel::KClientPort* client_port{};
auto port_result = service_manager.GetServicePort(&port, name); auto port_result = service_manager.GetServicePort(&client_port, name);
if (port_result == Service::SM::ResultInvalidServiceName) { if (port_result == Service::SM::ResultInvalidServiceName) {
LOG_ERROR(Service_SM, "Invalid service name '{}'", name); LOG_ERROR(Service_SM, "Invalid service name '{}'", name);
return Service::SM::ResultInvalidServiceName; return Service::SM::ResultInvalidServiceName;
@@ -187,7 +191,7 @@ Result SM::GetServiceImpl(Kernel::KClientSession** out_client_session, HLEReques
// Create a new session. // Create a new session.
Kernel::KClientSession* session{}; Kernel::KClientSession* session{};
if (const auto result = port->GetClientPort().CreateSession(&session); result.IsError()) { if (const auto result = client_port->CreateSession(&session); result.IsError()) {
LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw); LOG_ERROR(Service_SM, "called service={} -> error 0x{:08X}", name, result.raw);
return result; return result;
} }
@@ -221,7 +225,9 @@ void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_s
LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name, LOG_DEBUG(Service_SM, "called with name={}, max_session_count={}, is_light={}", name,
max_session_count, is_light); max_session_count, is_light);
if (const auto result = service_manager.RegisterService(name, max_session_count, nullptr); Kernel::KServerPort* server_port{};
if (const auto result = service_manager.RegisterService(std::addressof(server_port), name,
max_session_count, nullptr);
result.IsError()) { result.IsError()) {
LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", result.raw); LOG_ERROR(Service_SM, "failed to register service with error_code={:08X}", result.raw);
IPC::ResponseBuilder rb{ctx, 2}; IPC::ResponseBuilder rb{ctx, 2};
@@ -229,13 +235,9 @@ void SM::RegisterServiceImpl(HLERequestContext& ctx, std::string name, u32 max_s
return; return;
} }
auto* port = Kernel::KPort::Create(kernel);
port->Initialize(ServerSessionCountMax, is_light, 0);
SCOPE_EXIT({ port->GetClientPort().Close(); });
IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles}; IPC::ResponseBuilder rb{ctx, 2, 0, 1, IPC::ResponseBuilder::Flags::AlwaysMoveHandles};
rb.Push(ResultSuccess); rb.Push(ResultSuccess);
rb.PushMoveObjects(port->GetServerPort()); rb.PushMoveObjects(server_port);
} }
void SM::UnregisterService(HLERequestContext& ctx) { void SM::UnregisterService(HLERequestContext& ctx) {

View File

@@ -56,10 +56,10 @@ public:
explicit ServiceManager(Kernel::KernelCore& kernel_); explicit ServiceManager(Kernel::KernelCore& kernel_);
~ServiceManager(); ~ServiceManager();
Result RegisterService(std::string name, u32 max_sessions, Result RegisterService(Kernel::KServerPort** out_server_port, std::string name,
SessionRequestHandlerFactory handler_factory); u32 max_sessions, SessionRequestHandlerFactory handler_factory);
Result UnregisterService(const std::string& name); Result UnregisterService(const std::string& name);
Result GetServicePort(Kernel::KPort** out_port, const std::string& name); Result GetServicePort(Kernel::KClientPort** out_client_port, const std::string& name);
template <Common::DerivedFrom<SessionRequestHandler> T> template <Common::DerivedFrom<SessionRequestHandler> T>
std::shared_ptr<T> GetService(const std::string& service_name) const { std::shared_ptr<T> GetService(const std::string& service_name) const {
@@ -84,7 +84,7 @@ private:
/// Map of registered services, retrieved using GetServicePort. /// Map of registered services, retrieved using GetServicePort.
std::mutex lock; std::mutex lock;
std::unordered_map<std::string, SessionRequestHandlerFactory> registered_services; std::unordered_map<std::string, SessionRequestHandlerFactory> registered_services;
std::unordered_map<std::string, Kernel::KPort*> service_ports; std::unordered_map<std::string, Kernel::KClientPort*> service_ports;
/// Kernel context /// Kernel context
Kernel::KernelCore& kernel; Kernel::KernelCore& kernel;

View File

@@ -28,7 +28,6 @@ void Controller::ConvertCurrentObjectToDomain(HLERequestContext& ctx) {
void Controller::CloneCurrentObject(HLERequestContext& ctx) { void Controller::CloneCurrentObject(HLERequestContext& ctx) {
LOG_DEBUG(Service, "called"); LOG_DEBUG(Service, "called");
auto& process = *ctx.GetThread().GetOwnerProcess();
auto session_manager = ctx.GetManager(); auto session_manager = ctx.GetManager();
// FIXME: this is duplicated from the SVC, it should just call it instead // FIXME: this is duplicated from the SVC, it should just call it instead
@@ -36,11 +35,11 @@ void Controller::CloneCurrentObject(HLERequestContext& ctx) {
// Reserve a new session from the process resource limit. // Reserve a new session from the process resource limit.
Kernel::KScopedResourceReservation session_reservation( Kernel::KScopedResourceReservation session_reservation(
&process, Kernel::LimitableResource::SessionCountMax); Kernel::GetCurrentProcessPointer(kernel), Kernel::LimitableResource::SessionCountMax);
ASSERT(session_reservation.Succeeded()); ASSERT(session_reservation.Succeeded());
// Create the session. // Create the session.
Kernel::KSession* session = Kernel::KSession::Create(system.Kernel()); Kernel::KSession* session = Kernel::KSession::Create(kernel);
ASSERT(session != nullptr); ASSERT(session != nullptr);
// Initialize the session. // Initialize the session.
@@ -50,7 +49,7 @@ void Controller::CloneCurrentObject(HLERequestContext& ctx) {
session_reservation.Commit(); session_reservation.Commit();
// Register the session. // Register the session.
Kernel::KSession::Register(system.Kernel(), session); Kernel::KSession::Register(kernel, session);
// Register with server manager. // Register with server manager.
session_manager->GetServerManager().RegisterSession(&session->GetServerSession(), session_manager->GetServerManager().RegisterSession(&session->GetServerSession(),

View File

@@ -129,9 +129,10 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
} }
metadata.Print(); metadata.Print();
// Enable NCE only for programs with 39-bit address space. // Enable NCE only for applications with 39-bit address space.
const bool is_39bit = const bool is_39bit =
metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit; metadata.GetAddressSpaceType() == FileSys::ProgramAddressSpaceType::Is39Bit;
const bool is_application = metadata.GetPoolPartition() == FileSys::PoolPartition::Application;
Settings::SetNceEnabled(is_39bit); Settings::SetNceEnabled(is_39bit);
const std::array static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2", const std::array static_modules = {"rtld", "main", "subsdk0", "subsdk1", "subsdk2",
@@ -147,7 +148,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
const auto GetPatcher = [&](size_t i) -> Core::NCE::Patcher* { const auto GetPatcher = [&](size_t i) -> Core::NCE::Patcher* {
#ifdef HAS_NCE #ifdef HAS_NCE
if (Settings::IsNceEnabled()) { if (is_application && Settings::IsNceEnabled()) {
return &module_patchers[i]; return &module_patchers[i];
} }
#endif #endif
@@ -175,7 +176,7 @@ AppLoader_DeconstructedRomDirectory::LoadResult AppLoader_DeconstructedRomDirect
// Enable direct memory mapping in case of NCE. // Enable direct memory mapping in case of NCE.
const u64 fastmem_base = [&]() -> size_t { const u64 fastmem_base = [&]() -> size_t {
if (Settings::IsNceEnabled()) { if (is_application && Settings::IsNceEnabled()) {
auto& buffer = system.DeviceMemory().buffer; auto& buffer = system.DeviceMemory().buffer;
buffer.EnableDirectMappedAddress(); buffer.EnableDirectMappedAddress();
return reinterpret_cast<u64>(buffer.VirtualBasePointer()); return reinterpret_cast<u64>(buffer.VirtualBasePointer());

View File

@@ -45,7 +45,13 @@ struct Memory::Impl {
void SetCurrentPageTable(Kernel::KProcess& process) { void SetCurrentPageTable(Kernel::KProcess& process) {
current_page_table = &process.GetPageTable().GetImpl(); current_page_table = &process.GetPageTable().GetImpl();
if (std::addressof(process) == system.ApplicationProcess() &&
Settings::IsFastmemEnabled()) {
current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer(); current_page_table->fastmem_arena = system.DeviceMemory().buffer.VirtualBasePointer();
} else {
current_page_table->fastmem_arena = nullptr;
}
} }
void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size, void MapMemoryRegion(Common::PageTable& page_table, Common::ProcessAddress base, u64 size,
@@ -57,7 +63,7 @@ struct Memory::Impl {
MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target, MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, target,
Common::PageType::Memory); Common::PageType::Memory);
if (Settings::IsFastmemEnabled()) { if (current_page_table->fastmem_arena) {
system.DeviceMemory().buffer.Map(GetInteger(base), system.DeviceMemory().buffer.Map(GetInteger(base),
GetInteger(target) - DramMemoryMap::Base, size, perms); GetInteger(target) - DramMemoryMap::Base, size, perms);
} }
@@ -69,7 +75,7 @@ struct Memory::Impl {
MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0, MapPages(page_table, base / YUZU_PAGESIZE, size / YUZU_PAGESIZE, 0,
Common::PageType::Unmapped); Common::PageType::Unmapped);
if (Settings::IsFastmemEnabled()) { if (current_page_table->fastmem_arena) {
system.DeviceMemory().buffer.Unmap(GetInteger(base), size); system.DeviceMemory().buffer.Unmap(GetInteger(base), size);
} }
} }
@@ -79,7 +85,7 @@ struct Memory::Impl {
ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size); ASSERT_MSG((size & YUZU_PAGEMASK) == 0, "non-page aligned size: {:016X}", size);
ASSERT_MSG((vaddr & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", vaddr); ASSERT_MSG((vaddr & YUZU_PAGEMASK) == 0, "non-page aligned base: {:016X}", vaddr);
if (!Settings::IsFastmemEnabled()) { if (!current_page_table->fastmem_arena) {
return; return;
} }
@@ -88,11 +94,6 @@ struct Memory::Impl {
const bool is_x = const bool is_x =
True(perms & Common::MemoryPermission::Execute) && Settings::IsNceEnabled(); True(perms & Common::MemoryPermission::Execute) && Settings::IsNceEnabled();
if (!current_page_table) {
system.DeviceMemory().buffer.Protect(vaddr, size, is_r, is_w, is_x);
return;
}
u64 protect_bytes{}; u64 protect_bytes{};
u64 protect_begin{}; u64 protect_begin{};
for (u64 addr = vaddr; addr < vaddr + size; addr += YUZU_PAGESIZE) { for (u64 addr = vaddr; addr < vaddr + size; addr += YUZU_PAGESIZE) {
@@ -239,7 +240,7 @@ struct Memory::Impl {
bool WalkBlock(const Common::ProcessAddress addr, const std::size_t size, auto on_unmapped, bool WalkBlock(const Common::ProcessAddress addr, const std::size_t size, auto on_unmapped,
auto on_memory, auto on_rasterizer, auto increment) { auto on_memory, auto on_rasterizer, auto increment) {
const auto& page_table = system.ApplicationProcess()->GetPageTable().GetImpl(); const auto& page_table = *current_page_table;
std::size_t remaining_size = size; std::size_t remaining_size = size;
std::size_t page_index = addr >> YUZU_PAGEBITS; std::size_t page_index = addr >> YUZU_PAGEBITS;
std::size_t page_offset = addr & YUZU_PAGEMASK; std::size_t page_offset = addr & YUZU_PAGEMASK;
@@ -484,7 +485,7 @@ struct Memory::Impl {
return; return;
} }
if (Settings::IsFastmemEnabled()) { if (current_page_table->fastmem_arena) {
system.DeviceMemory().buffer.Protect(vaddr, size, !debug, !debug); system.DeviceMemory().buffer.Protect(vaddr, size, !debug, !debug);
} }
@@ -541,7 +542,7 @@ struct Memory::Impl {
return; return;
} }
if (Settings::IsFastmemEnabled()) { if (current_page_table->fastmem_arena) {
const bool is_read_enable = const bool is_read_enable =
!Settings::values.use_reactive_flushing.GetValue() || !cached; !Settings::values.use_reactive_flushing.GetValue() || !cached;
system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached); system.DeviceMemory().buffer.Protect(vaddr, size, is_read_enable, !cached);
@@ -886,8 +887,7 @@ void Memory::ProtectRegion(Common::PageTable& page_table, Common::ProcessAddress
} }
bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const { bool Memory::IsValidVirtualAddress(const Common::ProcessAddress vaddr) const {
const Kernel::KProcess& process = *system.ApplicationProcess(); const auto& page_table = *impl->current_page_table;
const auto& page_table = process.GetPageTable().GetImpl();
const size_t page = vaddr >> YUZU_PAGEBITS; const size_t page = vaddr >> YUZU_PAGEBITS;
if (page >= page_table.pointers.size()) { if (page >= page_table.pointers.size()) {
return false; return false;

View File

@@ -214,16 +214,16 @@ Id TextureImage(EmitContext& ctx, IR::TextureInstInfo info, const IR::Value& ind
} }
} }
Id Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) { std::pair<Id, bool> Image(EmitContext& ctx, const IR::Value& index, IR::TextureInstInfo info) {
if (!index.IsImmediate() || index.U32() != 0) { if (!index.IsImmediate() || index.U32() != 0) {
throw NotImplementedException("Indirect image indexing"); throw NotImplementedException("Indirect image indexing");
} }
if (info.type == TextureType::Buffer) { if (info.type == TextureType::Buffer) {
const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)}; const ImageBufferDefinition def{ctx.image_buffers.at(info.descriptor_index)};
return ctx.OpLoad(def.image_type, def.id); return {ctx.OpLoad(def.image_type, def.id), def.is_integer};
} else { } else {
const ImageDefinition def{ctx.images.at(info.descriptor_index)}; const ImageDefinition def{ctx.images.at(info.descriptor_index)};
return ctx.OpLoad(def.image_type, def.id); return {ctx.OpLoad(def.image_type, def.id), def.is_integer};
} }
} }
@@ -566,13 +566,23 @@ Id EmitImageRead(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id co
LOG_WARNING(Shader_SPIRV, "Typeless image read not supported by host"); LOG_WARNING(Shader_SPIRV, "Typeless image read not supported by host");
return ctx.ConstantNull(ctx.U32[4]); return ctx.ConstantNull(ctx.U32[4]);
} }
return Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst, ctx.U32[4], const auto [image, is_integer] = Image(ctx, index, info);
Image(ctx, index, info), coords, std::nullopt, std::span<const Id>{}); const Id result_type{is_integer ? ctx.U32[4] : ctx.F32[4]};
Id color{Emit(&EmitContext::OpImageSparseRead, &EmitContext::OpImageRead, ctx, inst,
result_type, image, coords, std::nullopt, std::span<const Id>{})};
if (!is_integer) {
color = ctx.OpBitcast(ctx.U32[4], color);
}
return color;
} }
void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) { void EmitImageWrite(EmitContext& ctx, IR::Inst* inst, const IR::Value& index, Id coords, Id color) {
const auto info{inst->Flags<IR::TextureInstInfo>()}; const auto info{inst->Flags<IR::TextureInstInfo>()};
ctx.OpImageWrite(Image(ctx, index, info), coords, color); const auto [image, is_integer] = Image(ctx, index, info);
if (!is_integer) {
color = ctx.OpBitcast(ctx.F32[4], color);
}
ctx.OpImageWrite(image, coords, color);
} }
Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) { Id EmitIsTextureScaled(EmitContext& ctx, const IR::Value& index) {

View File

@@ -74,20 +74,19 @@ spv::ImageFormat GetImageFormat(ImageFormat format) {
throw InvalidArgument("Invalid image format {}", format); throw InvalidArgument("Invalid image format {}", format);
} }
Id ImageType(EmitContext& ctx, const ImageDescriptor& desc) { Id ImageType(EmitContext& ctx, const ImageDescriptor& desc, Id sampled_type) {
const spv::ImageFormat format{GetImageFormat(desc.format)}; const spv::ImageFormat format{GetImageFormat(desc.format)};
const Id type{ctx.U32[1]};
switch (desc.type) { switch (desc.type) {
case TextureType::Color1D: case TextureType::Color1D:
return ctx.TypeImage(type, spv::Dim::Dim1D, false, false, false, 2, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, false, false, 2, format);
case TextureType::ColorArray1D: case TextureType::ColorArray1D:
return ctx.TypeImage(type, spv::Dim::Dim1D, false, true, false, 2, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim1D, false, true, false, 2, format);
case TextureType::Color2D: case TextureType::Color2D:
return ctx.TypeImage(type, spv::Dim::Dim2D, false, false, false, 2, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, false, false, 2, format);
case TextureType::ColorArray2D: case TextureType::ColorArray2D:
return ctx.TypeImage(type, spv::Dim::Dim2D, false, true, false, 2, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim2D, false, true, false, 2, format);
case TextureType::Color3D: case TextureType::Color3D:
return ctx.TypeImage(type, spv::Dim::Dim3D, false, false, false, 2, format); return ctx.TypeImage(sampled_type, spv::Dim::Dim3D, false, false, false, 2, format);
case TextureType::Buffer: case TextureType::Buffer:
throw NotImplementedException("Image buffer"); throw NotImplementedException("Image buffer");
default: default:
@@ -1273,7 +1272,9 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) {
throw NotImplementedException("Array of image buffers"); throw NotImplementedException("Array of image buffers");
} }
const spv::ImageFormat format{GetImageFormat(desc.format)}; const spv::ImageFormat format{GetImageFormat(desc.format)};
const Id image_type{TypeImage(U32[1], spv::Dim::Buffer, false, false, false, 2, format)}; const Id sampled_type{desc.is_integer ? U32[1] : F32[1]};
const Id image_type{
TypeImage(sampled_type, spv::Dim::Buffer, false, false, false, 2, format)};
const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)};
const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)};
Decorate(id, spv::Decoration::Binding, binding); Decorate(id, spv::Decoration::Binding, binding);
@@ -1283,6 +1284,7 @@ void EmitContext::DefineImageBuffers(const Info& info, u32& binding) {
.id = id, .id = id,
.image_type = image_type, .image_type = image_type,
.count = desc.count, .count = desc.count,
.is_integer = desc.is_integer,
}); });
if (profile.supported_spirv >= 0x00010400) { if (profile.supported_spirv >= 0x00010400) {
interfaces.push_back(id); interfaces.push_back(id);
@@ -1327,7 +1329,8 @@ void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_inde
if (desc.count != 1) { if (desc.count != 1) {
throw NotImplementedException("Array of images"); throw NotImplementedException("Array of images");
} }
const Id image_type{ImageType(*this, desc)}; const Id sampled_type{desc.is_integer ? U32[1] : F32[1]};
const Id image_type{ImageType(*this, desc, sampled_type)};
const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)}; const Id pointer_type{TypePointer(spv::StorageClass::UniformConstant, image_type)};
const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)}; const Id id{AddGlobalVariable(pointer_type, spv::StorageClass::UniformConstant)};
Decorate(id, spv::Decoration::Binding, binding); Decorate(id, spv::Decoration::Binding, binding);
@@ -1337,6 +1340,7 @@ void EmitContext::DefineImages(const Info& info, u32& binding, u32& scaling_inde
.id = id, .id = id,
.image_type = image_type, .image_type = image_type,
.count = desc.count, .count = desc.count,
.is_integer = desc.is_integer,
}); });
if (profile.supported_spirv >= 0x00010400) { if (profile.supported_spirv >= 0x00010400) {
interfaces.push_back(id); interfaces.push_back(id);

View File

@@ -47,12 +47,14 @@ struct ImageBufferDefinition {
Id id; Id id;
Id image_type; Id image_type;
u32 count; u32 count;
bool is_integer;
}; };
struct ImageDefinition { struct ImageDefinition {
Id id; Id id;
Id image_type; Id image_type;
u32 count; u32 count;
bool is_integer;
}; };
struct UniformDefinitions { struct UniformDefinitions {

View File

@@ -24,6 +24,8 @@ public:
[[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0; [[nodiscard]] virtual TexturePixelFormat ReadTexturePixelFormat(u32 raw_handle) = 0;
[[nodiscard]] virtual bool IsTexturePixelFormatInteger(u32 raw_handle) = 0;
[[nodiscard]] virtual u32 ReadViewportTransformState() = 0; [[nodiscard]] virtual u32 ReadViewportTransformState() = 0;
[[nodiscard]] virtual u32 TextureBoundBuffer() const = 0; [[nodiscard]] virtual u32 TextureBoundBuffer() const = 0;

View File

@@ -815,6 +815,15 @@ bool FindGradient3DDerivatives(std::array<IR::Value, 3>& results, IR::Value coor
return true; return true;
} }
void ConvertDerivatives(std::array<IR::Value, 3>& results, IR::IREmitter& ir) {
for (size_t i = 0; i < 3; i++) {
if (results[i].Type() == IR::Type::U32) {
results[i] = results[i].IsImmediate() ? ir.Imm32(Common::BitCast<f32>(results[i].U32()))
: ir.BitCast<IR::F32>(IR::U32(results[i]));
}
}
}
void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) { void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
IR::TextureInstInfo info = inst.Flags<IR::TextureInstInfo>(); IR::TextureInstInfo info = inst.Flags<IR::TextureInstInfo>();
auto orig_opcode = inst.GetOpcode(); auto orig_opcode = inst.GetOpcode();
@@ -831,12 +840,14 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
if (!offset.IsImmediate()) { if (!offset.IsImmediate()) {
return; return;
} }
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
IR::Inst* const inst2 = coords.InstRecursive(); IR::Inst* const inst2 = coords.InstRecursive();
std::array<std::array<IR::Value, 3>, 3> results_matrix; std::array<std::array<IR::Value, 3>, 3> results_matrix;
for (size_t i = 0; i < 3; i++) { for (size_t i = 0; i < 3; i++) {
if (!FindGradient3DDerivatives(results_matrix[i], inst2->Arg(i).Resolve())) { if (!FindGradient3DDerivatives(results_matrix[i], inst2->Arg(i).Resolve())) {
return; return;
} }
ConvertDerivatives(results_matrix[i], ir);
} }
IR::F32 lod_clamp{}; IR::F32 lod_clamp{};
if (info.has_lod_clamp != 0) { if (info.has_lod_clamp != 0) {
@@ -846,7 +857,6 @@ void FoldImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
lod_clamp = IR::F32{bias_lc}; lod_clamp = IR::F32{bias_lc};
} }
} }
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
IR::Value new_coords = IR::Value new_coords =
ir.CompositeConstruct(results_matrix[0][0], results_matrix[1][0], results_matrix[2][0]); ir.CompositeConstruct(results_matrix[0][0], results_matrix[1][0], results_matrix[2][0]);
IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2], IR::Value derivatives_1 = ir.CompositeConstruct(results_matrix[0][1], results_matrix[0][2],

View File

@@ -372,6 +372,10 @@ TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAdd
return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf)); return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf));
} }
bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) {
return env.IsTexturePixelFormatInteger(GetTextureHandle(env, cbuf));
}
class Descriptors { class Descriptors {
public: public:
explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_, explicit Descriptors(TextureBufferDescriptors& texture_buffer_descriptors_,
@@ -403,6 +407,7 @@ public:
})}; })};
image_buffer_descriptors[index].is_written |= desc.is_written; image_buffer_descriptors[index].is_written |= desc.is_written;
image_buffer_descriptors[index].is_read |= desc.is_read; image_buffer_descriptors[index].is_read |= desc.is_read;
image_buffer_descriptors[index].is_integer |= desc.is_integer;
return index; return index;
} }
@@ -432,6 +437,7 @@ public:
})}; })};
image_descriptors[index].is_written |= desc.is_written; image_descriptors[index].is_written |= desc.is_written;
image_descriptors[index].is_read |= desc.is_read; image_descriptors[index].is_read |= desc.is_read;
image_descriptors[index].is_integer |= desc.is_integer;
return index; return index;
} }
@@ -469,6 +475,20 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1)))))); ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1))))));
} }
bool IsPixelFormatSNorm(TexturePixelFormat pixel_format) {
switch (pixel_format) {
case TexturePixelFormat::A8B8G8R8_SNORM:
case TexturePixelFormat::R8G8_SNORM:
case TexturePixelFormat::R8_SNORM:
case TexturePixelFormat::R16G16B16A16_SNORM:
case TexturePixelFormat::R16G16_SNORM:
case TexturePixelFormat::R16_SNORM:
return true;
default:
return false;
}
}
void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) { void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_format) {
const auto it{IR::Block::InstructionList::s_iterator_to(inst)}; const auto it{IR::Block::InstructionList::s_iterator_to(inst)};
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)}; IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
@@ -587,11 +607,13 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
} }
const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead}; const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead};
const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite}; const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite};
const bool is_integer{IsTexturePixelFormatInteger(env, cbuf)};
if (flags.type == TextureType::Buffer) { if (flags.type == TextureType::Buffer) {
index = descriptors.Add(ImageBufferDescriptor{ index = descriptors.Add(ImageBufferDescriptor{
.format = flags.image_format, .format = flags.image_format,
.is_written = is_written, .is_written = is_written,
.is_read = is_read, .is_read = is_read,
.is_integer = is_integer,
.cbuf_index = cbuf.index, .cbuf_index = cbuf.index,
.cbuf_offset = cbuf.offset, .cbuf_offset = cbuf.offset,
.count = cbuf.count, .count = cbuf.count,
@@ -603,6 +625,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
.format = flags.image_format, .format = flags.image_format,
.is_written = is_written, .is_written = is_written,
.is_read = is_read, .is_read = is_read,
.is_integer = is_integer,
.cbuf_index = cbuf.index, .cbuf_index = cbuf.index,
.cbuf_offset = cbuf.offset, .cbuf_offset = cbuf.offset,
.count = cbuf.count, .count = cbuf.count,
@@ -658,7 +681,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch && if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch &&
flags.type == TextureType::Buffer) { flags.type == TextureType::Buffer) {
const auto pixel_format = ReadTexturePixelFormat(env, cbuf); const auto pixel_format = ReadTexturePixelFormat(env, cbuf);
if (pixel_format != TexturePixelFormat::OTHER) { if (IsPixelFormatSNorm(pixel_format)) {
PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format); PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format);
} }
} }

View File

@@ -35,14 +35,109 @@ enum class TextureType : u32 {
}; };
constexpr u32 NUM_TEXTURE_TYPES = 9; constexpr u32 NUM_TEXTURE_TYPES = 9;
enum class TexturePixelFormat : u32 { enum class TexturePixelFormat {
A8B8G8R8_UNORM,
A8B8G8R8_SNORM, A8B8G8R8_SNORM,
A8B8G8R8_SINT,
A8B8G8R8_UINT,
R5G6B5_UNORM,
B5G6R5_UNORM,
A1R5G5B5_UNORM,
A2B10G10R10_UNORM,
A2B10G10R10_UINT,
A2R10G10B10_UNORM,
A1B5G5R5_UNORM,
A5B5G5R1_UNORM,
R8_UNORM,
R8_SNORM, R8_SNORM,
R8G8_SNORM, R8_SINT,
R8_UINT,
R16G16B16A16_FLOAT,
R16G16B16A16_UNORM,
R16G16B16A16_SNORM, R16G16B16A16_SNORM,
R16G16_SNORM, R16G16B16A16_SINT,
R16G16B16A16_UINT,
B10G11R11_FLOAT,
R32G32B32A32_UINT,
BC1_RGBA_UNORM,
BC2_UNORM,
BC3_UNORM,
BC4_UNORM,
BC4_SNORM,
BC5_UNORM,
BC5_SNORM,
BC7_UNORM,
BC6H_UFLOAT,
BC6H_SFLOAT,
ASTC_2D_4X4_UNORM,
B8G8R8A8_UNORM,
R32G32B32A32_FLOAT,
R32G32B32A32_SINT,
R32G32_FLOAT,
R32G32_SINT,
R32_FLOAT,
R16_FLOAT,
R16_UNORM,
R16_SNORM, R16_SNORM,
OTHER R16_UINT,
R16_SINT,
R16G16_UNORM,
R16G16_FLOAT,
R16G16_UINT,
R16G16_SINT,
R16G16_SNORM,
R32G32B32_FLOAT,
A8B8G8R8_SRGB,
R8G8_UNORM,
R8G8_SNORM,
R8G8_SINT,
R8G8_UINT,
R32G32_UINT,
R16G16B16X16_FLOAT,
R32_UINT,
R32_SINT,
ASTC_2D_8X8_UNORM,
ASTC_2D_8X5_UNORM,
ASTC_2D_5X4_UNORM,
B8G8R8A8_SRGB,
BC1_RGBA_SRGB,
BC2_SRGB,
BC3_SRGB,
BC7_SRGB,
A4B4G4R4_UNORM,
G4R4_UNORM,
ASTC_2D_4X4_SRGB,
ASTC_2D_8X8_SRGB,
ASTC_2D_8X5_SRGB,
ASTC_2D_5X4_SRGB,
ASTC_2D_5X5_UNORM,
ASTC_2D_5X5_SRGB,
ASTC_2D_10X8_UNORM,
ASTC_2D_10X8_SRGB,
ASTC_2D_6X6_UNORM,
ASTC_2D_6X6_SRGB,
ASTC_2D_10X6_UNORM,
ASTC_2D_10X6_SRGB,
ASTC_2D_10X5_UNORM,
ASTC_2D_10X5_SRGB,
ASTC_2D_10X10_UNORM,
ASTC_2D_10X10_SRGB,
ASTC_2D_12X10_UNORM,
ASTC_2D_12X10_SRGB,
ASTC_2D_12X12_UNORM,
ASTC_2D_12X12_SRGB,
ASTC_2D_8X6_UNORM,
ASTC_2D_8X6_SRGB,
ASTC_2D_6X5_UNORM,
ASTC_2D_6X5_SRGB,
E5B9G9R9_FLOAT,
D32_FLOAT,
D16_UNORM,
X8_D24_UNORM,
S8_UINT,
D24_UNORM_S8_UINT,
S8_UINT_D24_UNORM,
D32_FLOAT_S8_UINT,
}; };
enum class ImageFormat : u32 { enum class ImageFormat : u32 {
@@ -97,6 +192,7 @@ struct ImageBufferDescriptor {
ImageFormat format; ImageFormat format;
bool is_written; bool is_written;
bool is_read; bool is_read;
bool is_integer;
u32 cbuf_index; u32 cbuf_index;
u32 cbuf_offset; u32 cbuf_offset;
u32 count; u32 count;
@@ -129,6 +225,7 @@ struct ImageDescriptor {
ImageFormat format; ImageFormat format;
bool is_written; bool is_written;
bool is_read; bool is_read;
bool is_integer;
u32 cbuf_index; u32 cbuf_index;
u32 cbuf_offset; u32 cbuf_offset;
u32 count; u32 count;

View File

@@ -586,14 +586,22 @@ void Maxwell3D::ProcessQueryCondition() {
} }
void Maxwell3D::ProcessCounterReset() { void Maxwell3D::ProcessCounterReset() {
switch (regs.clear_report_value) { const auto query_type = [clear_report = regs.clear_report_value]() {
case Regs::ClearReport::ZPassPixelCount: switch (clear_report) {
rasterizer->ResetCounter(VideoCommon::QueryType::ZPassPixelCount64); case Tegra::Engines::Maxwell3D::Regs::ClearReport::ZPassPixelCount:
break; return VideoCommon::QueryType::ZPassPixelCount64;
case Tegra::Engines::Maxwell3D::Regs::ClearReport::StreamingPrimitivesSucceeded:
return VideoCommon::QueryType::StreamingPrimitivesSucceeded;
case Tegra::Engines::Maxwell3D::Regs::ClearReport::PrimitivesGenerated:
return VideoCommon::QueryType::PrimitivesGenerated;
case Tegra::Engines::Maxwell3D::Regs::ClearReport::VtgPrimitivesOut:
return VideoCommon::QueryType::VtgPrimitivesOut;
default: default:
LOG_DEBUG(Render_OpenGL, "Unimplemented counter reset={}", regs.clear_report_value); LOG_DEBUG(HW_GPU, "Unimplemented counter reset={}", clear_report);
break; return VideoCommon::QueryType::Payload;
} }
}();
rasterizer->ResetCounter(query_type);
} }
void Maxwell3D::ProcessSyncPoint() { void Maxwell3D::ProcessSyncPoint() {

View File

@@ -28,8 +28,11 @@
namespace VideoCore { namespace VideoCore {
enum class QueryType { enum class QueryType {
SamplesPassed, SamplesPassed,
PrimitivesGenerated,
TfbPrimitivesWritten,
Count,
}; };
constexpr std::size_t NumQueryTypes = 1; constexpr std::size_t NumQueryTypes = static_cast<size_t>(QueryType::Count);
} // namespace VideoCore } // namespace VideoCore
namespace VideoCommon { namespace VideoCommon {
@@ -44,15 +47,6 @@ public:
explicit CounterStreamBase(QueryCache& cache_, VideoCore::QueryType type_) explicit CounterStreamBase(QueryCache& cache_, VideoCore::QueryType type_)
: cache{cache_}, type{type_} {} : cache{cache_}, type{type_} {}
/// Updates the state of the stream, enabling or disabling as needed.
void Update(bool enabled) {
if (enabled) {
Enable();
} else {
Disable();
}
}
/// Resets the stream to zero. It doesn't disable the query after resetting. /// Resets the stream to zero. It doesn't disable the query after resetting.
void Reset() { void Reset() {
if (current) { if (current) {
@@ -80,7 +74,6 @@ public:
return current != nullptr; return current != nullptr;
} }
private:
/// Enables the stream. /// Enables the stream.
void Enable() { void Enable() {
if (current) { if (current) {
@@ -97,6 +90,7 @@ private:
last = std::exchange(current, nullptr); last = std::exchange(current, nullptr);
} }
private:
QueryCache& cache; QueryCache& cache;
const VideoCore::QueryType type; const VideoCore::QueryType type;
@@ -112,8 +106,14 @@ public:
: rasterizer{rasterizer_}, : rasterizer{rasterizer_},
// Use reinterpret_cast instead of static_cast as workaround for // Use reinterpret_cast instead of static_cast as workaround for
// UBSan bug (https://github.com/llvm/llvm-project/issues/59060) // UBSan bug (https://github.com/llvm/llvm-project/issues/59060)
cpu_memory{cpu_memory_}, streams{{CounterStream{reinterpret_cast<QueryCache&>(*this), cpu_memory{cpu_memory_}, streams{{
VideoCore::QueryType::SamplesPassed}}} { {CounterStream{reinterpret_cast<QueryCache&>(*this),
VideoCore::QueryType::SamplesPassed}},
{CounterStream{reinterpret_cast<QueryCache&>(*this),
VideoCore::QueryType::PrimitivesGenerated}},
{CounterStream{reinterpret_cast<QueryCache&>(*this),
VideoCore::QueryType::TfbPrimitivesWritten}},
}} {
(void)slot_async_jobs.insert(); // Null value (void)slot_async_jobs.insert(); // Null value
} }
@@ -157,12 +157,11 @@ public:
AsyncFlushQuery(query, timestamp, lock); AsyncFlushQuery(query, timestamp, lock);
} }
/// Updates counters from GPU state. Expected to be called once per draw, clear or dispatch. /// Enables all available GPU counters
void UpdateCounters() { void EnableCounters() {
std::unique_lock lock{mutex}; std::unique_lock lock{mutex};
if (maxwell3d) { for (auto& stream : streams) {
const auto& regs = maxwell3d->regs; stream.Enable();
Stream(VideoCore::QueryType::SamplesPassed).Update(regs.zpass_pixel_count_enable);
} }
} }
@@ -176,7 +175,7 @@ public:
void DisableStreams() { void DisableStreams() {
std::unique_lock lock{mutex}; std::unique_lock lock{mutex};
for (auto& stream : streams) { for (auto& stream : streams) {
stream.Update(false); stream.Disable();
} }
} }
@@ -353,7 +352,7 @@ private:
std::shared_ptr<std::vector<AsyncJobId>> uncommitted_flushes{}; std::shared_ptr<std::vector<AsyncJobId>> uncommitted_flushes{};
std::list<std::shared_ptr<std::vector<AsyncJobId>>> committed_flushes; std::list<std::shared_ptr<std::vector<AsyncJobId>>> committed_flushes;
}; }; // namespace VideoCommon
template <class QueryCache, class HostCounter> template <class QueryCache, class HostCounter>
class HostCounterBase { class HostCounterBase {

View File

@@ -18,16 +18,27 @@ namespace OpenGL {
namespace { namespace {
constexpr std::array<GLenum, VideoCore::NumQueryTypes> QueryTargets = {GL_SAMPLES_PASSED};
constexpr GLenum GetTarget(VideoCore::QueryType type) { constexpr GLenum GetTarget(VideoCore::QueryType type) {
return QueryTargets[static_cast<std::size_t>(type)]; switch (type) {
case VideoCore::QueryType::SamplesPassed:
return GL_SAMPLES_PASSED;
case VideoCore::QueryType::PrimitivesGenerated:
return GL_PRIMITIVES_GENERATED;
case VideoCore::QueryType::TfbPrimitivesWritten:
return GL_TRANSFORM_FEEDBACK_PRIMITIVES_WRITTEN;
default:
break;
}
UNIMPLEMENTED_MSG("Query type {}", type);
return 0;
} }
} // Anonymous namespace } // Anonymous namespace
QueryCache::QueryCache(RasterizerOpenGL& rasterizer_, Core::Memory::Memory& cpu_memory_) QueryCache::QueryCache(RasterizerOpenGL& rasterizer_, Core::Memory::Memory& cpu_memory_)
: QueryCacheLegacy(rasterizer_, cpu_memory_), gl_rasterizer{rasterizer_} {} : QueryCacheLegacy(rasterizer_, cpu_memory_), gl_rasterizer{rasterizer_} {
EnableCounters();
}
QueryCache::~QueryCache() = default; QueryCache::~QueryCache() = default;
@@ -103,13 +114,13 @@ u64 CachedQuery::Flush([[maybe_unused]] bool async) {
auto& stream = cache->Stream(type); auto& stream = cache->Stream(type);
const bool slice_counter = WaitPending() && stream.IsEnabled(); const bool slice_counter = WaitPending() && stream.IsEnabled();
if (slice_counter) { if (slice_counter) {
stream.Update(false); stream.Disable();
} }
auto result = VideoCommon::CachedQueryBase<HostCounter>::Flush(); auto result = VideoCommon::CachedQueryBase<HostCounter>::Flush();
if (slice_counter) { if (slice_counter) {
stream.Update(true); stream.Enable();
} }
return result; return result;

View File

@@ -51,6 +51,22 @@ constexpr size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16;
void oglEnable(GLenum cap, bool state) { void oglEnable(GLenum cap, bool state) {
(state ? glEnable : glDisable)(cap); (state ? glEnable : glDisable)(cap);
} }
std::optional<VideoCore::QueryType> MaxwellToVideoCoreQuery(VideoCommon::QueryType type) {
switch (type) {
case VideoCommon::QueryType::PrimitivesGenerated:
case VideoCommon::QueryType::VtgPrimitivesOut:
return VideoCore::QueryType::PrimitivesGenerated;
case VideoCommon::QueryType::ZPassPixelCount64:
return VideoCore::QueryType::SamplesPassed;
case VideoCommon::QueryType::StreamingPrimitivesSucceeded:
// case VideoCommon::QueryType::StreamingByteCount:
// TODO: StreamingByteCount = StreamingPrimitivesSucceeded * num_verts * vert_stride
return VideoCore::QueryType::TfbPrimitivesWritten;
default:
return std::nullopt;
}
}
} // Anonymous namespace } // Anonymous namespace
RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_, RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
@@ -216,7 +232,6 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
SCOPE_EXIT({ gpu.TickWork(); }); SCOPE_EXIT({ gpu.TickWork(); });
gpu_memory->FlushCaching(); gpu_memory->FlushCaching();
query_cache.UpdateCounters();
GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()}; GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()};
if (!pipeline) { if (!pipeline) {
@@ -334,7 +349,6 @@ void RasterizerOpenGL::DrawTexture() {
MICROPROFILE_SCOPE(OpenGL_Drawing); MICROPROFILE_SCOPE(OpenGL_Drawing);
SCOPE_EXIT({ gpu.TickWork(); }); SCOPE_EXIT({ gpu.TickWork(); });
query_cache.UpdateCounters();
texture_cache.SynchronizeGraphicsDescriptors(); texture_cache.SynchronizeGraphicsDescriptors();
texture_cache.UpdateRenderTargets(false); texture_cache.UpdateRenderTargets(false);
@@ -401,21 +415,28 @@ void RasterizerOpenGL::DispatchCompute() {
} }
void RasterizerOpenGL::ResetCounter(VideoCommon::QueryType type) { void RasterizerOpenGL::ResetCounter(VideoCommon::QueryType type) {
if (type == VideoCommon::QueryType::ZPassPixelCount64) { const auto query_cache_type = MaxwellToVideoCoreQuery(type);
query_cache.ResetCounter(VideoCore::QueryType::SamplesPassed); if (!query_cache_type.has_value()) {
UNIMPLEMENTED_IF_MSG(type != VideoCommon::QueryType::Payload, "Reset query type: {}", type);
return;
} }
query_cache.ResetCounter(*query_cache_type);
} }
void RasterizerOpenGL::Query(GPUVAddr gpu_addr, VideoCommon::QueryType type, void RasterizerOpenGL::Query(GPUVAddr gpu_addr, VideoCommon::QueryType type,
VideoCommon::QueryPropertiesFlags flags, u32 payload, u32 subreport) { VideoCommon::QueryPropertiesFlags flags, u32 payload, u32 subreport) {
if (type == VideoCommon::QueryType::ZPassPixelCount64) { const auto query_cache_type = MaxwellToVideoCoreQuery(type);
if (True(flags & VideoCommon::QueryPropertiesFlags::HasTimeout)) { if (!query_cache_type.has_value()) {
query_cache.Query(gpu_addr, VideoCore::QueryType::SamplesPassed, {gpu.GetTicks()}); return QueryFallback(gpu_addr, type, flags, payload, subreport);
} else {
query_cache.Query(gpu_addr, VideoCore::QueryType::SamplesPassed, std::nullopt);
}
return;
} }
const bool has_timeout = True(flags & VideoCommon::QueryPropertiesFlags::HasTimeout);
const auto timestamp = has_timeout ? std::optional<u64>{gpu.GetTicks()} : std::nullopt;
query_cache.Query(gpu_addr, *query_cache_type, timestamp);
}
void RasterizerOpenGL::QueryFallback(GPUVAddr gpu_addr, VideoCommon::QueryType type,
VideoCommon::QueryPropertiesFlags flags, u32 payload,
u32 subreport) {
if (type != VideoCommon::QueryType::Payload) { if (type != VideoCommon::QueryType::Payload) {
payload = 1u; payload = 1u;
} }

View File

@@ -225,6 +225,9 @@ private:
/// End a transform feedback /// End a transform feedback
void EndTransformFeedback(); void EndTransformFeedback();
void QueryFallback(GPUVAddr gpu_addr, VideoCommon::QueryType type,
VideoCommon::QueryPropertiesFlags flags, u32 payload, u32 subreport);
Tegra::GPU& gpu; Tegra::GPU& gpu;
const Device& device; const Device& device;

View File

@@ -51,7 +51,7 @@ using VideoCommon::LoadPipelines;
using VideoCommon::SerializePipeline; using VideoCommon::SerializePipeline;
using Context = ShaderContext::Context; using Context = ShaderContext::Context;
constexpr u32 CACHE_VERSION = 9; constexpr u32 CACHE_VERSION = 10;
template <typename Container> template <typename Container>
auto MakeSpan(Container& container) { auto MakeSpan(Container& container) {

View File

@@ -78,8 +78,15 @@ vk::Buffer CreateBuffer(const Device& device, const MemoryAllocator& memory_allo
} }
} // Anonymous namespace } // Anonymous namespace
Buffer::Buffer(BufferCacheRuntime&, VideoCommon::NullBufferParams null_params) Buffer::Buffer(BufferCacheRuntime& runtime, VideoCommon::NullBufferParams null_params)
: VideoCommon::BufferBase<VideoCore::RasterizerInterface>(null_params), tracker{4096} {} : VideoCommon::BufferBase<VideoCore::RasterizerInterface>(null_params), tracker{4096} {
if (runtime.device.HasNullDescriptor()) {
return;
}
device = &runtime.device;
buffer = runtime.CreateNullBuffer();
is_null = true;
}
Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_, Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rasterizer_,
VAddr cpu_addr_, u64 size_bytes_) VAddr cpu_addr_, u64 size_bytes_)
@@ -93,8 +100,12 @@ Buffer::Buffer(BufferCacheRuntime& runtime, VideoCore::RasterizerInterface& rast
VkBufferView Buffer::View(u32 offset, u32 size, VideoCore::Surface::PixelFormat format) { VkBufferView Buffer::View(u32 offset, u32 size, VideoCore::Surface::PixelFormat format) {
if (!device) { if (!device) {
// Null buffer, return a null descriptor // Null buffer supported, return a null descriptor
return VK_NULL_HANDLE; return VK_NULL_HANDLE;
} else if (is_null) {
// Null buffer not supported, adjust offset and size
offset = 0;
size = 0;
} }
const auto it{std::ranges::find_if(views, [offset, size, format](const BufferView& view) { const auto it{std::ranges::find_if(views, [offset, size, format](const BufferView& view) {
return offset == view.offset && size == view.size && format == view.format; return offset == view.offset && size == view.size && format == view.format;
@@ -627,9 +638,12 @@ void BufferCacheRuntime::BindTransformFeedbackBuffers(VideoCommon::HostBindings<
} }
void BufferCacheRuntime::ReserveNullBuffer() { void BufferCacheRuntime::ReserveNullBuffer() {
if (null_buffer) { if (!null_buffer) {
return; null_buffer = CreateNullBuffer();
} }
}
vk::Buffer BufferCacheRuntime::CreateNullBuffer() {
VkBufferCreateInfo create_info{ VkBufferCreateInfo create_info{
.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO, .sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO,
.pNext = nullptr, .pNext = nullptr,
@@ -644,15 +658,17 @@ void BufferCacheRuntime::ReserveNullBuffer() {
if (device.IsExtTransformFeedbackSupported()) { if (device.IsExtTransformFeedbackSupported()) {
create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT; create_info.usage |= VK_BUFFER_USAGE_TRANSFORM_FEEDBACK_BUFFER_BIT_EXT;
} }
null_buffer = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal); vk::Buffer ret = memory_allocator.CreateBuffer(create_info, MemoryUsage::DeviceLocal);
if (device.HasDebuggingToolAttached()) { if (device.HasDebuggingToolAttached()) {
null_buffer.SetObjectNameEXT("Null buffer"); ret.SetObjectNameEXT("Null buffer");
} }
scheduler.RequestOutsideRenderPassOperationContext(); scheduler.RequestOutsideRenderPassOperationContext();
scheduler.Record([buffer = *null_buffer](vk::CommandBuffer cmdbuf) { scheduler.Record([buffer = *ret](vk::CommandBuffer cmdbuf) {
cmdbuf.FillBuffer(buffer, 0, VK_WHOLE_SIZE, 0); cmdbuf.FillBuffer(buffer, 0, VK_WHOLE_SIZE, 0);
}); });
return ret;
} }
} // namespace Vulkan } // namespace Vulkan

View File

@@ -63,6 +63,7 @@ private:
vk::Buffer buffer; vk::Buffer buffer;
std::vector<BufferView> views; std::vector<BufferView> views;
VideoCommon::UsageTracker tracker; VideoCommon::UsageTracker tracker;
bool is_null{};
}; };
class QuadArrayIndexBuffer; class QuadArrayIndexBuffer;
@@ -151,6 +152,7 @@ private:
} }
void ReserveNullBuffer(); void ReserveNullBuffer();
vk::Buffer CreateNullBuffer();
const Device& device; const Device& device;
MemoryAllocator& memory_allocator; MemoryAllocator& memory_allocator;

View File

@@ -54,7 +54,7 @@ using VideoCommon::FileEnvironment;
using VideoCommon::GenericEnvironment; using VideoCommon::GenericEnvironment;
using VideoCommon::GraphicsEnvironment; using VideoCommon::GraphicsEnvironment;
constexpr u32 CACHE_VERSION = 10; constexpr u32 CACHE_VERSION = 11;
constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'}; constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'};
template <typename Container> template <typename Container>

View File

@@ -485,6 +485,10 @@ void RasterizerVulkan::DispatchCompute() {
} }
void RasterizerVulkan::ResetCounter(VideoCommon::QueryType type) { void RasterizerVulkan::ResetCounter(VideoCommon::QueryType type) {
if (type != VideoCommon::QueryType::ZPassPixelCount64) {
LOG_DEBUG(Render_Vulkan, "Unimplemented counter reset={}", type);
return;
}
query_cache.CounterReset(type); query_cache.CounterReset(type);
} }

View File

@@ -62,23 +62,9 @@ static Shader::TextureType ConvertTextureType(const Tegra::Texture::TICEntry& en
} }
static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture::TICEntry& entry) { static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture::TICEntry& entry) {
switch (PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type, return static_cast<Shader::TexturePixelFormat>(
entry.a_type, entry.srgb_conversion)) { PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type,
case VideoCore::Surface::PixelFormat::A8B8G8R8_SNORM: entry.a_type, entry.srgb_conversion));
return Shader::TexturePixelFormat::A8B8G8R8_SNORM;
case VideoCore::Surface::PixelFormat::R8_SNORM:
return Shader::TexturePixelFormat::R8_SNORM;
case VideoCore::Surface::PixelFormat::R8G8_SNORM:
return Shader::TexturePixelFormat::R8G8_SNORM;
case VideoCore::Surface::PixelFormat::R16G16B16A16_SNORM:
return Shader::TexturePixelFormat::R16G16B16A16_SNORM;
case VideoCore::Surface::PixelFormat::R16G16_SNORM:
return Shader::TexturePixelFormat::R16G16_SNORM;
case VideoCore::Surface::PixelFormat::R16_SNORM:
return Shader::TexturePixelFormat::R16_SNORM;
default:
return Shader::TexturePixelFormat::OTHER;
}
} }
static std::string_view StageToPrefix(Shader::Stage stage) { static std::string_view StageToPrefix(Shader::Stage stage) {
@@ -398,6 +384,11 @@ Shader::TexturePixelFormat GraphicsEnvironment::ReadTexturePixelFormat(u32 handl
return result; return result;
} }
bool GraphicsEnvironment::IsTexturePixelFormatInteger(u32 handle) {
return VideoCore::Surface::IsPixelFormatInteger(
static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
}
u32 GraphicsEnvironment::ReadViewportTransformState() { u32 GraphicsEnvironment::ReadViewportTransformState() {
const auto& regs{maxwell3d->regs}; const auto& regs{maxwell3d->regs};
viewport_transform_state = regs.viewport_scale_offset_enabled; viewport_transform_state = regs.viewport_scale_offset_enabled;
@@ -448,6 +439,11 @@ Shader::TexturePixelFormat ComputeEnvironment::ReadTexturePixelFormat(u32 handle
return result; return result;
} }
bool ComputeEnvironment::IsTexturePixelFormatInteger(u32 handle) {
return VideoCore::Surface::IsPixelFormatInteger(
static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
}
u32 ComputeEnvironment::ReadViewportTransformState() { u32 ComputeEnvironment::ReadViewportTransformState() {
return viewport_transform_state; return viewport_transform_state;
} }
@@ -551,6 +547,11 @@ Shader::TexturePixelFormat FileEnvironment::ReadTexturePixelFormat(u32 handle) {
return it->second; return it->second;
} }
bool FileEnvironment::IsTexturePixelFormatInteger(u32 handle) {
return VideoCore::Surface::IsPixelFormatInteger(
static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
}
u32 FileEnvironment::ReadViewportTransformState() { u32 FileEnvironment::ReadViewportTransformState() {
return viewport_transform_state; return viewport_transform_state;
} }

View File

@@ -115,6 +115,8 @@ public:
Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;
bool IsTexturePixelFormatInteger(u32 handle) override;
u32 ReadViewportTransformState() override; u32 ReadViewportTransformState() override;
std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer(u32 bank, u32 offset) override; std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer(u32 bank, u32 offset) override;
@@ -139,6 +141,8 @@ public:
Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;
bool IsTexturePixelFormatInteger(u32 handle) override;
u32 ReadViewportTransformState() override; u32 ReadViewportTransformState() override;
std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer( std::optional<Shader::ReplaceConstant> GetReplaceConstBuffer(
@@ -171,6 +175,8 @@ public:
[[nodiscard]] Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override; [[nodiscard]] Shader::TexturePixelFormat ReadTexturePixelFormat(u32 handle) override;
[[nodiscard]] bool IsTexturePixelFormatInteger(u32 handle) override;
[[nodiscard]] u32 ReadViewportTransformState() override; [[nodiscard]] u32 ReadViewportTransformState() override;
[[nodiscard]] u32 LocalMemorySize() const override; [[nodiscard]] u32 LocalMemorySize() const override;