Compare commits

..

3 Commits

Author SHA1 Message Date
0ab1c0e056 Android #167 2023-12-21 00:57:06 +00:00
23c62f26d5 Merge PR 12410 2023-12-21 00:57:06 +00:00
1019fbca95 Merge PR 12407 2023-12-21 00:57:06 +00:00
63 changed files with 756 additions and 1876 deletions

View File

@ -1,6 +1,7 @@
| 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 |
| [12407](https://github.com/yuzu-emu/yuzu//pull/12407) | [`6e2cbd474`](https://github.com/yuzu-emu/yuzu//pull/12407/files) | shader_recompiler: patch small float image writes on broken drivers | [liamwhite](https://github.com/liamwhite/) | Yes |
| [12410](https://github.com/yuzu-emu/yuzu//pull/12410) | [`d0a75580d`](https://github.com/yuzu-emu/yuzu//pull/12410/files) | renderer_vulkan: don't pass null view when nullDescriptor is not supported | [liamwhite](https://github.com/liamwhite/) | Yes |
End of merge log. You can find the original README.md below the break.

View File

@ -91,20 +91,18 @@ class GamesFragment : Fragment() {
viewLifecycleOwner.lifecycleScope.apply {
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.isReloading.collect {
binding.swipeRefresh.isRefreshing = it
if (gamesViewModel.games.value.isEmpty() && !it) {
binding.noticeText.visibility = View.VISIBLE
} else {
binding.noticeText.visibility = View.INVISIBLE
}
}
gamesViewModel.isReloading.collect { binding.swipeRefresh.isRefreshing = it }
}
}
launch {
repeatOnLifecycle(Lifecycle.State.RESUMED) {
gamesViewModel.games.collectLatest {
(binding.gridGames.adapter as GameAdapter).submitList(it)
if (it.isEmpty()) {
binding.noticeText.visibility = View.VISIBLE
} else {
binding.noticeText.visibility = View.GONE
}
}
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -116,6 +116,7 @@ class CpuManager;
class Debugger;
class DeviceMemory;
class ExclusiveMonitor;
class GPUDirtyMemoryManager;
class PerfStats;
class Reporter;
class SpeedLimiter;
@ -224,6 +225,12 @@ public:
/// Prepare the core emulation for a reschedule
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);
[[nodiscard]] size_t GetCurrentHostThreadID() const;
@ -243,6 +250,12 @@ public:
/// Gets a const reference to the underlying CPU manager
[[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.
[[nodiscard]] Core::Memory::Memory& ApplicationMemory();

View File

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

View File

@ -34,13 +34,6 @@ enum class ProgramFilePermission : u64 {
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)
* Data can either be loaded from a file path or with data and an offset into it.
@ -79,7 +72,6 @@ public:
u64 GetTitleID() const;
u64 GetFilesystemPermissions() const;
u32 GetSystemResourceSize() const;
PoolPartition GetPoolPartition() const;
const KernelCapabilityDescriptors& GetKernelCapabilities() const;
const std::array<u8, 0x10>& GetName() const {
return npdm_header.application_name;
@ -124,9 +116,8 @@ private:
union {
u32 flags;
BitField<0, 1, u32> production_flag;
BitField<1, 1, u32> unqualified_approval;
BitField<2, 4, PoolPartition> pool_partition;
BitField<0, 1, u32> is_retail;
BitField<1, 31, u32> flags_unk;
};
u64_le title_id_min;
u64_le title_id_max;

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

File diff suppressed because it is too large Load Diff

View File

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

View File

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

View File

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

View File

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

View File

@ -68,6 +68,8 @@ struct KernelCore::Impl {
global_object_list_container = std::make_unique<KAutoObjectWithListContainer>(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;
@ -119,8 +121,13 @@ struct KernelCore::Impl {
next_user_process_id = KProcess::ProcessIdMin;
next_thread_id = 1;
global_handle_table->Finalize();
global_handle_table.reset();
preemption_event = nullptr;
exclusive_monitor.reset();
// Cleanup persistent kernel objects
auto CleanupObject = [](KAutoObject* obj) {
if (obj) {
@ -184,6 +191,8 @@ struct KernelCore::Impl {
}
void InitializePhysicalCores() {
exclusive_monitor =
Core::MakeExclusiveMonitor(system.ApplicationMemory(), Core::Hardware::NUM_CPU_CORES);
for (u32 i = 0; i < Core::Hardware::NUM_CPU_CORES; i++) {
const s32 core{static_cast<s32>(i)};
@ -782,6 +791,10 @@ struct KernelCore::Impl {
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<KObjectNameGlobalData> object_name_global_data;
@ -792,6 +805,7 @@ struct KernelCore::Impl {
std::mutex server_lock;
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;
// Next host thead ID to use, 0-3 IDs represent core threads, >3 represent others
@ -868,6 +882,10 @@ KResourceLimit* KernelCore::GetSystemResourceLimit() {
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) {
impl->process_list.push_back(process);
}
@ -941,6 +959,14 @@ Kernel::KHardwareTimer& KernelCore::HardwareTimer() {
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() {
return *impl->global_object_list_container;
}
@ -1004,6 +1030,14 @@ u64 KernelCore::CreateNewUserProcessID() {
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) {
impl->RegisterCoreThread(core_id);
}

View File

@ -116,6 +116,9 @@ public:
/// Retrieves a shared pointer to the system resource limit instance.
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.
void AppendNewProcess(KProcess* process);
@ -167,6 +170,10 @@ public:
/// Stops execution of 'id' core, in order to reschedule a new thread.
void PrepareReschedule(std::size_t id);
Core::ExclusiveMonitor& GetExclusiveMonitor();
const Core::ExclusiveMonitor& GetExclusiveMonitor() const;
KAutoObjectWithListContainer& ObjectListContainer();
const KAutoObjectWithListContainer& ObjectListContainer() const;

View File

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

View File

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

View File

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

View File

@ -38,9 +38,7 @@ constexpr Result ResultInvalidState{ErrorModule::Kernel, 125};
constexpr Result ResultReservedUsed{ErrorModule::Kernel, 126};
constexpr Result ResultPortClosed{ErrorModule::Kernel, 131};
constexpr Result ResultLimitReached{ErrorModule::Kernel, 132};
constexpr Result ResultReceiveListBroken{ErrorModule::Kernel, 258};
constexpr Result ResultOutOfAddressSpace{ErrorModule::Kernel, 259};
constexpr Result ResultMessageTooLarge{ErrorModule::Kernel, 260};
constexpr Result ResultInvalidId{ErrorModule::Kernel, 519};
} // 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(" FAR: {:016x}\n", info.far);
crash_report += "\nBacktrace:\n";
for (u32 i = 0; i < std::min<u32>(info.backtrace_size, 32); i++) {
for (size_t i = 0; i < info.backtrace_size; i++) {
crash_report +=
fmt::format(" Backtrace[{:02d}]: {:016x}\n", i, info.backtrace[i]);
}

View File

@ -51,7 +51,7 @@ private:
IPC::RequestParser rp{ctx};
const auto vibration_device_handle{rp.PopRaw<Core::HID::VibrationDeviceHandle>()};
if (resource_manager != nullptr && resource_manager->GetNpad()) {
if (resource_manager != nullptr) {
resource_manager->GetNpad()->InitializeVibrationDevice(vibration_device_handle);
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

@ -512,7 +512,7 @@ OPCODE(ImageQueryDimensions, U32x4, Opaq
OPCODE(ImageQueryLod, F32x4, Opaque, Opaque, )
OPCODE(ImageGradient, F32x4, Opaque, Opaque, Opaque, Opaque, Opaque, )
OPCODE(ImageRead, U32x4, Opaque, Opaque, )
OPCODE(ImageWrite, Void, Opaque, Opaque, U32x4, )
OPCODE(ImageWrite, Void, Opaque, Opaque, Opaque, )
OPCODE(IsTextureScaled, U1, U32, )
OPCODE(IsImageScaled, U1, U32, )

View File

@ -19,8 +19,10 @@ struct HostTranslateInfo {
u32 min_ssbo_alignment{}; ///< Minimum alignment supported by the device for SSBOs
bool support_geometry_shader_passthrough{}; ///< True when the device supports geometry
///< passthrough shaders
bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional
///< control flow
bool support_conditional_barrier{}; ///< True when the device supports barriers in conditional
///< control flow
bool support_ufloat_write_as_uint{}; ///< True when the device supports writing float images
///< as bitcasts to uint
};
} // namespace Shader

View File

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

View File

@ -372,8 +372,8 @@ TexturePixelFormat ReadTexturePixelFormat(Environment& env, const ConstBufferAdd
return env.ReadTexturePixelFormat(GetTextureHandle(env, cbuf));
}
bool IsTexturePixelFormatInteger(Environment& env, const ConstBufferAddr& cbuf) {
return env.IsTexturePixelFormatInteger(GetTextureHandle(env, cbuf));
bool TexturePixelFormatIsFloat(Environment& env, const ConstBufferAddr& cbuf) {
return ReadTexturePixelFormat(env, cbuf) == TexturePixelFormat::B10G11R11_FLOAT;
}
class Descriptors {
@ -407,7 +407,6 @@ public:
})};
image_buffer_descriptors[index].is_written |= desc.is_written;
image_buffer_descriptors[index].is_read |= desc.is_read;
image_buffer_descriptors[index].is_integer |= desc.is_integer;
return index;
}
@ -433,11 +432,11 @@ public:
return desc.type == existing.type && desc.format == existing.format &&
desc.cbuf_index == existing.cbuf_index &&
desc.cbuf_offset == existing.cbuf_offset && desc.count == existing.count &&
desc.size_shift == existing.size_shift;
desc.size_shift == existing.size_shift && desc.is_float == existing.is_float;
})};
// TODO: handle is_float?
image_descriptors[index].is_written |= desc.is_written;
image_descriptors[index].is_read |= desc.is_read;
image_descriptors[index].is_integer |= desc.is_integer;
return index;
}
@ -475,20 +474,6 @@ void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
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) {
const auto it{IR::Block::InstructionList::s_iterator_to(inst)};
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
@ -520,6 +505,19 @@ void PatchTexelFetch(IR::Block& block, IR::Inst& inst, TexturePixelFormat pixel_
ir.FPMul(ir.ConvertSToF(32, 32, ir.BitCast<IR::U32>(w)), max_value));
inst.ReplaceUsesWith(converted);
}
void PatchSmallFloatImageWrite(IR::Block& block, IR::Inst& inst) {
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
const IR::Value old_value{inst.Arg(2)};
const IR::F32 x(ir.BitCast<IR::F32>(IR::U32(ir.CompositeExtract(old_value, 0))));
const IR::F32 y(ir.BitCast<IR::F32>(IR::U32(ir.CompositeExtract(old_value, 1))));
const IR::F32 z(ir.BitCast<IR::F32>(IR::U32(ir.CompositeExtract(old_value, 2))));
const IR::F32 w(ir.BitCast<IR::F32>(IR::U32(ir.CompositeExtract(old_value, 3))));
const IR::Value converted = ir.CompositeConstruct(x, y, z, w);
inst.SetArg(2, converted);
}
} // Anonymous namespace
void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo& host_info) {
@ -551,6 +549,9 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
inst->ReplaceOpcode(IndexedInstruction(*inst));
const auto& cbuf{texture_inst.cbuf};
const bool is_float_write{!host_info.support_ufloat_write_as_uint &&
inst->GetOpcode() == IR::Opcode::ImageWrite &&
TexturePixelFormatIsFloat(env, cbuf)};
auto flags{inst->Flags<IR::TextureInstInfo>()};
bool is_multisample{false};
switch (inst->GetOpcode()) {
@ -607,13 +608,11 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
}
const bool is_written{inst->GetOpcode() != IR::Opcode::ImageRead};
const bool is_read{inst->GetOpcode() != IR::Opcode::ImageWrite};
const bool is_integer{IsTexturePixelFormatInteger(env, cbuf)};
if (flags.type == TextureType::Buffer) {
index = descriptors.Add(ImageBufferDescriptor{
.format = flags.image_format,
.is_written = is_written,
.is_read = is_read,
.is_integer = is_integer,
.cbuf_index = cbuf.index,
.cbuf_offset = cbuf.offset,
.count = cbuf.count,
@ -625,7 +624,7 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
.format = flags.image_format,
.is_written = is_written,
.is_read = is_read,
.is_integer = is_integer,
.is_float = is_float_write,
.cbuf_index = cbuf.index,
.cbuf_offset = cbuf.offset,
.count = cbuf.count,
@ -681,10 +680,14 @@ void TexturePass(Environment& env, IR::Program& program, const HostTranslateInfo
if (!host_info.support_snorm_render_buffer && inst->GetOpcode() == IR::Opcode::ImageFetch &&
flags.type == TextureType::Buffer) {
const auto pixel_format = ReadTexturePixelFormat(env, cbuf);
if (IsPixelFormatSNorm(pixel_format)) {
if (pixel_format != TexturePixelFormat::OTHER) {
PatchTexelFetch(*texture_inst.block, *texture_inst.inst, pixel_format);
}
}
if (is_float_write) {
PatchSmallFloatImageWrite(*texture_inst.block, *inst);
}
}
}

View File

@ -35,109 +35,15 @@ enum class TextureType : u32 {
};
constexpr u32 NUM_TEXTURE_TYPES = 9;
enum class TexturePixelFormat {
A8B8G8R8_UNORM,
enum class TexturePixelFormat : u32 {
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_SINT,
R8_UINT,
R16G16B16A16_FLOAT,
R16G16B16A16_UNORM,
R16G16B16A16_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_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,
R16G16B16A16_SNORM,
R16G16_SNORM,
R16_SNORM,
B10G11R11_FLOAT,
OTHER
};
enum class ImageFormat : u32 {
@ -192,7 +98,6 @@ struct ImageBufferDescriptor {
ImageFormat format;
bool is_written;
bool is_read;
bool is_integer;
u32 cbuf_index;
u32 cbuf_offset;
u32 count;
@ -225,7 +130,7 @@ struct ImageDescriptor {
ImageFormat format;
bool is_written;
bool is_read;
bool is_integer;
bool is_float;
u32 cbuf_index;
u32 cbuf_offset;
u32 count;

View File

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

View File

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

View File

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

View File

@ -51,22 +51,6 @@ constexpr size_t NUM_SUPPORTED_VERTEX_ATTRIBUTES = 16;
void oglEnable(GLenum cap, bool state) {
(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
RasterizerOpenGL::RasterizerOpenGL(Core::Frontend::EmuWindow& emu_window_, Tegra::GPU& gpu_,
@ -232,6 +216,7 @@ void RasterizerOpenGL::PrepareDraw(bool is_indexed, Func&& draw_func) {
SCOPE_EXIT({ gpu.TickWork(); });
gpu_memory->FlushCaching();
query_cache.UpdateCounters();
GraphicsPipeline* const pipeline{shader_cache.CurrentGraphicsPipeline()};
if (!pipeline) {
@ -349,6 +334,7 @@ void RasterizerOpenGL::DrawTexture() {
MICROPROFILE_SCOPE(OpenGL_Drawing);
SCOPE_EXIT({ gpu.TickWork(); });
query_cache.UpdateCounters();
texture_cache.SynchronizeGraphicsDescriptors();
texture_cache.UpdateRenderTargets(false);
@ -415,28 +401,21 @@ void RasterizerOpenGL::DispatchCompute() {
}
void RasterizerOpenGL::ResetCounter(VideoCommon::QueryType type) {
const auto query_cache_type = MaxwellToVideoCoreQuery(type);
if (!query_cache_type.has_value()) {
UNIMPLEMENTED_IF_MSG(type != VideoCommon::QueryType::Payload, "Reset query type: {}", type);
return;
if (type == VideoCommon::QueryType::ZPassPixelCount64) {
query_cache.ResetCounter(VideoCore::QueryType::SamplesPassed);
}
query_cache.ResetCounter(*query_cache_type);
}
void RasterizerOpenGL::Query(GPUVAddr gpu_addr, VideoCommon::QueryType type,
VideoCommon::QueryPropertiesFlags flags, u32 payload, u32 subreport) {
const auto query_cache_type = MaxwellToVideoCoreQuery(type);
if (!query_cache_type.has_value()) {
return QueryFallback(gpu_addr, type, flags, payload, subreport);
if (type == VideoCommon::QueryType::ZPassPixelCount64) {
if (True(flags & VideoCommon::QueryPropertiesFlags::HasTimeout)) {
query_cache.Query(gpu_addr, VideoCore::QueryType::SamplesPassed, {gpu.GetTicks()});
} 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) {
payload = 1u;
}

View File

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

View File

@ -51,7 +51,7 @@ using VideoCommon::LoadPipelines;
using VideoCommon::SerializePipeline;
using Context = ShaderContext::Context;
constexpr u32 CACHE_VERSION = 10;
constexpr u32 CACHE_VERSION = 9;
template <typename Container>
auto MakeSpan(Container& container) {
@ -245,6 +245,7 @@ ShaderCache::ShaderCache(RasterizerOpenGL& rasterizer_, Core::Frontend::EmuWindo
.min_ssbo_alignment = static_cast<u32>(device.GetShaderStorageBufferAlignment()),
.support_geometry_shader_passthrough = device.HasGeometryShaderPassthrough(),
.support_conditional_barrier = device.SupportsConditionalBarriers(),
.support_ufloat_write_as_uint = true,
} {
if (use_asynchronous_shaders) {
workers = CreateWorkers();

View File

@ -54,7 +54,7 @@ using VideoCommon::FileEnvironment;
using VideoCommon::GenericEnvironment;
using VideoCommon::GraphicsEnvironment;
constexpr u32 CACHE_VERSION = 11;
constexpr u32 CACHE_VERSION = 10;
constexpr std::array<char, 8> VULKAN_CACHE_MAGIC_NUMBER{'y', 'u', 'z', 'u', 'v', 'k', 'c', 'h'};
template <typename Container>
@ -388,6 +388,9 @@ PipelineCache::PipelineCache(RasterizerVulkan& rasterizer_, const Device& device
.min_ssbo_alignment = static_cast<u32>(device.GetStorageBufferAlignment()),
.support_geometry_shader_passthrough = device.IsNvGeometryShaderPassthroughSupported(),
.support_conditional_barrier = device.SupportsConditionalBarriers(),
.support_ufloat_write_as_uint = driver_id != VK_DRIVER_ID_QUALCOMM_PROPRIETARY &&
driver_id != VK_DRIVER_ID_MESA_TURNIP &&
driver_id != VK_DRIVER_ID_ARM_PROPRIETARY,
};
if (device.GetMaxVertexInputAttributes() < Maxwell::NumVertexAttributes) {

View File

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

View File

@ -62,9 +62,25 @@ static Shader::TextureType ConvertTextureType(const Tegra::Texture::TICEntry& en
}
static Shader::TexturePixelFormat ConvertTexturePixelFormat(const Tegra::Texture::TICEntry& entry) {
return static_cast<Shader::TexturePixelFormat>(
PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type,
entry.a_type, entry.srgb_conversion));
switch (PixelFormatFromTextureInfo(entry.format, entry.r_type, entry.g_type, entry.b_type,
entry.a_type, entry.srgb_conversion)) {
case VideoCore::Surface::PixelFormat::A8B8G8R8_SNORM:
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;
case VideoCore::Surface::PixelFormat::B10G11R11_FLOAT:
return Shader::TexturePixelFormat::B10G11R11_FLOAT;
default:
return Shader::TexturePixelFormat::OTHER;
}
}
static std::string_view StageToPrefix(Shader::Stage stage) {
@ -384,11 +400,6 @@ Shader::TexturePixelFormat GraphicsEnvironment::ReadTexturePixelFormat(u32 handl
return result;
}
bool GraphicsEnvironment::IsTexturePixelFormatInteger(u32 handle) {
return VideoCore::Surface::IsPixelFormatInteger(
static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
}
u32 GraphicsEnvironment::ReadViewportTransformState() {
const auto& regs{maxwell3d->regs};
viewport_transform_state = regs.viewport_scale_offset_enabled;
@ -439,11 +450,6 @@ Shader::TexturePixelFormat ComputeEnvironment::ReadTexturePixelFormat(u32 handle
return result;
}
bool ComputeEnvironment::IsTexturePixelFormatInteger(u32 handle) {
return VideoCore::Surface::IsPixelFormatInteger(
static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
}
u32 ComputeEnvironment::ReadViewportTransformState() {
return viewport_transform_state;
}
@ -547,11 +553,6 @@ Shader::TexturePixelFormat FileEnvironment::ReadTexturePixelFormat(u32 handle) {
return it->second;
}
bool FileEnvironment::IsTexturePixelFormatInteger(u32 handle) {
return VideoCore::Surface::IsPixelFormatInteger(
static_cast<VideoCore::Surface::PixelFormat>(ReadTexturePixelFormat(handle)));
}
u32 FileEnvironment::ReadViewportTransformState() {
return viewport_transform_state;
}

View File

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

View File

@ -106,30 +106,32 @@ ConfigureGraphics::ConfigureGraphics(
Settings::values.bg_green.GetValue(),
Settings::values.bg_blue.GetValue()));
UpdateAPILayout();
PopulateVSyncModeSelection(false); //< must happen after UpdateAPILayout
PopulateVSyncModeSelection(); //< must happen after UpdateAPILayout
// VSync setting needs to be determined after populating the VSync combobox
const auto vsync_mode_setting = Settings::values.vsync_mode.GetValue();
const auto vsync_mode = VSyncSettingToMode(vsync_mode_setting);
int index{};
for (const auto mode : vsync_mode_combobox_enum_map) {
if (mode == vsync_mode) {
break;
if (Settings::IsConfiguringGlobal()) {
const auto vsync_mode_setting = Settings::values.vsync_mode.GetValue();
const auto vsync_mode = VSyncSettingToMode(vsync_mode_setting);
int index{};
for (const auto mode : vsync_mode_combobox_enum_map) {
if (mode == vsync_mode) {
break;
}
index++;
}
if (static_cast<unsigned long>(index) < vsync_mode_combobox_enum_map.size()) {
vsync_mode_combobox->setCurrentIndex(index);
}
index++;
}
if (static_cast<unsigned long>(index) < vsync_mode_combobox_enum_map.size()) {
vsync_mode_combobox->setCurrentIndex(index);
}
connect(api_combobox, qOverload<int>(&QComboBox::activated), this, [this] {
UpdateAPILayout();
PopulateVSyncModeSelection(false);
PopulateVSyncModeSelection();
});
connect(vulkan_device_combobox, qOverload<int>(&QComboBox::activated), this,
[this](int device) {
UpdateDeviceSelection(device);
PopulateVSyncModeSelection(false);
PopulateVSyncModeSelection();
});
connect(shader_backend_combobox, qOverload<int>(&QComboBox::activated), this,
[this](int backend) { UpdateShaderBackendSelection(backend); });
@ -145,9 +147,8 @@ ConfigureGraphics::ConfigureGraphics(
const auto& update_screenshot_info = [this, &builder]() {
const auto& combobox_enumerations = builder.ComboboxTranslations().at(
Settings::EnumMetadata<Settings::AspectRatio>::Index());
const auto ratio_index = aspect_ratio_combobox->currentIndex();
const auto ratio =
static_cast<Settings::AspectRatio>(combobox_enumerations[ratio_index].first);
const auto index = aspect_ratio_combobox->currentIndex();
const auto ratio = static_cast<Settings::AspectRatio>(combobox_enumerations[index].first);
const auto& combobox_enumerations_resolution = builder.ComboboxTranslations().at(
Settings::EnumMetadata<Settings::ResolutionSetup>::Index());
@ -173,7 +174,11 @@ ConfigureGraphics::ConfigureGraphics(
}
}
void ConfigureGraphics::PopulateVSyncModeSelection(bool use_setting) {
void ConfigureGraphics::PopulateVSyncModeSelection() {
if (!Settings::IsConfiguringGlobal()) {
return;
}
const Settings::RendererBackend backend{GetCurrentGraphicsBackend()};
if (backend == Settings::RendererBackend::Null) {
vsync_mode_combobox->setEnabled(false);
@ -184,9 +189,8 @@ void ConfigureGraphics::PopulateVSyncModeSelection(bool use_setting) {
const int current_index = //< current selected vsync mode from combobox
vsync_mode_combobox->currentIndex();
const auto current_mode = //< current selected vsync mode as a VkPresentModeKHR
current_index == -1 || use_setting
? VSyncSettingToMode(Settings::values.vsync_mode.GetValue())
: vsync_mode_combobox_enum_map[current_index];
current_index == -1 ? VSyncSettingToMode(Settings::values.vsync_mode.GetValue())
: vsync_mode_combobox_enum_map[current_index];
int index{};
const int device{vulkan_device_combobox->currentIndex()}; //< current selected Vulkan device
@ -210,23 +214,6 @@ void ConfigureGraphics::PopulateVSyncModeSelection(bool use_setting) {
}
index++;
}
if (!Settings::IsConfiguringGlobal()) {
vsync_restore_global_button->setVisible(!Settings::values.vsync_mode.UsingGlobal());
const Settings::VSyncMode global_vsync_mode = Settings::values.vsync_mode.GetValue(true);
vsync_restore_global_button->setEnabled(
(backend == Settings::RendererBackend::OpenGL &&
(global_vsync_mode == Settings::VSyncMode::Immediate ||
global_vsync_mode == Settings::VSyncMode::Fifo)) ||
backend == Settings::RendererBackend::Vulkan);
}
}
void ConfigureGraphics::UpdateVsyncSetting() const {
const auto mode = vsync_mode_combobox_enum_map[vsync_mode_combobox->currentIndex()];
const auto vsync_mode = PresentModeToSetting(mode);
Settings::values.vsync_mode.SetValue(vsync_mode);
}
void ConfigureGraphics::UpdateDeviceSelection(int device) {
@ -312,33 +299,6 @@ void ConfigureGraphics::Setup(const ConfigurationShared::Builder& builder) {
} else if (setting->Id() == Settings::values.vsync_mode.Id()) {
// Keep track of vsync_mode's combobox so we can populate it
vsync_mode_combobox = widget->combobox;
// Since vsync is populated at runtime, we have to manually set up the button for
// restoring the global setting.
if (!Settings::IsConfiguringGlobal()) {
QPushButton* restore_button =
ConfigurationShared::Widget::CreateRestoreGlobalButton(
Settings::values.vsync_mode.UsingGlobal(), widget);
restore_button->setEnabled(true);
widget->layout()->addWidget(restore_button);
QObject::connect(restore_button, &QAbstractButton::clicked,
[restore_button, this](bool) {
Settings::values.vsync_mode.SetGlobal(true);
PopulateVSyncModeSelection(true);
restore_button->setVisible(false);
});
std::function<void()> set_non_global = [restore_button, this]() {
Settings::values.vsync_mode.SetGlobal(false);
UpdateVsyncSetting();
restore_button->setVisible(true);
};
QObject::connect(widget->combobox, QOverload<int>::of(&QComboBox::activated),
[set_non_global]() { set_non_global(); });
vsync_restore_global_button = restore_button;
}
hold_graphics.emplace(setting->Id(), widget);
} else if (setting->Id() == Settings::values.aspect_ratio.Id()) {
// Keep track of the aspect ratio combobox to update other UI tabs that need it
@ -440,7 +400,11 @@ void ConfigureGraphics::ApplyConfiguration() {
func(powered_on);
}
UpdateVsyncSetting();
if (Settings::IsConfiguringGlobal()) {
const auto mode = vsync_mode_combobox_enum_map[vsync_mode_combobox->currentIndex()];
const auto vsync_mode = PresentModeToSetting(mode);
Settings::values.vsync_mode.SetValue(vsync_mode);
}
Settings::values.vulkan_device.SetGlobal(true);
Settings::values.shader_backend.SetGlobal(true);

View File

@ -62,8 +62,7 @@ private:
void Setup(const ConfigurationShared::Builder& builder);
void PopulateVSyncModeSelection(bool use_setting);
void UpdateVsyncSetting() const;
void PopulateVSyncModeSelection();
void UpdateBackgroundColorButton(QColor color);
void UpdateAPILayout();
void UpdateDeviceSelection(int device);
@ -105,7 +104,6 @@ private:
QComboBox* api_combobox;
QComboBox* shader_backend_combobox;
QComboBox* vsync_mode_combobox;
QPushButton* vsync_restore_global_button;
QWidget* vulkan_device_widget;
QWidget* api_widget;
QWidget* shader_backend_widget;