Compare commits

..

13 Commits

Author SHA1 Message Date
FengChen
b2a6dde438 video_code: support rectangle texture 2022-08-25 12:45:58 +08:00
bunnei
b1d61cd025 Merge pull request #8734 from liamwhite/bors-is-my-best-friend
core/arm: fix build error
2022-08-07 18:47:57 -07:00
Liam
aae208d07f core/arm: fix build error 2022-08-07 21:39:54 -04:00
bunnei
01bb5d5c4d Merge pull request #8637 from liamwhite/bad-interrupts
kernel: unlayer CPU interrupt handling
2022-08-07 17:48:55 -07:00
Morph
30515b3b27 Merge pull request #8240 from liamwhite/count-cycles
core/arm: re-enable cycle counting
2022-08-07 20:30:57 -04:00
liamwhite
167d948ce1 Merge pull request #8730 from lat9nq/fmt-9.0.0
vcpkg,yuzu: Update to fmt 9.0.0
2022-08-07 19:04:24 -04:00
liamwhite
b210efefb0 Merge pull request #8675 from merryhime/track-dynarmic-202207
externals: Update dynarmic to 6.2.3
2022-08-07 19:03:04 -04:00
lat9nq
e2123b27e8 yuzu: Fix fmt 9.0.0 issues 2022-08-07 17:02:06 -04:00
lat9nq
795ccc058d vcpkg: Update and update fmt to 9.0.0 2022-08-07 17:02:06 -04:00
Merry
8c933beb48 externals: Update dynarmic to 6.2.3 2022-07-29 23:07:00 +01:00
Liam
6523854dd6 kernel: unlayer CPU interrupt handling 2022-07-25 12:14:15 -04:00
Liam
d657ea69c9 core/arm: increase minimum_run_cycles 2022-06-21 20:37:16 -04:00
merry
30e8876ea4 core/arm: re-enable cycle counting 2022-06-21 20:36:24 -04:00
34 changed files with 171 additions and 210 deletions

View File

@@ -6,8 +6,6 @@ add_library(core STATIC
announce_multiplayer_session.h
arm/arm_interface.h
arm/arm_interface.cpp
arm/cpu_interrupt_handler.cpp
arm/cpu_interrupt_handler.h
arm/dynarmic/arm_dynarmic_32.cpp
arm/dynarmic/arm_dynarmic_32.h
arm/dynarmic/arm_dynarmic_64.cpp

View File

@@ -27,7 +27,6 @@ namespace Core {
class System;
class CPUInterruptHandler;
using CPUInterrupts = std::array<CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>;
using WatchpointArray = std::array<Kernel::DebugWatchpoint, Core::Hardware::NUM_WATCHPOINTS>;
/// Generic ARMv8 CPU interface
@@ -36,10 +35,8 @@ public:
YUZU_NON_COPYABLE(ARM_Interface);
YUZU_NON_MOVEABLE(ARM_Interface);
explicit ARM_Interface(System& system_, CPUInterrupts& interrupt_handlers_,
bool uses_wall_clock_)
: system{system_}, interrupt_handlers{interrupt_handlers_}, uses_wall_clock{
uses_wall_clock_} {}
explicit ARM_Interface(System& system_, bool uses_wall_clock_)
: system{system_}, uses_wall_clock{uses_wall_clock_} {}
virtual ~ARM_Interface() = default;
struct ThreadContext32 {
@@ -181,6 +178,9 @@ public:
/// Signal an interrupt and ask the core to halt as soon as possible.
virtual void SignalInterrupt() = 0;
/// Clear a previous interrupt.
virtual void ClearInterrupt() = 0;
struct BacktraceEntry {
std::string module;
u64 address;
@@ -208,7 +208,6 @@ public:
protected:
/// System context that this ARM interface is running under.
System& system;
CPUInterrupts& interrupt_handlers;
const WatchpointArray* watchpoints;
bool uses_wall_clock;

View File

@@ -1,24 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "common/thread.h"
#include "core/arm/cpu_interrupt_handler.h"
namespace Core {
CPUInterruptHandler::CPUInterruptHandler() : interrupt_event{std::make_unique<Common::Event>()} {}
CPUInterruptHandler::~CPUInterruptHandler() = default;
void CPUInterruptHandler::SetInterrupt(bool is_interrupted_) {
if (is_interrupted_) {
interrupt_event->Set();
}
is_interrupted = is_interrupted_;
}
void CPUInterruptHandler::AwaitInterrupt() {
interrupt_event->Wait();
}
} // namespace Core

View File

@@ -1,39 +0,0 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#pragma once
#include <atomic>
#include <memory>
namespace Common {
class Event;
}
namespace Core {
class CPUInterruptHandler {
public:
CPUInterruptHandler();
~CPUInterruptHandler();
CPUInterruptHandler(const CPUInterruptHandler&) = delete;
CPUInterruptHandler& operator=(const CPUInterruptHandler&) = delete;
CPUInterruptHandler(CPUInterruptHandler&&) = delete;
CPUInterruptHandler& operator=(CPUInterruptHandler&&) = delete;
bool IsInterrupted() const {
return is_interrupted;
}
void SetInterrupt(bool is_interrupted);
void AwaitInterrupt();
private:
std::unique_ptr<Common::Event> interrupt_event;
std::atomic_bool is_interrupted{false};
};
} // namespace Core

View File

@@ -11,7 +11,6 @@
#include "common/logging/log.h"
#include "common/page_table.h"
#include "common/settings.h"
#include "core/arm/cpu_interrupt_handler.h"
#include "core/arm/dynarmic/arm_dynarmic_32.h"
#include "core/arm/dynarmic/arm_dynarmic_cp15.h"
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
@@ -125,7 +124,9 @@ public:
}
void AddTicks(u64 ticks) override {
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
if (parent.uses_wall_clock) {
return;
}
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
// rough approximation of the amount of executed ticks in the system, it may be thrown off
@@ -142,7 +143,12 @@ public:
}
u64 GetTicksRemaining() override {
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
if (parent.uses_wall_clock) {
if (!IsInterrupted()) {
return minimum_run_cycles;
}
return 0U;
}
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
}
@@ -168,11 +174,15 @@ public:
parent.jit.load()->HaltExecution(hr);
}
bool IsInterrupted() {
return parent.system.Kernel().PhysicalCore(parent.core_index).IsInterrupted();
}
ARM_Dynarmic_32& parent;
Core::Memory::Memory& memory;
std::size_t num_interpreted_instructions{};
bool debugger_enabled{};
static constexpr u64 minimum_run_cycles = 1000U;
static constexpr u64 minimum_run_cycles = 10000U;
};
std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable* page_table) const {
@@ -200,7 +210,7 @@ std::shared_ptr<Dynarmic::A32::Jit> ARM_Dynarmic_32::MakeJit(Common::PageTable*
// Timing
config.wall_clock_cntpct = uses_wall_clock;
config.enable_cycle_counting = !uses_wall_clock;
config.enable_cycle_counting = true;
// Code cache size
config.code_cache_size = 512_MiB;
@@ -311,11 +321,9 @@ void ARM_Dynarmic_32::RewindBreakpointInstruction() {
LoadContext(breakpoint_context);
}
ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_,
bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
std::size_t core_index_)
: ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
cb(std::make_unique<DynarmicCallbacks32>(*this)),
ARM_Dynarmic_32::ARM_Dynarmic_32(System& system_, bool uses_wall_clock_,
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
: ARM_Interface{system_, uses_wall_clock_}, cb(std::make_unique<DynarmicCallbacks32>(*this)),
cp15(std::make_shared<DynarmicCP15>(*this)), core_index{core_index_},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
null_jit{MakeJit(nullptr)}, jit{null_jit.get()} {}
@@ -394,6 +402,10 @@ void ARM_Dynarmic_32::SignalInterrupt() {
jit.load()->HaltExecution(break_loop);
}
void ARM_Dynarmic_32::ClearInterrupt() {
jit.load()->ClearHalt(break_loop);
}
void ARM_Dynarmic_32::ClearInstructionCache() {
jit.load()->ClearCache();
}

View File

@@ -28,8 +28,8 @@ class System;
class ARM_Dynarmic_32 final : public ARM_Interface {
public:
ARM_Dynarmic_32(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
ARM_Dynarmic_32(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
std::size_t core_index_);
~ARM_Dynarmic_32() override;
void SetPC(u64 pc) override;
@@ -56,6 +56,7 @@ public:
void LoadContext(const ThreadContext64& ctx) override {}
void SignalInterrupt() override;
void ClearInterrupt() override;
void ClearExclusiveState() override;
void ClearInstructionCache() override;

View File

@@ -10,7 +10,6 @@
#include "common/logging/log.h"
#include "common/page_table.h"
#include "common/settings.h"
#include "core/arm/cpu_interrupt_handler.h"
#include "core/arm/dynarmic/arm_dynarmic_64.h"
#include "core/arm/dynarmic/arm_exclusive_monitor.h"
#include "core/core.h"
@@ -166,7 +165,9 @@ public:
}
void AddTicks(u64 ticks) override {
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
if (parent.uses_wall_clock) {
return;
}
// Divide the number of ticks by the amount of CPU cores. TODO(Subv): This yields only a
// rough approximation of the amount of executed ticks in the system, it may be thrown off
@@ -181,7 +182,12 @@ public:
}
u64 GetTicksRemaining() override {
ASSERT_MSG(!parent.uses_wall_clock, "This should never happen - dynarmic ticking disabled");
if (parent.uses_wall_clock) {
if (!IsInterrupted()) {
return minimum_run_cycles;
}
return 0U;
}
return std::max<s64>(parent.system.CoreTiming().GetDowncount(), 0);
}
@@ -211,12 +217,16 @@ public:
parent.jit.load()->HaltExecution(hr);
}
bool IsInterrupted() {
return parent.system.Kernel().PhysicalCore(parent.core_index).IsInterrupted();
}
ARM_Dynarmic_64& parent;
Core::Memory::Memory& memory;
u64 tpidrro_el0 = 0;
u64 tpidr_el0 = 0;
bool debugger_enabled{};
static constexpr u64 minimum_run_cycles = 1000U;
static constexpr u64 minimum_run_cycles = 10000U;
};
std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable* page_table,
@@ -260,7 +270,7 @@ std::shared_ptr<Dynarmic::A64::Jit> ARM_Dynarmic_64::MakeJit(Common::PageTable*
// Timing
config.wall_clock_cntpct = uses_wall_clock;
config.enable_cycle_counting = !uses_wall_clock;
config.enable_cycle_counting = true;
// Code cache size
config.code_cache_size = 512_MiB;
@@ -371,10 +381,9 @@ void ARM_Dynarmic_64::RewindBreakpointInstruction() {
LoadContext(breakpoint_context);
}
ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_,
bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
std::size_t core_index_)
: ARM_Interface{system_, interrupt_handlers_, uses_wall_clock_},
ARM_Dynarmic_64::ARM_Dynarmic_64(System& system_, bool uses_wall_clock_,
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_)
: ARM_Interface{system_, uses_wall_clock_},
cb(std::make_unique<DynarmicCallbacks64>(*this)), core_index{core_index_},
exclusive_monitor{dynamic_cast<DynarmicExclusiveMonitor&>(exclusive_monitor_)},
null_jit{MakeJit(nullptr, 48)}, jit{null_jit.get()} {}
@@ -461,6 +470,10 @@ void ARM_Dynarmic_64::SignalInterrupt() {
jit.load()->HaltExecution(break_loop);
}
void ARM_Dynarmic_64::ClearInterrupt() {
jit.load()->ClearHalt(break_loop);
}
void ARM_Dynarmic_64::ClearInstructionCache() {
jit.load()->ClearCache();
}

View File

@@ -20,14 +20,13 @@ class Memory;
namespace Core {
class DynarmicCallbacks64;
class CPUInterruptHandler;
class DynarmicExclusiveMonitor;
class System;
class ARM_Dynarmic_64 final : public ARM_Interface {
public:
ARM_Dynarmic_64(System& system_, CPUInterrupts& interrupt_handlers_, bool uses_wall_clock_,
ExclusiveMonitor& exclusive_monitor_, std::size_t core_index_);
ARM_Dynarmic_64(System& system_, bool uses_wall_clock_, ExclusiveMonitor& exclusive_monitor_,
std::size_t core_index_);
~ARM_Dynarmic_64() override;
void SetPC(u64 pc) override;
@@ -50,6 +49,7 @@ public:
void LoadContext(const ThreadContext64& ctx) override;
void SignalInterrupt() override;
void ClearInterrupt() override;
void ClearExclusiveState() override;
void ClearInstructionCache() override;

View File

@@ -8,10 +8,6 @@
#include "core/core.h"
#include "core/core_timing.h"
#ifdef _MSC_VER
#include <intrin.h>
#endif
using Callback = Dynarmic::A32::Coprocessor::Callback;
using CallbackOrAccessOneWord = Dynarmic::A32::Coprocessor::CallbackOrAccessOneWord;
using CallbackOrAccessTwoWords = Dynarmic::A32::Coprocessor::CallbackOrAccessTwoWords;
@@ -51,31 +47,12 @@ CallbackOrAccessOneWord DynarmicCP15::CompileSendOneWord(bool two, unsigned opc1
switch (opc2) {
case 4:
// CP15_DATA_SYNC_BARRIER
return Callback{
[](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
#ifdef _MSC_VER
_mm_mfence();
_mm_lfence();
#else
asm volatile("mfence\n\tlfence\n\t" : : : "memory");
#endif
return 0;
},
std::nullopt,
};
// This is a dummy write, we ignore the value written here.
return &dummy_value;
case 5:
// CP15_DATA_MEMORY_BARRIER
return Callback{
[](Dynarmic::A32::Jit*, void*, std::uint32_t, std::uint32_t) -> std::uint64_t {
#ifdef _MSC_VER
_mm_mfence();
#else
asm volatile("mfence\n\t" : : : "memory");
#endif
return 0;
},
std::nullopt,
};
// This is a dummy write, we ignore the value written here.
return &dummy_value;
}
}

View File

@@ -35,8 +35,6 @@ public:
ARM_Dynarmic_32& parent;
u32 uprw = 0;
u32 uro = 0;
friend class ARM_Dynarmic_32;
};
} // namespace Core

View File

@@ -15,6 +15,7 @@
#include "core/debugger/debugger_interface.h"
#include "core/debugger/gdbstub.h"
#include "core/hle/kernel/global_scheduler_context.h"
#include "core/hle/kernel/k_scheduler.h"
template <typename Readable, typename Buffer, typename Callback>
static void AsyncReceiveInto(Readable& r, Buffer& buffer, Callback&& c) {
@@ -230,13 +231,12 @@ private:
}
void PauseEmulation() {
Kernel::KScopedSchedulerLock sl{system.Kernel()};
// Put all threads to sleep on next scheduler round.
for (auto* thread : ThreadList()) {
thread->RequestSuspend(Kernel::SuspendType::Debug);
}
// Signal an interrupt so that scheduler will fire.
system.Kernel().InterruptAllPhysicalCores();
}
void ResumeEmulation(Kernel::KThread* except = nullptr) {
@@ -253,7 +253,8 @@ private:
template <typename Callback>
void MarkResumed(Callback&& cb) {
std::scoped_lock lk{connection_lock};
Kernel::KScopedSchedulerLock sl{system.Kernel()};
std::scoped_lock cl{connection_lock};
stopped = false;
cb();
}

View File

@@ -17,7 +17,6 @@
#include "common/thread.h"
#include "common/thread_worker.h"
#include "core/arm/arm_interface.h"
#include "core/arm/cpu_interrupt_handler.h"
#include "core/arm/exclusive_monitor.h"
#include "core/core.h"
#include "core/core_timing.h"
@@ -82,7 +81,7 @@ struct KernelCore::Impl {
void InitializeCores() {
for (u32 core_id = 0; core_id < Core::Hardware::NUM_CPU_CORES; core_id++) {
cores[core_id].Initialize((*current_process).Is64BitProcess());
cores[core_id]->Initialize((*current_process).Is64BitProcess());
system.Memory().SetCurrentPageTable(*current_process, core_id);
}
}
@@ -100,7 +99,9 @@ struct KernelCore::Impl {
next_user_process_id = KProcess::ProcessIDMin;
next_thread_id = 1;
cores.clear();
for (auto& core : cores) {
core = nullptr;
}
global_handle_table->Finalize();
global_handle_table.reset();
@@ -199,7 +200,7 @@ struct KernelCore::Impl {
const s32 core{static_cast<s32>(i)};
schedulers[i] = std::make_unique<Kernel::KScheduler>(system.Kernel());
cores.emplace_back(i, system, *schedulers[i], interrupts);
cores[i] = std::make_unique<Kernel::PhysicalCore>(i, system, *schedulers[i]);
auto* main_thread{Kernel::KThread::Create(system.Kernel())};
main_thread->SetName(fmt::format("MainThread:{}", core));
@@ -761,7 +762,7 @@ struct KernelCore::Impl {
std::unordered_set<KAutoObject*> registered_in_use_objects;
std::unique_ptr<Core::ExclusiveMonitor> exclusive_monitor;
std::vector<Kernel::PhysicalCore> 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
std::atomic<u32> next_host_thread_id{Core::Hardware::NUM_CPU_CORES};
@@ -785,7 +786,6 @@ struct KernelCore::Impl {
Common::ThreadWorker service_threads_manager;
std::array<KThread*, Core::Hardware::NUM_CPU_CORES> shutdown_threads;
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES> interrupts{};
std::array<std::unique_ptr<Kernel::KScheduler>, Core::Hardware::NUM_CPU_CORES> schedulers{};
bool is_multicore{};
@@ -874,11 +874,11 @@ const Kernel::KScheduler& KernelCore::Scheduler(std::size_t id) const {
}
Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) {
return impl->cores[id];
return *impl->cores[id];
}
const Kernel::PhysicalCore& KernelCore::PhysicalCore(std::size_t id) const {
return impl->cores[id];
return *impl->cores[id];
}
size_t KernelCore::CurrentPhysicalCoreIndex() const {
@@ -890,11 +890,11 @@ size_t KernelCore::CurrentPhysicalCoreIndex() const {
}
Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() {
return impl->cores[CurrentPhysicalCoreIndex()];
return *impl->cores[CurrentPhysicalCoreIndex()];
}
const Kernel::PhysicalCore& KernelCore::CurrentPhysicalCore() const {
return impl->cores[CurrentPhysicalCoreIndex()];
return *impl->cores[CurrentPhysicalCoreIndex()];
}
Kernel::KScheduler* KernelCore::CurrentScheduler() {
@@ -906,15 +906,6 @@ Kernel::KScheduler* KernelCore::CurrentScheduler() {
return impl->schedulers[core_id].get();
}
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts() {
return impl->interrupts;
}
const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& KernelCore::Interrupts()
const {
return impl->interrupts;
}
Kernel::TimeManager& KernelCore::TimeManager() {
return impl->time_manager;
}
@@ -939,24 +930,18 @@ const KAutoObjectWithListContainer& KernelCore::ObjectListContainer() const {
return *impl->global_object_list_container;
}
void KernelCore::InterruptAllPhysicalCores() {
for (auto& physical_core : impl->cores) {
physical_core.Interrupt();
}
}
void KernelCore::InvalidateAllInstructionCaches() {
for (auto& physical_core : impl->cores) {
physical_core.ArmInterface().ClearInstructionCache();
physical_core->ArmInterface().ClearInstructionCache();
}
}
void KernelCore::InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size) {
for (auto& physical_core : impl->cores) {
if (!physical_core.IsInitialized()) {
if (!physical_core->IsInitialized()) {
continue;
}
physical_core.ArmInterface().InvalidateCacheRange(addr, size);
physical_core->ArmInterface().InvalidateCacheRange(addr, size);
}
}

View File

@@ -9,14 +9,12 @@
#include <string>
#include <unordered_map>
#include <vector>
#include "core/arm/cpu_interrupt_handler.h"
#include "core/hardware_properties.h"
#include "core/hle/kernel/k_auto_object.h"
#include "core/hle/kernel/k_slab_heap.h"
#include "core/hle/kernel/svc_common.h"
namespace Core {
class CPUInterruptHandler;
class ExclusiveMonitor;
class System;
} // namespace Core
@@ -183,12 +181,6 @@ public:
const KAutoObjectWithListContainer& ObjectListContainer() const;
std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts();
const std::array<Core::CPUInterruptHandler, Core::Hardware::NUM_CPU_CORES>& Interrupts() const;
void InterruptAllPhysicalCores();
void InvalidateAllInstructionCaches();
void InvalidateCpuInstructionCacheRange(VAddr addr, std::size_t size);

View File

@@ -1,7 +1,6 @@
// SPDX-FileCopyrightText: Copyright 2020 yuzu Emulator Project
// SPDX-License-Identifier: GPL-2.0-or-later
#include "core/arm/cpu_interrupt_handler.h"
#include "core/arm/dynarmic/arm_dynarmic_32.h"
#include "core/arm/dynarmic/arm_dynarmic_64.h"
#include "core/core.h"
@@ -11,16 +10,14 @@
namespace Kernel {
PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,
Core::CPUInterrupts& interrupts_)
: core_index{core_index_}, system{system_}, scheduler{scheduler_},
interrupts{interrupts_}, guard{std::make_unique<std::mutex>()} {
PhysicalCore::PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_)
: core_index{core_index_}, system{system_}, scheduler{scheduler_} {
#ifdef ARCHITECTURE_x86_64
// TODO(bunnei): Initialization relies on a core being available. We may later replace this with
// a 32-bit instance of Dynarmic. This should be abstracted out to a CPU manager.
auto& kernel = system.Kernel();
arm_interface = std::make_unique<Core::ARM_Dynarmic_64>(
system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
#else
#error Platform not supported yet.
#endif
@@ -34,7 +31,7 @@ void PhysicalCore::Initialize([[maybe_unused]] bool is_64_bit) {
if (!is_64_bit) {
// We already initialized a 64-bit core, replace with a 32-bit one.
arm_interface = std::make_unique<Core::ARM_Dynarmic_32>(
system, interrupts, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
system, kernel.IsMulticore(), kernel.GetExclusiveMonitor(), core_index);
}
#else
#error Platform not supported yet.
@@ -47,24 +44,26 @@ void PhysicalCore::Run() {
}
void PhysicalCore::Idle() {
interrupts[core_index].AwaitInterrupt();
std::unique_lock lk{guard};
on_interrupt.wait(lk, [this] { return is_interrupted; });
}
bool PhysicalCore::IsInterrupted() const {
return interrupts[core_index].IsInterrupted();
return is_interrupted;
}
void PhysicalCore::Interrupt() {
guard->lock();
interrupts[core_index].SetInterrupt(true);
std::unique_lock lk{guard};
is_interrupted = true;
arm_interface->SignalInterrupt();
guard->unlock();
on_interrupt.notify_all();
}
void PhysicalCore::ClearInterrupt() {
guard->lock();
interrupts[core_index].SetInterrupt(false);
guard->unlock();
std::unique_lock lk{guard};
is_interrupted = false;
arm_interface->ClearInterrupt();
on_interrupt.notify_all();
}
} // namespace Kernel

View File

@@ -14,7 +14,6 @@ class KScheduler;
} // namespace Kernel
namespace Core {
class CPUInterruptHandler;
class ExclusiveMonitor;
class System;
} // namespace Core
@@ -23,15 +22,11 @@ namespace Kernel {
class PhysicalCore {
public:
PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_,
Core::CPUInterrupts& interrupts_);
PhysicalCore(std::size_t core_index_, Core::System& system_, KScheduler& scheduler_);
~PhysicalCore();
PhysicalCore(const PhysicalCore&) = delete;
PhysicalCore& operator=(const PhysicalCore&) = delete;
PhysicalCore(PhysicalCore&&) = default;
PhysicalCore& operator=(PhysicalCore&&) = delete;
YUZU_NON_COPYABLE(PhysicalCore);
YUZU_NON_MOVEABLE(PhysicalCore);
/// Initialize the core for the specified parameters.
void Initialize(bool is_64_bit);
@@ -86,9 +81,11 @@ private:
const std::size_t core_index;
Core::System& system;
Kernel::KScheduler& scheduler;
Core::CPUInterrupts& interrupts;
std::unique_ptr<std::mutex> guard;
std::mutex guard;
std::condition_variable on_interrupt;
std::unique_ptr<Core::ARM_Interface> arm_interface;
bool is_interrupted;
};
} // namespace Kernel

View File

@@ -67,6 +67,7 @@ std::string_view TextureType(IR::TextureInstInfo info) {
case TextureType::ColorArray1D:
return "SHADOWARRAY1D";
case TextureType::Color2D:
case TextureType::Color2DRect:
return "SHADOW2D";
case TextureType::ColorArray2D:
return "SHADOWARRAY2D";
@@ -86,6 +87,7 @@ std::string_view TextureType(IR::TextureInstInfo info) {
case TextureType::ColorArray1D:
return "ARRAY1D";
case TextureType::Color2D:
case TextureType::Color2DRect:
return "2D";
case TextureType::ColorArray2D:
return "ARRAY2D";

View File

@@ -466,6 +466,7 @@ void EmitImageQueryDimensions(EmitContext& ctx, IR::Inst& inst, const IR::Value&
case TextureType::ColorArray1D:
case TextureType::Color2D:
case TextureType::ColorCube:
case TextureType::Color2DRect:
return ctx.AddU32x4(
"{}=uvec4(uvec2(textureSize({},int({}))),0u,uint(textureQueryLevels({})));", inst,
texture, lod, texture);

View File

@@ -86,6 +86,7 @@ std::string_view SamplerType(TextureType type, bool is_depth) {
case TextureType::ColorArray1D:
return "sampler1DArray";
case TextureType::Color2D:
case TextureType::Color2DRect:
return "sampler2D";
case TextureType::ColorArray2D:
return "sampler2DArray";

View File

@@ -453,6 +453,7 @@ Id EmitImageQueryDimensions(EmitContext& ctx, IR::Inst* inst, const IR::Value& i
case TextureType::ColorArray1D:
case TextureType::Color2D:
case TextureType::ColorCube:
case TextureType::Color2DRect:
return ctx.OpCompositeConstruct(ctx.U32[4], ctx.OpImageQuerySizeLod(ctx.U32[2], image, lod),
zero, mips());
case TextureType::ColorArray2D:

View File

@@ -41,6 +41,7 @@ Id ImageType(EmitContext& ctx, const TextureDescriptor& desc) {
case TextureType::ColorArray1D:
return ctx.TypeImage(type, spv::Dim::Dim1D, depth, true, false, 1, format);
case TextureType::Color2D:
case TextureType::Color2DRect:
return ctx.TypeImage(type, spv::Dim::Dim2D, depth, false, false, 1, format);
case TextureType::ColorArray2D:
return ctx.TypeImage(type, spv::Dim::Dim2D, depth, true, false, 1, format);

View File

@@ -1832,6 +1832,11 @@ Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod) {
return Inst(op, handle, lod);
}
Value IREmitter::ImageQueryDimension(const Value& handle, const IR::U32& lod,
TextureInstInfo info) {
return Inst(Opcode::ImageQueryDimensions, Flags{info}, handle, lod);
}
Value IREmitter::ImageQueryLod(const Value& handle, const Value& coords, TextureInstInfo info) {
const Opcode op{handle.IsImmediate() ? Opcode::BoundImageQueryLod
: Opcode::BindlessImageQueryLod};

View File

@@ -315,6 +315,8 @@ public:
const F32& dref, const F32& lod,
const Value& offset, TextureInstInfo info);
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod);
[[nodiscard]] Value ImageQueryDimension(const Value& handle, const IR::U32& lod,
TextureInstInfo info);
[[nodiscard]] Value ImageQueryLod(const Value& handle, const Value& coords,
TextureInstInfo info);

View File

@@ -16,6 +16,7 @@ namespace {
switch (type) {
case TextureType::Color2D:
case TextureType::ColorArray2D:
case TextureType::Color2DRect:
return true;
case TextureType::Color1D:
case TextureType::ColorArray1D:
@@ -132,7 +133,8 @@ void PatchImageQueryDimensions(IR::Block& block, IR::Inst& inst) {
const IR::U1 is_scaled{ir.IsTextureScaled(ir.Imm32(info.descriptor_index))};
switch (info.type) {
case TextureType::Color2D:
case TextureType::ColorArray2D: {
case TextureType::ColorArray2D:
case TextureType::Color2DRect: {
const IR::Value new_inst{&*block.PrependNewInst(it, inst)};
const IR::U32 width{DownScale(ir, is_scaled, IR::U32{ir.CompositeExtract(new_inst, 0)})};
const IR::U32 height{DownScale(ir, is_scaled, IR::U32{ir.CompositeExtract(new_inst, 1)})};
@@ -163,6 +165,7 @@ void ScaleIntegerComposite(IR::IREmitter& ir, IR::Inst& inst, const IR::U1& is_s
const IR::U32 y{Scale(ir, is_scaled, IR::U32{ir.CompositeExtract(composite, 1)})};
switch (info.type) {
case TextureType::Color2D:
case TextureType::Color2DRect:
inst.SetArg(index, ir.CompositeConstruct(x, y));
break;
case TextureType::ColorArray2D: {
@@ -193,6 +196,7 @@ void ScaleIntegerOffsetComposite(IR::IREmitter& ir, IR::Inst& inst, const IR::U1
switch (info.type) {
case TextureType::ColorArray2D:
case TextureType::Color2D:
case TextureType::Color2DRect:
inst.SetArg(index, ir.CompositeConstruct(x, y));
break;
case TextureType::Color1D:
@@ -216,6 +220,7 @@ void SubScaleCoord(IR::IREmitter& ir, IR::Inst& inst, const IR::U1& is_scaled) {
const IR::U32 scaled_y{SubScale(ir, is_scaled, coord_y, IR::Attribute::PositionY)};
switch (info.type) {
case TextureType::Color2D:
case TextureType::Color2DRect:
inst.SetArg(1, ir.CompositeConstruct(scaled_x, scaled_y));
break;
case TextureType::ColorArray2D: {

View File

@@ -362,6 +362,21 @@ private:
TextureDescriptors& texture_descriptors;
ImageDescriptors& image_descriptors;
};
void PatchImageSampleImplicitLod(IR::Block& block, IR::Inst& inst) {
IR::IREmitter ir{block, IR::Block::InstructionList::s_iterator_to(inst)};
const auto info{inst.Flags<IR::TextureInstInfo>()};
const IR::Value coord(inst.Arg(1));
const IR::Value handle(ir.Imm32(0));
const IR::U32 lod{ir.Imm32(0)};
const IR::Value texture_size = ir.ImageQueryDimension(handle, lod, info);
inst.SetArg(
1, ir.CompositeConstruct(
ir.FPMul(IR::F32(ir.CompositeExtract(coord, 0)),
ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 0)))),
ir.FPMul(IR::F32(ir.CompositeExtract(coord, 1)),
ir.FPRecip(ir.ConvertUToF(32, 32, ir.CompositeExtract(texture_size, 1))))));
}
} // Anonymous namespace
void TexturePass(Environment& env, IR::Program& program) {
@@ -399,6 +414,14 @@ void TexturePass(Environment& env, IR::Program& program) {
flags.type.Assign(ReadTextureType(env, cbuf));
inst->SetFlags(flags);
break;
case IR::Opcode::ImageSampleImplicitLod:
if (flags.type == TextureType::Color2D) {
auto texture_type = ReadTextureType(env, cbuf);
if (texture_type == TextureType::Color2DRect) {
PatchImageSampleImplicitLod(*texture_inst.block, *texture_inst.inst);
}
}
break;
case IR::Opcode::ImageFetch:
if (flags.type != TextureType::Color1D) {
break;

View File

@@ -24,8 +24,9 @@ enum class TextureType : u32 {
ColorCube,
ColorArrayCube,
Buffer,
Color2DRect,
};
constexpr u32 NUM_TEXTURE_TYPES = 8;
constexpr u32 NUM_TEXTURE_TYPES = 9;
enum class ImageFormat : u32 {
Typeless,

View File

@@ -93,6 +93,7 @@ GLenum ImageTarget(Shader::TextureType type, int num_samples = 1) {
case Shader::TextureType::Color1D:
return GL_TEXTURE_1D;
case Shader::TextureType::Color2D:
case Shader::TextureType::Color2DRect:
return is_multisampled ? GL_TEXTURE_2D_MULTISAMPLE : GL_TEXTURE_2D;
case Shader::TextureType::ColorCube:
return GL_TEXTURE_CUBE_MAP;
@@ -502,6 +503,7 @@ TextureCacheRuntime::TextureCacheRuntime(const Device& device_, ProgramManager&
set_view(Shader::TextureType::ColorArray1D, null_image_1d_array.handle);
set_view(Shader::TextureType::ColorArray2D, null_image_view_2d_array.handle);
set_view(Shader::TextureType::ColorArrayCube, null_image_cube_array.handle);
set_view(Shader::TextureType::Color2DRect, null_image_view_2d.handle);
if (resolution.active) {
for (size_t i = 0; i < rescale_draw_fbos.size(); ++i) {
@@ -1110,6 +1112,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
flat_range.extent.layers = 1;
[[fallthrough]];
case ImageViewType::e2D:
case ImageViewType::Rect:
if (True(flags & VideoCommon::ImageViewFlagBits::Slice)) {
// 2D and 2D array views on a 3D textures are used exclusively for render targets
ASSERT(info.range.extent.levels == 1);
@@ -1135,9 +1138,6 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
SetupView(Shader::TextureType::ColorCube);
SetupView(Shader::TextureType::ColorArrayCube);
break;
case ImageViewType::Rect:
UNIMPLEMENTED();
break;
case ImageViewType::Buffer:
ASSERT(false);
break;
@@ -1150,6 +1150,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
default_handle = Handle(Shader::TextureType::ColorArray1D);
break;
case ImageViewType::e2D:
case ImageViewType::Rect:
default_handle = Handle(Shader::TextureType::Color2D);
break;
case ImageViewType::e2DArray:
@@ -1210,6 +1211,7 @@ GLuint ImageView::MakeView(Shader::TextureType view_type, GLenum view_format) {
case Shader::TextureType::Color1D:
case Shader::TextureType::Color2D:
case Shader::TextureType::ColorCube:
case Shader::TextureType::Color2DRect:
view_range = flat_range;
break;
case Shader::TextureType::ColorArray1D:
@@ -1250,7 +1252,6 @@ Sampler::Sampler(TextureCacheRuntime& runtime, const TSCEntry& config) {
const GLint seamless = config.cubemap_interface_filtering ? GL_TRUE : GL_FALSE;
UNIMPLEMENTED_IF(config.cubemap_anisotropy != 1);
UNIMPLEMENTED_IF(config.float_coord_normalization != 0);
sampler.Create();
const GLuint handle = sampler.handle;

View File

@@ -434,7 +434,9 @@ void PipelineCache::LoadDiskResources(u64 title_id, std::stop_token stop_loading
state.statistics.get(), false)};
std::scoped_lock lock{state.mutex};
graphics_cache.emplace(key, std::move(pipeline));
if (pipeline) {
graphics_cache.emplace(key, std::move(pipeline));
}
++state.built;
if (state.has_loaded) {
callback(VideoCore::LoadCallbackStage::Build, state.built, state.total);

View File

@@ -230,6 +230,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
case Shader::TextureType::Color1D:
return VK_IMAGE_VIEW_TYPE_1D;
case Shader::TextureType::Color2D:
case Shader::TextureType::Color2DRect:
return VK_IMAGE_VIEW_TYPE_2D;
case Shader::TextureType::ColorCube:
return VK_IMAGE_VIEW_TYPE_CUBE;
@@ -254,6 +255,7 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
case VideoCommon::ImageViewType::e1D:
return VK_IMAGE_VIEW_TYPE_1D;
case VideoCommon::ImageViewType::e2D:
case VideoCommon::ImageViewType::Rect:
return VK_IMAGE_VIEW_TYPE_2D;
case VideoCommon::ImageViewType::Cube:
return VK_IMAGE_VIEW_TYPE_CUBE;
@@ -265,9 +267,6 @@ constexpr VkBorderColor ConvertBorderColor(const std::array<float, 4>& color) {
return VK_IMAGE_VIEW_TYPE_2D_ARRAY;
case VideoCommon::ImageViewType::CubeArray:
return VK_IMAGE_VIEW_TYPE_CUBE_ARRAY;
case VideoCommon::ImageViewType::Rect:
UNIMPLEMENTED_MSG("Rect image view");
return VK_IMAGE_VIEW_TYPE_2D;
case VideoCommon::ImageViewType::Buffer:
ASSERT_MSG(false, "Texture buffers can't be image views");
return VK_IMAGE_VIEW_TYPE_1D;
@@ -1579,6 +1578,7 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
break;
case VideoCommon::ImageViewType::e2D:
case VideoCommon::ImageViewType::e2DArray:
case VideoCommon::ImageViewType::Rect:
create(TextureType::Color2D, 1);
create(TextureType::ColorArray2D, std::nullopt);
render_target = Handle(Shader::TextureType::ColorArray2D);
@@ -1592,9 +1592,6 @@ ImageView::ImageView(TextureCacheRuntime& runtime, const VideoCommon::ImageViewI
create(TextureType::ColorCube, 6);
create(TextureType::ColorArrayCube, std::nullopt);
break;
case VideoCommon::ImageViewType::Rect:
UNIMPLEMENTED();
break;
case VideoCommon::ImageViewType::Buffer:
ASSERT(false);
break;

View File

@@ -39,7 +39,11 @@ static Shader::TextureType ConvertType(const Tegra::Texture::TICEntry& entry) {
return Shader::TextureType::Color1D;
case Tegra::Texture::TextureType::Texture2D:
case Tegra::Texture::TextureType::Texture2DNoMipmap:
return Shader::TextureType::Color2D;
if (entry.normalized_coords) {
return Shader::TextureType::Color2D;
} else {
return Shader::TextureType::Color2DRect;
}
case Tegra::Texture::TextureType::Texture3D:
return Shader::TextureType::Color3D;
case Tegra::Texture::TextureType::TextureCubemap:
@@ -53,7 +57,8 @@ static Shader::TextureType ConvertType(const Tegra::Texture::TICEntry& entry) {
case Tegra::Texture::TextureType::TextureCubeArray:
return Shader::TextureType::ColorArrayCube;
default:
throw Shader::NotImplementedException("Unknown texture type");
UNIMPLEMENTED();
return Shader::TextureType::Color2D;
}
}

View File

@@ -1089,8 +1089,8 @@ QStringList GRenderWindow::GetUnsupportedGLExtensions() const {
}
if (!unsupported_ext.empty()) {
LOG_ERROR(Frontend, "GPU does not support all required extensions: {}",
glGetString(GL_RENDERER));
const std::string gl_renderer{reinterpret_cast<const char*>(glGetString(GL_RENDERER))};
LOG_ERROR(Frontend, "GPU does not support all required extensions: {}", gl_renderer);
}
for (const QString& ext : unsupported_ext) {
LOG_ERROR(Frontend, "Unsupported GL extension: {}", ext.toStdString());

View File

@@ -3338,7 +3338,8 @@ void GMainWindow::MigrateConfigFiles() {
}
const auto origin = config_dir_fs_path / filename;
const auto destination = config_dir_fs_path / "custom" / filename;
LOG_INFO(Frontend, "Migrating config file from {} to {}", origin, destination);
LOG_INFO(Frontend, "Migrating config file from {} to {}", origin.string(),
destination.string());
if (!Common::FS::RenameFile(origin, destination)) {
// Delete the old config file if one already exists in the new location.
Common::FS::RemoveFile(origin);

View File

@@ -1,7 +1,7 @@
{
"$schema": "https://raw.githubusercontent.com/microsoft/vcpkg/master/scripts/vcpkg.schema.json",
"name": "yuzu",
"builtin-baseline": "cef0b3ec767df6e83806899fe9525f6cf8d7bc91",
"builtin-baseline": "9b22b40c6c61bf0da2d46346dd44a11e90972cc9",
"version": "1.0",
"dependencies": [
"boost-algorithm",
@@ -37,6 +37,10 @@
{
"name": "catch2",
"version": "2.13.9"
},
{
"name": "fmt",
"version": "9.0.0"
}
]
}