diff options
| author | 2023-05-29 00:35:51 +0100 | |
|---|---|---|
| committer | 2023-07-02 23:09:48 +0100 | |
| commit | 6f7cb69c94bef0795f054d881e061745f69d1eda (patch) | |
| tree | cc0bec2fed92a5645886dde773add00c84d8b9f4 /src/core | |
| parent | Merge pull request #10998 from Morph1984/qt-stop-messing-with-me (diff) | |
| download | yuzu-6f7cb69c94bef0795f054d881e061745f69d1eda.tar.gz yuzu-6f7cb69c94bef0795f054d881e061745f69d1eda.tar.xz yuzu-6f7cb69c94bef0795f054d881e061745f69d1eda.zip | |
Use spans over guest memory where possible instead of copying data.
Diffstat (limited to 'src/core')
| -rw-r--r-- | src/core/core_timing.cpp | 3 | ||||
| -rw-r--r-- | src/core/core_timing.h | 2 | ||||
| -rw-r--r-- | src/core/hle/service/hle_ipc.cpp | 32 | ||||
| -rw-r--r-- | src/core/memory.cpp | 54 | ||||
| -rw-r--r-- | src/core/memory.h | 212 |
5 files changed, 285 insertions, 18 deletions
diff --git a/src/core/core_timing.cpp b/src/core/core_timing.cpp index e6112a3c9..b98a0cb33 100644 --- a/src/core/core_timing.cpp +++ b/src/core/core_timing.cpp | |||
| @@ -70,7 +70,7 @@ void CoreTiming::Initialize(std::function<void()>&& on_thread_init_) { | |||
| 70 | -> std::optional<std::chrono::nanoseconds> { return std::nullopt; }; | 70 | -> std::optional<std::chrono::nanoseconds> { return std::nullopt; }; |
| 71 | ev_lost = CreateEvent("_lost_event", empty_timed_callback); | 71 | ev_lost = CreateEvent("_lost_event", empty_timed_callback); |
| 72 | if (is_multicore) { | 72 | if (is_multicore) { |
| 73 | timer_thread = std::make_unique<std::thread>(ThreadEntry, std::ref(*this)); | 73 | timer_thread = std::make_unique<std::jthread>(ThreadEntry, std::ref(*this)); |
| 74 | } | 74 | } |
| 75 | } | 75 | } |
| 76 | 76 | ||
| @@ -255,7 +255,6 @@ void CoreTiming::ThreadLoop() { | |||
| 255 | #ifdef _WIN32 | 255 | #ifdef _WIN32 |
| 256 | while (!paused && !event.IsSet() && wait_time > 0) { | 256 | while (!paused && !event.IsSet() && wait_time > 0) { |
| 257 | wait_time = *next_time - GetGlobalTimeNs().count(); | 257 | wait_time = *next_time - GetGlobalTimeNs().count(); |
| 258 | |||
| 259 | if (wait_time >= timer_resolution_ns) { | 258 | if (wait_time >= timer_resolution_ns) { |
| 260 | Common::Windows::SleepForOneTick(); | 259 | Common::Windows::SleepForOneTick(); |
| 261 | } else { | 260 | } else { |
diff --git a/src/core/core_timing.h b/src/core/core_timing.h index 5bca1c78d..c20e906fb 100644 --- a/src/core/core_timing.h +++ b/src/core/core_timing.h | |||
| @@ -163,7 +163,7 @@ private: | |||
| 163 | Common::Event pause_event{}; | 163 | Common::Event pause_event{}; |
| 164 | std::mutex basic_lock; | 164 | std::mutex basic_lock; |
| 165 | std::mutex advance_lock; | 165 | std::mutex advance_lock; |
| 166 | std::unique_ptr<std::thread> timer_thread; | 166 | std::unique_ptr<std::jthread> timer_thread; |
| 167 | std::atomic<bool> paused{}; | 167 | std::atomic<bool> paused{}; |
| 168 | std::atomic<bool> paused_set{}; | 168 | std::atomic<bool> paused_set{}; |
| 169 | std::atomic<bool> wait_set{}; | 169 | std::atomic<bool> wait_set{}; |
diff --git a/src/core/hle/service/hle_ipc.cpp b/src/core/hle/service/hle_ipc.cpp index 2290df705..f6a1e54f2 100644 --- a/src/core/hle/service/hle_ipc.cpp +++ b/src/core/hle/service/hle_ipc.cpp | |||
| @@ -329,8 +329,22 @@ std::vector<u8> HLERequestContext::ReadBufferCopy(std::size_t buffer_index) cons | |||
| 329 | } | 329 | } |
| 330 | 330 | ||
| 331 | std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { | 331 | std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) const { |
| 332 | static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_a; | 332 | static thread_local std::array read_buffer_a{ |
| 333 | static thread_local std::array<Common::ScratchBuffer<u8>, 2> read_buffer_x; | 333 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), |
| 334 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 335 | }; | ||
| 336 | static thread_local std::array read_buffer_data_a{ | ||
| 337 | Common::ScratchBuffer<u8>(), | ||
| 338 | Common::ScratchBuffer<u8>(), | ||
| 339 | }; | ||
| 340 | static thread_local std::array read_buffer_x{ | ||
| 341 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 342 | Core::Memory::CpuGuestMemory<u8, Core::Memory::GuestMemoryFlags::SafeRead>(memory, 0, 0), | ||
| 343 | }; | ||
| 344 | static thread_local std::array read_buffer_data_x{ | ||
| 345 | Common::ScratchBuffer<u8>(), | ||
| 346 | Common::ScratchBuffer<u8>(), | ||
| 347 | }; | ||
| 334 | 348 | ||
| 335 | const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && | 349 | const bool is_buffer_a{BufferDescriptorA().size() > buffer_index && |
| 336 | BufferDescriptorA()[buffer_index].Size()}; | 350 | BufferDescriptorA()[buffer_index].Size()}; |
| @@ -339,19 +353,17 @@ std::span<const u8> HLERequestContext::ReadBuffer(std::size_t buffer_index) cons | |||
| 339 | BufferDescriptorA().size() > buffer_index, { return {}; }, | 353 | BufferDescriptorA().size() > buffer_index, { return {}; }, |
| 340 | "BufferDescriptorA invalid buffer_index {}", buffer_index); | 354 | "BufferDescriptorA invalid buffer_index {}", buffer_index); |
| 341 | auto& read_buffer = read_buffer_a[buffer_index]; | 355 | auto& read_buffer = read_buffer_a[buffer_index]; |
| 342 | read_buffer.resize_destructive(BufferDescriptorA()[buffer_index].Size()); | 356 | return read_buffer.Read(BufferDescriptorA()[buffer_index].Address(), |
| 343 | memory.ReadBlock(BufferDescriptorA()[buffer_index].Address(), read_buffer.data(), | 357 | BufferDescriptorA()[buffer_index].Size(), |
| 344 | read_buffer.size()); | 358 | &read_buffer_data_a[buffer_index]); |
| 345 | return read_buffer; | ||
| 346 | } else { | 359 | } else { |
| 347 | ASSERT_OR_EXECUTE_MSG( | 360 | ASSERT_OR_EXECUTE_MSG( |
| 348 | BufferDescriptorX().size() > buffer_index, { return {}; }, | 361 | BufferDescriptorX().size() > buffer_index, { return {}; }, |
| 349 | "BufferDescriptorX invalid buffer_index {}", buffer_index); | 362 | "BufferDescriptorX invalid buffer_index {}", buffer_index); |
| 350 | auto& read_buffer = read_buffer_x[buffer_index]; | 363 | auto& read_buffer = read_buffer_x[buffer_index]; |
| 351 | read_buffer.resize_destructive(BufferDescriptorX()[buffer_index].Size()); | 364 | return read_buffer.Read(BufferDescriptorX()[buffer_index].Address(), |
| 352 | memory.ReadBlock(BufferDescriptorX()[buffer_index].Address(), read_buffer.data(), | 365 | BufferDescriptorX()[buffer_index].Size(), |
| 353 | read_buffer.size()); | 366 | &read_buffer_data_x[buffer_index]); |
| 354 | return read_buffer; | ||
| 355 | } | 367 | } |
| 356 | } | 368 | } |
| 357 | 369 | ||
diff --git a/src/core/memory.cpp b/src/core/memory.cpp index 257406f09..805963178 100644 --- a/src/core/memory.cpp +++ b/src/core/memory.cpp | |||
| @@ -266,6 +266,22 @@ struct Memory::Impl { | |||
| 266 | ReadBlockImpl<true>(*system.ApplicationProcess(), src_addr, dest_buffer, size); | 266 | ReadBlockImpl<true>(*system.ApplicationProcess(), src_addr, dest_buffer, size); |
| 267 | } | 267 | } |
| 268 | 268 | ||
| 269 | const u8* GetSpan(const VAddr src_addr, const std::size_t size) const { | ||
| 270 | if (current_page_table->blocks[src_addr >> YUZU_PAGEBITS] == | ||
| 271 | current_page_table->blocks[(src_addr + size) >> YUZU_PAGEBITS]) { | ||
| 272 | return GetPointerSilent(src_addr); | ||
| 273 | } | ||
| 274 | return nullptr; | ||
| 275 | } | ||
| 276 | |||
| 277 | u8* GetSpan(const VAddr src_addr, const std::size_t size) { | ||
| 278 | if (current_page_table->blocks[src_addr >> YUZU_PAGEBITS] == | ||
| 279 | current_page_table->blocks[(src_addr + size) >> YUZU_PAGEBITS]) { | ||
| 280 | return GetPointerSilent(src_addr); | ||
| 281 | } | ||
| 282 | return nullptr; | ||
| 283 | } | ||
| 284 | |||
| 269 | template <bool UNSAFE> | 285 | template <bool UNSAFE> |
| 270 | void WriteBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr, | 286 | void WriteBlockImpl(const Kernel::KProcess& process, const Common::ProcessAddress dest_addr, |
| 271 | const void* src_buffer, const std::size_t size) { | 287 | const void* src_buffer, const std::size_t size) { |
| @@ -559,7 +575,7 @@ struct Memory::Impl { | |||
| 559 | } | 575 | } |
| 560 | } | 576 | } |
| 561 | 577 | ||
| 562 | const Common::ProcessAddress end = base + size; | 578 | const auto end = base + size; |
| 563 | ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", | 579 | ASSERT_MSG(end <= page_table.pointers.size(), "out of range mapping at {:016X}", |
| 564 | base + page_table.pointers.size()); | 580 | base + page_table.pointers.size()); |
| 565 | 581 | ||
| @@ -570,14 +586,18 @@ struct Memory::Impl { | |||
| 570 | while (base != end) { | 586 | while (base != end) { |
| 571 | page_table.pointers[base].Store(nullptr, type); | 587 | page_table.pointers[base].Store(nullptr, type); |
| 572 | page_table.backing_addr[base] = 0; | 588 | page_table.backing_addr[base] = 0; |
| 573 | 589 | page_table.blocks[base] = 0; | |
| 574 | base += 1; | 590 | base += 1; |
| 575 | } | 591 | } |
| 576 | } else { | 592 | } else { |
| 593 | auto orig_base = base; | ||
| 577 | while (base != end) { | 594 | while (base != end) { |
| 578 | page_table.pointers[base].Store( | 595 | auto host_ptr = |
| 579 | system.DeviceMemory().GetPointer<u8>(target) - (base << YUZU_PAGEBITS), type); | 596 | system.DeviceMemory().GetPointer<u8>(target) - (base << YUZU_PAGEBITS); |
| 580 | page_table.backing_addr[base] = GetInteger(target) - (base << YUZU_PAGEBITS); | 597 | auto backing = GetInteger(target) - (base << YUZU_PAGEBITS); |
| 598 | page_table.pointers[base].Store(host_ptr, type); | ||
| 599 | page_table.backing_addr[base] = backing; | ||
| 600 | page_table.blocks[base] = orig_base << YUZU_PAGEBITS; | ||
| 581 | 601 | ||
| 582 | ASSERT_MSG(page_table.pointers[base].Pointer(), | 602 | ASSERT_MSG(page_table.pointers[base].Pointer(), |
| 583 | "memory mapping base yield a nullptr within the table"); | 603 | "memory mapping base yield a nullptr within the table"); |
| @@ -747,6 +767,14 @@ struct Memory::Impl { | |||
| 747 | VAddr last_address; | 767 | VAddr last_address; |
| 748 | }; | 768 | }; |
| 749 | 769 | ||
| 770 | void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) { | ||
| 771 | system.GPU().InvalidateRegion(GetInteger(dest_addr), size); | ||
| 772 | } | ||
| 773 | |||
| 774 | void FlushRegion(Common::ProcessAddress dest_addr, size_t size) { | ||
| 775 | system.GPU().FlushRegion(GetInteger(dest_addr), size); | ||
| 776 | } | ||
| 777 | |||
| 750 | Core::System& system; | 778 | Core::System& system; |
| 751 | Common::PageTable* current_page_table = nullptr; | 779 | Common::PageTable* current_page_table = nullptr; |
| 752 | std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES> | 780 | std::array<VideoCore::RasterizerDownloadArea, Core::Hardware::NUM_CPU_CORES> |
| @@ -881,6 +909,14 @@ void Memory::ReadBlockUnsafe(const Common::ProcessAddress src_addr, void* dest_b | |||
| 881 | impl->ReadBlockUnsafe(src_addr, dest_buffer, size); | 909 | impl->ReadBlockUnsafe(src_addr, dest_buffer, size); |
| 882 | } | 910 | } |
| 883 | 911 | ||
| 912 | const u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) const { | ||
| 913 | return impl->GetSpan(src_addr, size); | ||
| 914 | } | ||
| 915 | |||
| 916 | u8* Memory::GetSpan(const VAddr src_addr, const std::size_t size) { | ||
| 917 | return impl->GetSpan(src_addr, size); | ||
| 918 | } | ||
| 919 | |||
| 884 | void Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer, | 920 | void Memory::WriteBlock(const Common::ProcessAddress dest_addr, const void* src_buffer, |
| 885 | const std::size_t size) { | 921 | const std::size_t size) { |
| 886 | impl->WriteBlock(dest_addr, src_buffer, size); | 922 | impl->WriteBlock(dest_addr, src_buffer, size); |
| @@ -924,4 +960,12 @@ void Memory::MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug) | |||
| 924 | impl->MarkRegionDebug(GetInteger(vaddr), size, debug); | 960 | impl->MarkRegionDebug(GetInteger(vaddr), size, debug); |
| 925 | } | 961 | } |
| 926 | 962 | ||
| 963 | void Memory::InvalidateRegion(Common::ProcessAddress dest_addr, size_t size) { | ||
| 964 | impl->InvalidateRegion(dest_addr, size); | ||
| 965 | } | ||
| 966 | |||
| 967 | void Memory::FlushRegion(Common::ProcessAddress dest_addr, size_t size) { | ||
| 968 | impl->FlushRegion(dest_addr, size); | ||
| 969 | } | ||
| 970 | |||
| 927 | } // namespace Core::Memory | 971 | } // namespace Core::Memory |
diff --git a/src/core/memory.h b/src/core/memory.h index ea01824f8..ea33c769c 100644 --- a/src/core/memory.h +++ b/src/core/memory.h | |||
| @@ -5,8 +5,12 @@ | |||
| 5 | 5 | ||
| 6 | #include <cstddef> | 6 | #include <cstddef> |
| 7 | #include <memory> | 7 | #include <memory> |
| 8 | #include <optional> | ||
| 8 | #include <span> | 9 | #include <span> |
| 9 | #include <string> | 10 | #include <string> |
| 11 | #include <vector> | ||
| 12 | |||
| 13 | #include "common/scratch_buffer.h" | ||
| 10 | #include "common/typed_address.h" | 14 | #include "common/typed_address.h" |
| 11 | #include "core/hle/result.h" | 15 | #include "core/hle/result.h" |
| 12 | 16 | ||
| @@ -24,6 +28,10 @@ class PhysicalMemory; | |||
| 24 | class KProcess; | 28 | class KProcess; |
| 25 | } // namespace Kernel | 29 | } // namespace Kernel |
| 26 | 30 | ||
| 31 | namespace Tegra { | ||
| 32 | class MemoryManager; | ||
| 33 | } | ||
| 34 | |||
| 27 | namespace Core::Memory { | 35 | namespace Core::Memory { |
| 28 | 36 | ||
| 29 | /** | 37 | /** |
| @@ -343,6 +351,9 @@ public: | |||
| 343 | */ | 351 | */ |
| 344 | void ReadBlockUnsafe(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size); | 352 | void ReadBlockUnsafe(Common::ProcessAddress src_addr, void* dest_buffer, std::size_t size); |
| 345 | 353 | ||
| 354 | const u8* GetSpan(const VAddr src_addr, const std::size_t size) const; | ||
| 355 | u8* GetSpan(const VAddr src_addr, const std::size_t size); | ||
| 356 | |||
| 346 | /** | 357 | /** |
| 347 | * Writes a range of bytes into the current process' address space at the specified | 358 | * Writes a range of bytes into the current process' address space at the specified |
| 348 | * virtual address. | 359 | * virtual address. |
| @@ -461,6 +472,8 @@ public: | |||
| 461 | void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug); | 472 | void MarkRegionDebug(Common::ProcessAddress vaddr, u64 size, bool debug); |
| 462 | 473 | ||
| 463 | void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers); | 474 | void SetGPUDirtyManagers(std::span<Core::GPUDirtyMemoryManager> managers); |
| 475 | void InvalidateRegion(Common::ProcessAddress dest_addr, size_t size); | ||
| 476 | void FlushRegion(Common::ProcessAddress dest_addr, size_t size); | ||
| 464 | 477 | ||
| 465 | private: | 478 | private: |
| 466 | Core::System& system; | 479 | Core::System& system; |
| @@ -469,4 +482,203 @@ private: | |||
| 469 | std::unique_ptr<Impl> impl; | 482 | std::unique_ptr<Impl> impl; |
| 470 | }; | 483 | }; |
| 471 | 484 | ||
| 485 | enum GuestMemoryFlags : u32 { | ||
| 486 | Read = 1 << 0, | ||
| 487 | Write = 1 << 1, | ||
| 488 | Safe = 1 << 2, | ||
| 489 | Cached = 1 << 3, | ||
| 490 | |||
| 491 | SafeRead = Read | Safe, | ||
| 492 | SafeWrite = Write | Safe, | ||
| 493 | SafeReadWrite = SafeRead | SafeWrite, | ||
| 494 | SafeReadCachedWrite = SafeReadWrite | Cached, | ||
| 495 | |||
| 496 | UnsafeRead = Read, | ||
| 497 | UnsafeWrite = Write, | ||
| 498 | UnsafeReadWrite = UnsafeRead | UnsafeWrite, | ||
| 499 | UnsafeReadCachedWrite = UnsafeReadWrite | Cached, | ||
| 500 | }; | ||
| 501 | |||
| 502 | namespace { | ||
| 503 | template <typename M, typename T, GuestMemoryFlags FLAGS> | ||
| 504 | class GuestMemory { | ||
| 505 | using iterator = T*; | ||
| 506 | using const_iterator = const T*; | ||
| 507 | using value_type = T; | ||
| 508 | using element_type = T; | ||
| 509 | using iterator_category = std::contiguous_iterator_tag; | ||
| 510 | |||
| 511 | public: | ||
| 512 | GuestMemory() = delete; | ||
| 513 | explicit GuestMemory(M& memory_, u64 addr_, std::size_t size_, | ||
| 514 | Common::ScratchBuffer<T>* backup = nullptr) | ||
| 515 | : memory{memory_}, addr{addr_}, size{size_} { | ||
| 516 | static_assert(FLAGS & GuestMemoryFlags::Read || FLAGS & GuestMemoryFlags::Write); | ||
| 517 | if constexpr (FLAGS & GuestMemoryFlags::Read) { | ||
| 518 | Read(addr, size, backup); | ||
| 519 | } | ||
| 520 | } | ||
| 521 | |||
| 522 | ~GuestMemory() = default; | ||
| 523 | |||
| 524 | T* data() noexcept { | ||
| 525 | return data_span.data(); | ||
| 526 | } | ||
| 527 | |||
| 528 | const T* data() const noexcept { | ||
| 529 | return data_span.data(); | ||
| 530 | } | ||
| 531 | |||
| 532 | [[nodiscard]] T* begin() noexcept { | ||
| 533 | return data(); | ||
| 534 | } | ||
| 535 | |||
| 536 | [[nodiscard]] const T* begin() const noexcept { | ||
| 537 | return data(); | ||
| 538 | } | ||
| 539 | |||
| 540 | [[nodiscard]] T* end() noexcept { | ||
| 541 | return data() + size; | ||
| 542 | } | ||
| 543 | |||
| 544 | [[nodiscard]] const T* end() const noexcept { | ||
| 545 | return data() + size; | ||
| 546 | } | ||
| 547 | |||
| 548 | T& operator[](size_t index) noexcept { | ||
| 549 | return data_span[index]; | ||
| 550 | } | ||
| 551 | |||
| 552 | const T& operator[](size_t index) const noexcept { | ||
| 553 | return data_span[index]; | ||
| 554 | } | ||
| 555 | |||
| 556 | void SetAddressAndSize(u64 addr_, std::size_t size_) noexcept { | ||
| 557 | addr = addr_; | ||
| 558 | size = size_; | ||
| 559 | addr_changed = true; | ||
| 560 | } | ||
| 561 | |||
| 562 | std::span<T> Read(u64 addr_, std::size_t size_, | ||
| 563 | Common::ScratchBuffer<T>* backup = nullptr) noexcept { | ||
| 564 | addr = addr_; | ||
| 565 | size = size_; | ||
| 566 | if (size == 0) { | ||
| 567 | is_data_copy = true; | ||
| 568 | return {}; | ||
| 569 | } | ||
| 570 | |||
| 571 | if (TrySetSpan()) { | ||
| 572 | if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 573 | memory.FlushRegion(addr, size * sizeof(T)); | ||
| 574 | } | ||
| 575 | } else { | ||
| 576 | if (backup) { | ||
| 577 | backup->resize_destructive(size); | ||
| 578 | data_span = *backup; | ||
| 579 | } else { | ||
| 580 | data_copy.resize(size); | ||
| 581 | data_span = std::span(data_copy); | ||
| 582 | } | ||
| 583 | is_data_copy = true; | ||
| 584 | span_valid = true; | ||
| 585 | if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 586 | memory.ReadBlock(addr, data_span.data(), size * sizeof(T)); | ||
| 587 | } else { | ||
| 588 | memory.ReadBlockUnsafe(addr, data_span.data(), size * sizeof(T)); | ||
| 589 | } | ||
| 590 | } | ||
| 591 | return data_span; | ||
| 592 | } | ||
| 593 | |||
| 594 | void Write(std::span<T> write_data) noexcept { | ||
| 595 | if constexpr (FLAGS & GuestMemoryFlags::Cached) { | ||
| 596 | memory.WriteBlockCached(addr, write_data.data(), size * sizeof(T)); | ||
| 597 | } else if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 598 | memory.WriteBlock(addr, write_data.data(), size * sizeof(T)); | ||
| 599 | } else { | ||
| 600 | memory.WriteBlockUnsafe(addr, write_data.data(), size * sizeof(T)); | ||
| 601 | } | ||
| 602 | } | ||
| 603 | |||
| 604 | bool TrySetSpan() noexcept { | ||
| 605 | if (u8* ptr = memory.GetSpan(addr, size * sizeof(T)); ptr) { | ||
| 606 | data_span = {reinterpret_cast<T*>(ptr), size}; | ||
| 607 | span_valid = true; | ||
| 608 | return true; | ||
| 609 | } | ||
| 610 | return false; | ||
| 611 | } | ||
| 612 | |||
| 613 | protected: | ||
| 614 | bool IsDataCopy() const noexcept { | ||
| 615 | return is_data_copy; | ||
| 616 | } | ||
| 617 | |||
| 618 | bool AddressChanged() const noexcept { | ||
| 619 | return addr_changed; | ||
| 620 | } | ||
| 621 | |||
| 622 | M& memory; | ||
| 623 | u64 addr; | ||
| 624 | size_t size; | ||
| 625 | std::span<T> data_span{}; | ||
| 626 | std::vector<T> data_copy; | ||
| 627 | bool span_valid{false}; | ||
| 628 | bool is_data_copy{false}; | ||
| 629 | bool addr_changed{false}; | ||
| 630 | }; | ||
| 631 | |||
| 632 | template <typename M, typename T, GuestMemoryFlags FLAGS> | ||
| 633 | class GuestMemoryScoped : public GuestMemory<M, T, FLAGS> { | ||
| 634 | public: | ||
| 635 | GuestMemoryScoped() = delete; | ||
| 636 | explicit GuestMemoryScoped(M& memory_, u64 addr_, std::size_t size_, | ||
| 637 | Common::ScratchBuffer<T>* backup = nullptr) | ||
| 638 | : GuestMemory<M, T, FLAGS>(memory_, addr_, size_, backup) { | ||
| 639 | if constexpr (!(FLAGS & GuestMemoryFlags::Read)) { | ||
| 640 | if (!this->TrySetSpan()) { | ||
| 641 | if (backup) { | ||
| 642 | this->data_span = *backup; | ||
| 643 | this->span_valid = true; | ||
| 644 | this->is_data_copy = true; | ||
| 645 | } | ||
| 646 | } | ||
| 647 | } | ||
| 648 | } | ||
| 649 | |||
| 650 | ~GuestMemoryScoped() { | ||
| 651 | if constexpr (FLAGS & GuestMemoryFlags::Write) { | ||
| 652 | if (this->size == 0) [[unlikely]] { | ||
| 653 | return; | ||
| 654 | } | ||
| 655 | |||
| 656 | if (this->AddressChanged() || this->IsDataCopy()) { | ||
| 657 | ASSERT(this->span_valid); | ||
| 658 | if constexpr (FLAGS & GuestMemoryFlags::Cached) { | ||
| 659 | this->memory.WriteBlockCached(this->addr, this->data_span.data(), | ||
| 660 | this->size * sizeof(T)); | ||
| 661 | } else if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 662 | this->memory.WriteBlock(this->addr, this->data_span.data(), | ||
| 663 | this->size * sizeof(T)); | ||
| 664 | } else { | ||
| 665 | this->memory.WriteBlockUnsafe(this->addr, this->data_span.data(), | ||
| 666 | this->size * sizeof(T)); | ||
| 667 | } | ||
| 668 | } else if constexpr (FLAGS & GuestMemoryFlags::Safe) { | ||
| 669 | this->memory.InvalidateRegion(this->addr, this->size * sizeof(T)); | ||
| 670 | } | ||
| 671 | } | ||
| 672 | } | ||
| 673 | }; | ||
| 674 | } // namespace | ||
| 675 | |||
| 676 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 677 | using CpuGuestMemory = GuestMemory<Memory, T, FLAGS>; | ||
| 678 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 679 | using CpuGuestMemoryScoped = GuestMemoryScoped<Memory, T, FLAGS>; | ||
| 680 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 681 | using GpuGuestMemory = GuestMemory<Tegra::MemoryManager, T, FLAGS>; | ||
| 682 | template <typename T, GuestMemoryFlags FLAGS> | ||
| 683 | using GpuGuestMemoryScoped = GuestMemoryScoped<Tegra::MemoryManager, T, FLAGS>; | ||
| 472 | } // namespace Core::Memory | 684 | } // namespace Core::Memory |