mirror of
https://git.eden-emu.dev/eden-emu/eden.git
synced 2026-09-29 11:53:24 +00:00
Compare commits
4 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| cbb74b3e70 | |||
| 7da774f766 | |||
| e875a3196b | |||
| 4eb082485d |
@@ -9,3 +9,11 @@ At the moment of writing, we do not support CFW such as Atmosphere, due to:
|
|||||||
We do however, maintain HLE compatibility with the former mentioned CFW, applications that require Atmosphere to run will run fine in the emulator without any adjustments.
|
We do however, maintain HLE compatibility with the former mentioned CFW, applications that require Atmosphere to run will run fine in the emulator without any adjustments.
|
||||||
|
|
||||||
If they don't run - then that's a bug!
|
If they don't run - then that's a bug!
|
||||||
|
|
||||||
|
## Atmosphere
|
||||||
|
|
||||||
|
Fusee Galee, the bootloader and other low-level mechanisms are not emulated at the moment.
|
||||||
|
|
||||||
|
Having OFW is recommended, but may not be required (untested).
|
||||||
|
|
||||||
|
Extract the contents of Atmosphere into `sdmc`. Then to launch simply use `-hlaunch` instead (orthogonal to `-qlaunch`).
|
||||||
|
|||||||
@@ -10,6 +10,9 @@ There are two main applications, an SDL-based app (`eden-cli`) and a Qt based ap
|
|||||||
- `-u <number>`: Select the index of the user to load as.
|
- `-u <number>`: Select the index of the user to load as.
|
||||||
- `-input-profile <name>`: Specifies input profile name to use (for player #0 only).
|
- `-input-profile <name>`: Specifies input profile name to use (for player #0 only).
|
||||||
- `-qlaunch`: Launch QLaunch.
|
- `-qlaunch`: Launch QLaunch.
|
||||||
|
- `-hlaunch`: Launch homebrew launcher `nx-hbloader`.
|
||||||
|
- Requires a copy of Atmosphere to be extracted onto `sdmc`.
|
||||||
|
- This is a shorthand for `<eden folder>/sdmc/atmosphere/hbl.nsp`.
|
||||||
- `-setup`: Launch setup applet.
|
- `-setup`: Launch setup applet.
|
||||||
|
|
||||||
## eden-cli
|
## eden-cli
|
||||||
|
|||||||
@@ -14,17 +14,12 @@
|
|||||||
#include <mutex>
|
#include <mutex>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
#include <span>
|
#include <span>
|
||||||
#include <utility>
|
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/range_mutex.h"
|
#include "common/range_mutex.h"
|
||||||
#include "common/scratch_buffer.h"
|
#include "common/scratch_buffer.h"
|
||||||
#include "common/virtual_buffer.h"
|
#include "common/virtual_buffer.h"
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#endif
|
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
|
||||||
constexpr size_t DEVICE_PAGEBITS = 12ULL;
|
constexpr size_t DEVICE_PAGEBITS = 12ULL;
|
||||||
@@ -50,74 +45,6 @@ class DeviceMemoryManager {
|
|||||||
using DeviceMethods = typename Traits::DeviceMethods;
|
using DeviceMethods = typename Traits::DeviceMethods;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
class MirrorMapping {
|
|
||||||
public:
|
|
||||||
MirrorMapping() = default;
|
|
||||||
MirrorMapping(u8* mapped_base_, size_t mapped_size_, size_t data_offset_)
|
|
||||||
: mapped_base{mapped_base_}, mapped_size{mapped_size_}, data_offset{data_offset_} {}
|
|
||||||
|
|
||||||
MirrorMapping(const MirrorMapping&) = delete;
|
|
||||||
MirrorMapping& operator=(const MirrorMapping&) = delete;
|
|
||||||
|
|
||||||
MirrorMapping(MirrorMapping&& other) noexcept {
|
|
||||||
MoveFrom(other);
|
|
||||||
}
|
|
||||||
|
|
||||||
MirrorMapping& operator=(MirrorMapping&& other) noexcept {
|
|
||||||
if (this != &other) {
|
|
||||||
Release();
|
|
||||||
MoveFrom(other);
|
|
||||||
}
|
|
||||||
return *this;
|
|
||||||
}
|
|
||||||
|
|
||||||
~MirrorMapping() {
|
|
||||||
Release();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] bool IsValid() const noexcept {
|
|
||||||
return mapped_base != nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] explicit operator bool() const noexcept {
|
|
||||||
return IsValid();
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] u8* Data() noexcept {
|
|
||||||
return mapped_base ? mapped_base + data_offset : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] const u8* Data() const noexcept {
|
|
||||||
return mapped_base ? mapped_base + data_offset : nullptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
[[nodiscard]] size_t Size() const noexcept {
|
|
||||||
return mapped_size >= data_offset ? mapped_size - data_offset : 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
|
||||||
void MoveFrom(MirrorMapping& other) noexcept {
|
|
||||||
mapped_base = std::exchange(other.mapped_base, nullptr);
|
|
||||||
mapped_size = std::exchange(other.mapped_size, 0);
|
|
||||||
data_offset = std::exchange(other.data_offset, 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Release() noexcept {
|
|
||||||
#if defined(__linux__)
|
|
||||||
if (mapped_base) {
|
|
||||||
munmap(mapped_base, mapped_size);
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
mapped_base = nullptr;
|
|
||||||
mapped_size = 0;
|
|
||||||
data_offset = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
u8* mapped_base{};
|
|
||||||
size_t mapped_size{};
|
|
||||||
size_t data_offset{};
|
|
||||||
};
|
|
||||||
|
|
||||||
DeviceMemoryManager(const DeviceMemory& device_memory);
|
DeviceMemoryManager(const DeviceMemory& device_memory);
|
||||||
~DeviceMemoryManager();
|
~DeviceMemoryManager();
|
||||||
|
|
||||||
@@ -191,11 +118,6 @@ public:
|
|||||||
void WriteBlock(DAddr address, const void* src_pointer, size_t size);
|
void WriteBlock(DAddr address, const void* src_pointer, size_t size);
|
||||||
void WriteBlockUnsafe(DAddr address, const void* src_pointer, size_t size);
|
void WriteBlockUnsafe(DAddr address, const void* src_pointer, size_t size);
|
||||||
|
|
||||||
[[nodiscard]] MirrorMapping CreateMirrorMapping(DAddr address, size_t size) const;
|
|
||||||
[[nodiscard]] u64 GetMappingVersion() const noexcept {
|
|
||||||
return mapping_version.load(std::memory_order_acquire);
|
|
||||||
}
|
|
||||||
|
|
||||||
Asid RegisterProcess(Memory::Memory* memory);
|
Asid RegisterProcess(Memory::Memory* memory);
|
||||||
void UnregisterProcess(Asid id);
|
void UnregisterProcess(Asid id);
|
||||||
|
|
||||||
@@ -314,7 +236,6 @@ private:
|
|||||||
std::unique_ptr<CachedPages> cached_pages;
|
std::unique_ptr<CachedPages> cached_pages;
|
||||||
Common::RangeMutex counter_guard;
|
Common::RangeMutex counter_guard;
|
||||||
std::mutex mapping_guard;
|
std::mutex mapping_guard;
|
||||||
std::atomic<u64> mapping_version{1};
|
|
||||||
|
|
||||||
|
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -4,10 +4,6 @@
|
|||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
#if defined(__linux__) && !defined(_GNU_SOURCE)
|
|
||||||
#define _GNU_SOURCE
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include <atomic>
|
#include <atomic>
|
||||||
#include <limits>
|
#include <limits>
|
||||||
#include <memory>
|
#include <memory>
|
||||||
@@ -15,17 +11,6 @@
|
|||||||
#include <algorithm>
|
#include <algorithm>
|
||||||
#include <vector>
|
#include <vector>
|
||||||
|
|
||||||
#if defined(__linux__)
|
|
||||||
#include <sys/mman.h>
|
|
||||||
#ifndef MREMAP_MAYMOVE
|
|
||||||
#define MREMAP_MAYMOVE 1
|
|
||||||
#endif
|
|
||||||
#ifndef MREMAP_FIXED
|
|
||||||
#define MREMAP_FIXED 2
|
|
||||||
#endif
|
|
||||||
extern "C" void* mremap(void* old_address, size_t old_size, size_t new_size, int flags, ...);
|
|
||||||
#endif
|
|
||||||
|
|
||||||
#include "common/address_space.h"
|
#include "common/address_space.h"
|
||||||
#include "common/address_space.inc"
|
#include "common/address_space.inc"
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
@@ -255,7 +240,6 @@ void DeviceMemoryManager<Traits>::Map(DAddr address, VAddr virtual_address, size
|
|||||||
impl->multi_dev_address.Register(new_dev, start_id);
|
impl->multi_dev_address.Register(new_dev, start_id);
|
||||||
}
|
}
|
||||||
t_slot = {};
|
t_slot = {};
|
||||||
mapping_version.fetch_add(1, std::memory_order_release);
|
|
||||||
if (track) {
|
if (track) {
|
||||||
TrackContinuityImpl(address, virtual_address, size, asid);
|
TrackContinuityImpl(address, virtual_address, size, asid);
|
||||||
}
|
}
|
||||||
@@ -288,7 +272,6 @@ void DeviceMemoryManager<Traits>::Unmap(DAddr address, size_t size) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
t_slot = {};
|
t_slot = {};
|
||||||
mapping_version.fetch_add(1, std::memory_order_release);
|
|
||||||
}
|
}
|
||||||
template <typename Traits>
|
template <typename Traits>
|
||||||
void DeviceMemoryManager<Traits>::TrackContinuityImpl(DAddr address, VAddr virtual_address,
|
void DeviceMemoryManager<Traits>::TrackContinuityImpl(DAddr address, VAddr virtual_address,
|
||||||
@@ -332,78 +315,6 @@ const u8* DeviceMemoryManager<Traits>::GetSpan(const DAddr src_addr, const std::
|
|||||||
return nullptr;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
template <typename Traits>
|
|
||||||
typename DeviceMemoryManager<Traits>::MirrorMapping DeviceMemoryManager<Traits>::CreateMirrorMapping(
|
|
||||||
DAddr address, size_t size) const {
|
|
||||||
#if !defined(__linux__)
|
|
||||||
return {};
|
|
||||||
#else
|
|
||||||
if (size == 0) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const DAddr aligned_address = Common::AlignDown(address, DAddr{page_size});
|
|
||||||
const size_t data_offset = static_cast<size_t>(address - aligned_address);
|
|
||||||
const size_t mapped_size = Common::AlignUp(size + data_offset, page_size);
|
|
||||||
|
|
||||||
struct Segment {
|
|
||||||
const u8* source;
|
|
||||||
size_t size;
|
|
||||||
};
|
|
||||||
|
|
||||||
std::vector<Segment> segments;
|
|
||||||
segments.reserve(Common::DivCeil(mapped_size, page_size));
|
|
||||||
|
|
||||||
size_t remaining_size = mapped_size;
|
|
||||||
size_t page_index = aligned_address >> page_bits;
|
|
||||||
while (remaining_size > 0) {
|
|
||||||
const size_t next_pages = std::size_t(tracked_entries[page_index].continuity_tracker);
|
|
||||||
const size_t copy_amount = (std::min)(next_pages << page_bits, remaining_size);
|
|
||||||
|
|
||||||
const auto phys_addr = tracked_entries[page_index].compressed_physical_ptr;
|
|
||||||
if (phys_addr == 0) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto* source =
|
|
||||||
GetPointerFromRaw<u8>(PAddr(phys_addr - 1U) << Memory::YUZU_PAGEBITS);
|
|
||||||
|
|
||||||
if (!segments.empty() && segments.back().source + segments.back().size == source) {
|
|
||||||
segments.back().size += copy_amount;
|
|
||||||
} else {
|
|
||||||
segments.push_back({source, copy_amount});
|
|
||||||
}
|
|
||||||
|
|
||||||
page_index += next_pages;
|
|
||||||
remaining_size -= copy_amount;
|
|
||||||
}
|
|
||||||
|
|
||||||
void* const mirror_base =
|
|
||||||
mmap(nullptr, mapped_size, PROT_NONE, MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
|
|
||||||
if (mirror_base == MAP_FAILED) {
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
|
|
||||||
size_t mirror_offset = 0;
|
|
||||||
for (const auto& segment : segments) {
|
|
||||||
void* const target = static_cast<u8*>(mirror_base) + mirror_offset;
|
|
||||||
void* const result = mremap(const_cast<u8*>(segment.source), 0, segment.size,
|
|
||||||
MREMAP_MAYMOVE | MREMAP_FIXED, target);
|
|
||||||
if (result == MAP_FAILED) {
|
|
||||||
munmap(mirror_base, mapped_size);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
if (mprotect(result, segment.size, PROT_READ | PROT_WRITE) != 0) {
|
|
||||||
munmap(mirror_base, mapped_size);
|
|
||||||
return {};
|
|
||||||
}
|
|
||||||
mirror_offset += segment.size;
|
|
||||||
}
|
|
||||||
|
|
||||||
return MirrorMapping{static_cast<u8*>(mirror_base), mapped_size, data_offset};
|
|
||||||
#endif
|
|
||||||
}
|
|
||||||
|
|
||||||
template <typename Traits>
|
template <typename Traits>
|
||||||
void DeviceMemoryManager<Traits>::InnerGatherDeviceAddresses(Common::ScratchBuffer<u32>& buffer,
|
void DeviceMemoryManager<Traits>::InnerGatherDeviceAddresses(Common::ScratchBuffer<u32>& buffer,
|
||||||
PAddr address) {
|
PAddr address) {
|
||||||
|
|||||||
@@ -1,3 +1,6 @@
|
|||||||
|
// SPDX-FileCopyrightText: Copyright 2026 Eden Emulator Project
|
||||||
|
// SPDX-License-Identifier: GPL-3.0-or-later
|
||||||
|
|
||||||
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
// SPDX-FileCopyrightText: Copyright 2023 yuzu Emulator Project
|
||||||
// SPDX-License-Identifier: GPL-2.0-or-later
|
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||||
|
|
||||||
@@ -268,7 +271,8 @@ Result KCapabilities::SetHandleTableCapability(const u32 cap) {
|
|||||||
Result KCapabilities::SetDebugFlagsCapability(const u32 cap) {
|
Result KCapabilities::SetDebugFlagsCapability(const u32 cap) {
|
||||||
// Validate.
|
// Validate.
|
||||||
const DebugFlags pack{cap};
|
const DebugFlags pack{cap};
|
||||||
R_UNLESS(pack.reserved == 0, ResultReservedUsed);
|
// TODO: Enabling this breaks compatibility with HBloader and such
|
||||||
|
//R_UNLESS(pack.reserved == 0, ResultReservedUsed);
|
||||||
|
|
||||||
DebugFlags debug_capabilities{m_debug_capabilities};
|
DebugFlags debug_capabilities{m_debug_capabilities};
|
||||||
debug_capabilities.allow_debug.Assign(pack.allow_debug);
|
debug_capabilities.allow_debug.Assign(pack.allow_debug);
|
||||||
|
|||||||
@@ -629,7 +629,7 @@ Errno BSD::BindImpl(s32 fd, std::span<const u8> addr) {
|
|||||||
if (!IsFileDescriptorValid(fd)) {
|
if (!IsFileDescriptorValid(fd)) {
|
||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
ASSERT(addr.size() == sizeof(SockAddrIn));
|
ASSERT(addr.size() >= 16);
|
||||||
auto addr_in = GetValue<SockAddrIn>(addr);
|
auto addr_in = GetValue<SockAddrIn>(addr);
|
||||||
|
|
||||||
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
|
return Translate(file_descriptors[fd]->socket->Bind(Translate(addr_in)));
|
||||||
@@ -640,7 +640,7 @@ Errno BSD::ConnectImpl(s32 fd, std::span<const u8> addr) {
|
|||||||
return Errno::BADF;
|
return Errno::BADF;
|
||||||
}
|
}
|
||||||
|
|
||||||
UNIMPLEMENTED_IF(addr.size() != sizeof(SockAddrIn));
|
ASSERT(addr.size() >= 16);
|
||||||
auto addr_in = GetValue<SockAddrIn>(addr);
|
auto addr_in = GetValue<SockAddrIn>(addr);
|
||||||
|
|
||||||
const Errno result = Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
|
const Errno result = Translate(file_descriptors[fd]->socket->Connect(Translate(addr_in)));
|
||||||
@@ -874,7 +874,7 @@ std::pair<s32, Errno> BSD::RecvFromImpl(s32 fd, u32 flags, std::vector<u8>& mess
|
|||||||
if (ret < 0) {
|
if (ret < 0) {
|
||||||
addr.clear();
|
addr.clear();
|
||||||
} else {
|
} else {
|
||||||
ASSERT(addr.size() == sizeof(SockAddrIn));
|
ASSERT(addr.size() >= 16);
|
||||||
const SockAddrIn result = Translate(addr_in);
|
const SockAddrIn result = Translate(addr_in);
|
||||||
PutValue(addr, result);
|
PutValue(addr, result);
|
||||||
}
|
}
|
||||||
@@ -899,7 +899,7 @@ std::pair<s32, Errno> BSD::SendToImpl(s32 fd, u32 flags, std::span<const u8> mes
|
|||||||
Network::SockAddrIn addr_in;
|
Network::SockAddrIn addr_in;
|
||||||
Network::SockAddrIn* p_addr_in = nullptr;
|
Network::SockAddrIn* p_addr_in = nullptr;
|
||||||
if (!addr.empty()) {
|
if (!addr.empty()) {
|
||||||
ASSERT(addr.size() == sizeof(SockAddrIn));
|
ASSERT(addr.size() >= 16);
|
||||||
auto guest_addr_in = GetValue<SockAddrIn>(addr);
|
auto guest_addr_in = GetValue<SockAddrIn>(addr);
|
||||||
addr_in = Translate(guest_addr_in);
|
addr_in = Translate(guest_addr_in);
|
||||||
p_addr_in = &addr_in;
|
p_addr_in = &addr_in;
|
||||||
|
|||||||
@@ -238,7 +238,7 @@ static std::vector<u8> SerializeAddrInfo(const std::vector<Network::AddrInfo>& v
|
|||||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.family))); // ai_family
|
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.family))); // ai_family
|
||||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.socket_type))); // ai_socktype
|
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.socket_type))); // ai_socktype
|
||||||
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.protocol))); // ai_protocol
|
Append<u32_be>(data, static_cast<u32>(Translate(addrinfo.protocol))); // ai_protocol
|
||||||
Append<u32_be>(data, sizeof(SockAddrIn)); // ai_addrlen
|
Append<u32_be>(data, 16); // ai_addrlen
|
||||||
// ^ *not* sizeof(SerializedSockAddrIn), not that it matters since they're the same size
|
// ^ *not* sizeof(SerializedSockAddrIn), not that it matters since they're the same size
|
||||||
|
|
||||||
// ai_addr:
|
// ai_addr:
|
||||||
|
|||||||
@@ -110,8 +110,9 @@ struct SockAddrIn {
|
|||||||
u8 family;
|
u8 family;
|
||||||
u16 portno;
|
u16 portno;
|
||||||
std::array<u8, 4> ip;
|
std::array<u8, 4> ip;
|
||||||
std::array<u8, 8> zeroes;
|
std::array<u8, 248> zeroes;
|
||||||
};
|
};
|
||||||
|
static_assert(sizeof(SockAddrIn) == 0x100);
|
||||||
|
|
||||||
enum class PollEvents : u16 {
|
enum class PollEvents : u16 {
|
||||||
// Using Pascal case because IN is a macro on Windows.
|
// Using Pascal case because IN is a macro on Windows.
|
||||||
|
|||||||
@@ -265,13 +265,9 @@ PollEvents Translate(Network::PollEvents flags) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
Network::SockAddrIn Translate(SockAddrIn value) {
|
Network::SockAddrIn Translate(SockAddrIn value) {
|
||||||
if (value.len != 0 && value.len != sizeof(value) && value.len != 6) {
|
// All lengths are valid, from [0 upto 256]
|
||||||
LOG_WARNING(Service, "Unexpected SockAddrIn len={}, expected 0, {}, or 6",
|
|
||||||
value.len, sizeof(value));
|
|
||||||
}
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
.family = Translate(static_cast<Domain>(value.family)),
|
.family = Translate(Domain(value.family)),
|
||||||
.ip = value.ip,
|
.ip = value.ip,
|
||||||
.portno = static_cast<u16>(value.portno >> 8 | value.portno << 8),
|
.portno = static_cast<u16>(value.portno >> 8 | value.portno << 8),
|
||||||
};
|
};
|
||||||
@@ -279,7 +275,7 @@ Network::SockAddrIn Translate(SockAddrIn value) {
|
|||||||
|
|
||||||
SockAddrIn Translate(Network::SockAddrIn value) {
|
SockAddrIn Translate(Network::SockAddrIn value) {
|
||||||
return {
|
return {
|
||||||
.len = sizeof(SockAddrIn),
|
.len = 16,
|
||||||
.family = static_cast<u8>(Translate(value.family)),
|
.family = static_cast<u8>(Translate(value.family)),
|
||||||
.portno = static_cast<u16>(value.portno >> 8 | value.portno << 8),
|
.portno = static_cast<u16>(value.portno >> 8 | value.portno << 8),
|
||||||
.ip = value.ip,
|
.ip = value.ip,
|
||||||
|
|||||||
@@ -104,51 +104,6 @@ void BufferCache<P>::TickFrame() {
|
|||||||
RunGarbageCollector();
|
RunGarbageCollector();
|
||||||
}
|
}
|
||||||
++frame_tick;
|
++frame_tick;
|
||||||
static constexpr u64 mirror_stats_log_interval = 300;
|
|
||||||
if ((frame_tick % mirror_stats_log_interval) == 0) {
|
|
||||||
const u64 upload_hit_copies = mirror_upload_hit_copies - mirror_upload_hit_copies_last;
|
|
||||||
const u64 upload_miss_copies = mirror_upload_miss_copies - mirror_upload_miss_copies_last;
|
|
||||||
const u64 upload_hit_bytes = mirror_upload_hit_bytes - mirror_upload_hit_bytes_last;
|
|
||||||
const u64 upload_miss_bytes = mirror_upload_miss_bytes - mirror_upload_miss_bytes_last;
|
|
||||||
const u64 download_hit_copies =
|
|
||||||
mirror_download_hit_copies - mirror_download_hit_copies_last;
|
|
||||||
const u64 download_miss_copies =
|
|
||||||
mirror_download_miss_copies - mirror_download_miss_copies_last;
|
|
||||||
const u64 download_hit_bytes = mirror_download_hit_bytes - mirror_download_hit_bytes_last;
|
|
||||||
const u64 download_miss_bytes =
|
|
||||||
mirror_download_miss_bytes - mirror_download_miss_bytes_last;
|
|
||||||
|
|
||||||
const u64 upload_total_copies = upload_hit_copies + upload_miss_copies;
|
|
||||||
const u64 download_total_copies = download_hit_copies + download_miss_copies;
|
|
||||||
if (upload_total_copies > 0 || download_total_copies > 0) {
|
|
||||||
const double upload_hit_ratio = upload_total_copies > 0
|
|
||||||
? (100.0 * static_cast<double>(upload_hit_copies) /
|
|
||||||
static_cast<double>(upload_total_copies))
|
|
||||||
: 0.0;
|
|
||||||
const double download_hit_ratio =
|
|
||||||
download_total_copies > 0
|
|
||||||
? (100.0 * static_cast<double>(download_hit_copies) /
|
|
||||||
static_cast<double>(download_total_copies))
|
|
||||||
: 0.0;
|
|
||||||
LOG_INFO(HW_GPU,
|
|
||||||
"Buffer mirror counters (last {} frames): upload hit/miss copies = {}/{}, "
|
|
||||||
"hit ratio = {:.2f}%, bytes hit/miss = {}/{}, download hit/miss copies = "
|
|
||||||
"{}/{}, hit ratio = {:.2f}%, bytes hit/miss = {}/{}",
|
|
||||||
mirror_stats_log_interval, upload_hit_copies, upload_miss_copies,
|
|
||||||
upload_hit_ratio, upload_hit_bytes, upload_miss_bytes, download_hit_copies,
|
|
||||||
download_miss_copies, download_hit_ratio, download_hit_bytes,
|
|
||||||
download_miss_bytes);
|
|
||||||
}
|
|
||||||
|
|
||||||
mirror_upload_hit_copies_last = mirror_upload_hit_copies;
|
|
||||||
mirror_upload_miss_copies_last = mirror_upload_miss_copies;
|
|
||||||
mirror_upload_hit_bytes_last = mirror_upload_hit_bytes;
|
|
||||||
mirror_upload_miss_bytes_last = mirror_upload_miss_bytes;
|
|
||||||
mirror_download_hit_copies_last = mirror_download_hit_copies;
|
|
||||||
mirror_download_miss_copies_last = mirror_download_miss_copies;
|
|
||||||
mirror_download_hit_bytes_last = mirror_download_hit_bytes;
|
|
||||||
mirror_download_miss_bytes_last = mirror_download_miss_bytes;
|
|
||||||
}
|
|
||||||
delayed_destruction_ring.Tick();
|
delayed_destruction_ring.Tick();
|
||||||
|
|
||||||
for (auto& buffer : async_buffers_death_ring) {
|
for (auto& buffer : async_buffers_death_ring) {
|
||||||
@@ -1609,21 +1564,6 @@ BufferId BufferCache<P>::CreateBuffer(DAddr device_addr, u32 wanted_size) {
|
|||||||
const u32 size = static_cast<u32>(overlap.end - overlap.begin);
|
const u32 size = static_cast<u32>(overlap.end - overlap.begin);
|
||||||
const BufferId new_buffer_id = slot_buffers.insert(runtime, overlap.begin, size);
|
const BufferId new_buffer_id = slot_buffers.insert(runtime, overlap.begin, size);
|
||||||
auto& new_buffer = slot_buffers[new_buffer_id];
|
auto& new_buffer = slot_buffers[new_buffer_id];
|
||||||
const u64 current_mapping_version = device_memory.GetMappingVersion();
|
|
||||||
if (mirror_mapping_version != current_mapping_version) {
|
|
||||||
buffer_mirrors.clear();
|
|
||||||
mirror_mapping_version = current_mapping_version;
|
|
||||||
}
|
|
||||||
buffer_mirrors.erase(new_buffer.CpuAddr());
|
|
||||||
if (auto mirror =
|
|
||||||
device_memory.CreateMirrorMapping(new_buffer.CpuAddr(), new_buffer.SizeBytes());
|
|
||||||
mirror) {
|
|
||||||
buffer_mirrors.emplace(new_buffer.CpuAddr(), std::move(mirror));
|
|
||||||
if (!mirror_creation_logged) [[unlikely]] {
|
|
||||||
LOG_INFO(HW_GPU, "Buffer mirror mapping enabled (first successful mapping)");
|
|
||||||
mirror_creation_logged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const size_t size_bytes = new_buffer.SizeBytes();
|
const size_t size_bytes = new_buffer.SizeBytes();
|
||||||
runtime.ClearBuffer(new_buffer, 0, size_bytes, 0);
|
runtime.ClearBuffer(new_buffer, 0, size_bytes, 0);
|
||||||
new_buffer.MarkUsage(0, size_bytes);
|
new_buffer.MarkUsage(0, size_bytes);
|
||||||
@@ -1717,52 +1657,15 @@ void BufferCache<P>::ImmediateUploadMemory([[maybe_unused]] Buffer& buffer,
|
|||||||
[[maybe_unused]] std::span<const BufferCopy> copies) {
|
[[maybe_unused]] std::span<const BufferCopy> copies) {
|
||||||
if constexpr (!USE_MEMORY_MAPS_FOR_UPLOADS) {
|
if constexpr (!USE_MEMORY_MAPS_FOR_UPLOADS) {
|
||||||
std::span<u8> immediate_buffer;
|
std::span<u8> immediate_buffer;
|
||||||
const auto resolve_mirror_pointer = [&]() -> const u8* {
|
|
||||||
const u64 current_mapping_version = device_memory.GetMappingVersion();
|
|
||||||
if (mirror_mapping_version != current_mapping_version) {
|
|
||||||
buffer_mirrors.clear();
|
|
||||||
mirror_mapping_version = current_mapping_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto mirror_it = buffer_mirrors.find(buffer.CpuAddr());
|
|
||||||
if (mirror_it == buffer_mirrors.end()) {
|
|
||||||
if (auto mirror =
|
|
||||||
device_memory.CreateMirrorMapping(buffer.CpuAddr(), buffer.SizeBytes());
|
|
||||||
mirror) {
|
|
||||||
auto [it, inserted] =
|
|
||||||
buffer_mirrors.emplace(buffer.CpuAddr(), std::move(mirror));
|
|
||||||
mirror_it = it;
|
|
||||||
if (inserted && !mirror_creation_logged) [[unlikely]] {
|
|
||||||
LOG_INFO(HW_GPU, "Buffer mirror mapping enabled (first successful mapping)");
|
|
||||||
mirror_creation_logged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mirror_it != buffer_mirrors.end() ? mirror_it->second.Data() : nullptr;
|
|
||||||
};
|
|
||||||
const u8* const mirror_pointer = resolve_mirror_pointer();
|
|
||||||
for (const BufferCopy& copy : copies) {
|
for (const BufferCopy& copy : copies) {
|
||||||
std::span<const u8> upload_span;
|
std::span<const u8> upload_span;
|
||||||
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
|
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
|
||||||
if (mirror_pointer != nullptr) {
|
if (IsRangeGranular(device_addr, copy.size)) {
|
||||||
mirror_upload_hit_copies++;
|
|
||||||
mirror_upload_hit_bytes += copy.size;
|
|
||||||
if (!mirror_upload_logged) [[unlikely]] {
|
|
||||||
LOG_INFO(HW_GPU, "Buffer mirror fast path active for upload sync");
|
|
||||||
mirror_upload_logged = true;
|
|
||||||
}
|
|
||||||
upload_span =
|
|
||||||
std::span(mirror_pointer + static_cast<size_t>(copy.dst_offset), copy.size);
|
|
||||||
} else if (IsRangeGranular(device_addr, copy.size)) {
|
|
||||||
mirror_upload_miss_copies++;
|
|
||||||
mirror_upload_miss_bytes += copy.size;
|
|
||||||
auto* const ptr = device_memory.GetPointer<u8>(device_addr);
|
auto* const ptr = device_memory.GetPointer<u8>(device_addr);
|
||||||
if (ptr != nullptr) {
|
if (ptr != nullptr) {
|
||||||
upload_span = std::span(ptr, copy.size);
|
upload_span = std::span(ptr, copy.size);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
mirror_upload_miss_copies++;
|
|
||||||
mirror_upload_miss_bytes += copy.size;
|
|
||||||
if (immediate_buffer.empty()) {
|
if (immediate_buffer.empty()) {
|
||||||
immediate_buffer = ImmediateBuffer(largest_copy);
|
immediate_buffer = ImmediateBuffer(largest_copy);
|
||||||
}
|
}
|
||||||
@@ -1781,47 +1684,10 @@ void BufferCache<P>::MappedUploadMemory([[maybe_unused]] Buffer& buffer,
|
|||||||
if constexpr (USE_MEMORY_MAPS) {
|
if constexpr (USE_MEMORY_MAPS) {
|
||||||
auto upload_staging = runtime.UploadStagingBuffer(total_size_bytes);
|
auto upload_staging = runtime.UploadStagingBuffer(total_size_bytes);
|
||||||
const std::span<u8> staging_pointer = upload_staging.mapped_span;
|
const std::span<u8> staging_pointer = upload_staging.mapped_span;
|
||||||
const auto resolve_mirror_pointer = [&]() -> const u8* {
|
|
||||||
const u64 current_mapping_version = device_memory.GetMappingVersion();
|
|
||||||
if (mirror_mapping_version != current_mapping_version) {
|
|
||||||
buffer_mirrors.clear();
|
|
||||||
mirror_mapping_version = current_mapping_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto mirror_it = buffer_mirrors.find(buffer.CpuAddr());
|
|
||||||
if (mirror_it == buffer_mirrors.end()) {
|
|
||||||
if (auto mirror =
|
|
||||||
device_memory.CreateMirrorMapping(buffer.CpuAddr(), buffer.SizeBytes());
|
|
||||||
mirror) {
|
|
||||||
auto [it, inserted] =
|
|
||||||
buffer_mirrors.emplace(buffer.CpuAddr(), std::move(mirror));
|
|
||||||
mirror_it = it;
|
|
||||||
if (inserted && !mirror_creation_logged) [[unlikely]] {
|
|
||||||
LOG_INFO(HW_GPU, "Buffer mirror mapping enabled (first successful mapping)");
|
|
||||||
mirror_creation_logged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mirror_it != buffer_mirrors.end() ? mirror_it->second.Data() : nullptr;
|
|
||||||
};
|
|
||||||
const u8* const mirror_pointer = resolve_mirror_pointer();
|
|
||||||
for (BufferCopy& copy : copies) {
|
for (BufferCopy& copy : copies) {
|
||||||
u8* const src_pointer = staging_pointer.data() + copy.src_offset;
|
u8* const src_pointer = staging_pointer.data() + copy.src_offset;
|
||||||
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
|
const DAddr device_addr = buffer.CpuAddr() + copy.dst_offset;
|
||||||
if (mirror_pointer != nullptr) {
|
device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size);
|
||||||
mirror_upload_hit_copies++;
|
|
||||||
mirror_upload_hit_bytes += copy.size;
|
|
||||||
if (!mirror_upload_logged) [[unlikely]] {
|
|
||||||
LOG_INFO(HW_GPU, "Buffer mirror fast path active for upload sync");
|
|
||||||
mirror_upload_logged = true;
|
|
||||||
}
|
|
||||||
std::memcpy(src_pointer, mirror_pointer + static_cast<size_t>(copy.dst_offset),
|
|
||||||
copy.size);
|
|
||||||
} else {
|
|
||||||
mirror_upload_miss_copies++;
|
|
||||||
mirror_upload_miss_bytes += copy.size;
|
|
||||||
device_memory.ReadBlockUnsafe(device_addr, src_pointer, copy.size);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Apply the staging offset
|
// Apply the staging offset
|
||||||
copy.src_offset += upload_staging.offset;
|
copy.src_offset += upload_staging.offset;
|
||||||
@@ -1914,30 +1780,6 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, DAddr device_addr, u64
|
|||||||
if constexpr (USE_MEMORY_MAPS) {
|
if constexpr (USE_MEMORY_MAPS) {
|
||||||
auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
|
auto download_staging = runtime.DownloadStagingBuffer(total_size_bytes);
|
||||||
const u8* const mapped_memory = download_staging.mapped_span.data();
|
const u8* const mapped_memory = download_staging.mapped_span.data();
|
||||||
const auto resolve_mirror_pointer = [&]() -> u8* {
|
|
||||||
const u64 current_mapping_version = device_memory.GetMappingVersion();
|
|
||||||
if (mirror_mapping_version != current_mapping_version) {
|
|
||||||
buffer_mirrors.clear();
|
|
||||||
mirror_mapping_version = current_mapping_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto mirror_it = buffer_mirrors.find(buffer.CpuAddr());
|
|
||||||
if (mirror_it == buffer_mirrors.end()) {
|
|
||||||
if (auto mirror =
|
|
||||||
device_memory.CreateMirrorMapping(buffer.CpuAddr(), buffer.SizeBytes());
|
|
||||||
mirror) {
|
|
||||||
auto [it, inserted] =
|
|
||||||
buffer_mirrors.emplace(buffer.CpuAddr(), std::move(mirror));
|
|
||||||
mirror_it = it;
|
|
||||||
if (inserted && !mirror_creation_logged) [[unlikely]] {
|
|
||||||
LOG_INFO(HW_GPU, "Buffer mirror mapping enabled (first successful mapping)");
|
|
||||||
mirror_creation_logged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mirror_it != buffer_mirrors.end() ? mirror_it->second.Data() : nullptr;
|
|
||||||
};
|
|
||||||
u8* const mirror_pointer = resolve_mirror_pointer();
|
|
||||||
const std::span<BufferCopy> copies_span(copies.data(), copies.data() + copies.size());
|
const std::span<BufferCopy> copies_span(copies.data(), copies.data() + copies.size());
|
||||||
for (BufferCopy& copy : copies) {
|
for (BufferCopy& copy : copies) {
|
||||||
// Modify copies to have the staging offset in mind
|
// Modify copies to have the staging offset in mind
|
||||||
@@ -1951,65 +1793,14 @@ void BufferCache<P>::DownloadBufferMemory(Buffer& buffer, DAddr device_addr, u64
|
|||||||
// Undo the modified offset
|
// Undo the modified offset
|
||||||
const u64 dst_offset = copy.dst_offset - download_staging.offset;
|
const u64 dst_offset = copy.dst_offset - download_staging.offset;
|
||||||
const u8* copy_mapped_memory = mapped_memory + dst_offset;
|
const u8* copy_mapped_memory = mapped_memory + dst_offset;
|
||||||
if (mirror_pointer != nullptr) {
|
device_memory.WriteBlockUnsafe(copy_device_addr, copy_mapped_memory, copy.size);
|
||||||
mirror_download_hit_copies++;
|
|
||||||
mirror_download_hit_bytes += copy.size;
|
|
||||||
if (!mirror_download_logged) [[unlikely]] {
|
|
||||||
LOG_INFO(HW_GPU, "Buffer mirror fast path active for download sync");
|
|
||||||
mirror_download_logged = true;
|
|
||||||
}
|
|
||||||
std::memcpy(mirror_pointer + static_cast<size_t>(copy.src_offset),
|
|
||||||
copy_mapped_memory, copy.size);
|
|
||||||
} else {
|
|
||||||
mirror_download_miss_copies++;
|
|
||||||
mirror_download_miss_bytes += copy.size;
|
|
||||||
device_memory.WriteBlockUnsafe(copy_device_addr, copy_mapped_memory, copy.size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy);
|
const std::span<u8> immediate_buffer = ImmediateBuffer(largest_copy);
|
||||||
const auto resolve_mirror_pointer = [&]() -> u8* {
|
|
||||||
const u64 current_mapping_version = device_memory.GetMappingVersion();
|
|
||||||
if (mirror_mapping_version != current_mapping_version) {
|
|
||||||
buffer_mirrors.clear();
|
|
||||||
mirror_mapping_version = current_mapping_version;
|
|
||||||
}
|
|
||||||
|
|
||||||
auto mirror_it = buffer_mirrors.find(buffer.CpuAddr());
|
|
||||||
if (mirror_it == buffer_mirrors.end()) {
|
|
||||||
if (auto mirror =
|
|
||||||
device_memory.CreateMirrorMapping(buffer.CpuAddr(), buffer.SizeBytes());
|
|
||||||
mirror) {
|
|
||||||
auto [it, inserted] =
|
|
||||||
buffer_mirrors.emplace(buffer.CpuAddr(), std::move(mirror));
|
|
||||||
mirror_it = it;
|
|
||||||
if (inserted && !mirror_creation_logged) [[unlikely]] {
|
|
||||||
LOG_INFO(HW_GPU, "Buffer mirror mapping enabled (first successful mapping)");
|
|
||||||
mirror_creation_logged = true;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return mirror_it != buffer_mirrors.end() ? mirror_it->second.Data() : nullptr;
|
|
||||||
};
|
|
||||||
u8* const mirror_pointer = resolve_mirror_pointer();
|
|
||||||
for (const BufferCopy& copy : copies) {
|
for (const BufferCopy& copy : copies) {
|
||||||
buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size));
|
buffer.ImmediateDownload(copy.src_offset, immediate_buffer.subspan(0, copy.size));
|
||||||
const DAddr copy_device_addr = buffer.CpuAddr() + copy.src_offset;
|
const DAddr copy_device_addr = buffer.CpuAddr() + copy.src_offset;
|
||||||
if (mirror_pointer != nullptr) {
|
device_memory.WriteBlockUnsafe(copy_device_addr, immediate_buffer.data(), copy.size);
|
||||||
mirror_download_hit_copies++;
|
|
||||||
mirror_download_hit_bytes += copy.size;
|
|
||||||
if (!mirror_download_logged) [[unlikely]] {
|
|
||||||
LOG_INFO(HW_GPU, "Buffer mirror fast path active for download sync");
|
|
||||||
mirror_download_logged = true;
|
|
||||||
}
|
|
||||||
std::memcpy(mirror_pointer + static_cast<size_t>(copy.src_offset),
|
|
||||||
immediate_buffer.data(), copy.size);
|
|
||||||
} else {
|
|
||||||
mirror_download_miss_copies++;
|
|
||||||
mirror_download_miss_bytes += copy.size;
|
|
||||||
device_memory.WriteBlockUnsafe(copy_device_addr, immediate_buffer.data(),
|
|
||||||
copy.size);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -2050,10 +1841,6 @@ void BufferCache<P>::DeleteBuffer(BufferId buffer_id, bool do_not_mark) {
|
|||||||
if (!do_not_mark) {
|
if (!do_not_mark) {
|
||||||
Buffer& buffer = slot_buffers[buffer_id];
|
Buffer& buffer = slot_buffers[buffer_id];
|
||||||
memory_tracker.MarkRegionAsCpuModified(buffer.CpuAddr(), buffer.SizeBytes());
|
memory_tracker.MarkRegionAsCpuModified(buffer.CpuAddr(), buffer.SizeBytes());
|
||||||
buffer_mirrors.erase(buffer.CpuAddr());
|
|
||||||
} else {
|
|
||||||
const Buffer& buffer = slot_buffers[buffer_id];
|
|
||||||
buffer_mirrors.erase(buffer.CpuAddr());
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Unregister(buffer_id);
|
Unregister(buffer_id);
|
||||||
|
|||||||
@@ -473,8 +473,6 @@ private:
|
|||||||
Tegra::MaxwellDeviceMemoryManager& device_memory;
|
Tegra::MaxwellDeviceMemoryManager& device_memory;
|
||||||
|
|
||||||
Common::SlotVector<Buffer> slot_buffers;
|
Common::SlotVector<Buffer> slot_buffers;
|
||||||
ankerl::unordered_dense::map<DAddr, Tegra::MaxwellDeviceMemoryManager::MirrorMapping>
|
|
||||||
buffer_mirrors;
|
|
||||||
#ifdef YUZU_LEGACY
|
#ifdef YUZU_LEGACY
|
||||||
static constexpr size_t TICKS_TO_DESTROY = 6;
|
static constexpr size_t TICKS_TO_DESTROY = 6;
|
||||||
#else
|
#else
|
||||||
@@ -524,26 +522,6 @@ private:
|
|||||||
|
|
||||||
std::array<BufferId, ((1ULL << 34) >> CACHING_PAGEBITS)> page_table;
|
std::array<BufferId, ((1ULL << 34) >> CACHING_PAGEBITS)> page_table;
|
||||||
Common::ScratchBuffer<u8> tmp_buffer;
|
Common::ScratchBuffer<u8> tmp_buffer;
|
||||||
bool mirror_creation_logged = false;
|
|
||||||
bool mirror_upload_logged = false;
|
|
||||||
bool mirror_download_logged = false;
|
|
||||||
u64 mirror_mapping_version = 0;
|
|
||||||
u64 mirror_upload_hit_copies = 0;
|
|
||||||
u64 mirror_upload_miss_copies = 0;
|
|
||||||
u64 mirror_upload_hit_bytes = 0;
|
|
||||||
u64 mirror_upload_miss_bytes = 0;
|
|
||||||
u64 mirror_download_hit_copies = 0;
|
|
||||||
u64 mirror_download_miss_copies = 0;
|
|
||||||
u64 mirror_download_hit_bytes = 0;
|
|
||||||
u64 mirror_download_miss_bytes = 0;
|
|
||||||
u64 mirror_upload_hit_copies_last = 0;
|
|
||||||
u64 mirror_upload_miss_copies_last = 0;
|
|
||||||
u64 mirror_upload_hit_bytes_last = 0;
|
|
||||||
u64 mirror_upload_miss_bytes_last = 0;
|
|
||||||
u64 mirror_download_hit_copies_last = 0;
|
|
||||||
u64 mirror_download_miss_copies_last = 0;
|
|
||||||
u64 mirror_download_hit_bytes_last = 0;
|
|
||||||
u64 mirror_download_miss_bytes_last = 0;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
|||||||
@@ -5,6 +5,8 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#undef PIXEL_FORMAT_LIST
|
||||||
|
|
||||||
#include <climits>
|
#include <climits>
|
||||||
#include <utility>
|
#include <utility>
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
@@ -128,7 +130,7 @@ namespace VideoCore::Surface {
|
|||||||
PIXEL_FORMAT_ELEM(S8_UINT_D24_UNORM, 1, 1, 32) \
|
PIXEL_FORMAT_ELEM(S8_UINT_D24_UNORM, 1, 1, 32) \
|
||||||
PIXEL_FORMAT_ELEM(D32_FLOAT_S8_UINT, 1, 1, 64)
|
PIXEL_FORMAT_ELEM(D32_FLOAT_S8_UINT, 1, 1, 64)
|
||||||
|
|
||||||
enum class PixelFormat {
|
enum class PixelFormat : u32 {
|
||||||
#define PIXEL_FORMAT_ELEM(name, ...) name,
|
#define PIXEL_FORMAT_ELEM(name, ...) name,
|
||||||
PIXEL_FORMAT_LIST
|
PIXEL_FORMAT_LIST
|
||||||
#undef PIXEL_FORMAT_ELEM
|
#undef PIXEL_FORMAT_ELEM
|
||||||
@@ -192,6 +194,13 @@ constexpr u32 BytesPerBlock(PixelFormat pixel_format) {
|
|||||||
return BitsPerBlock(pixel_format) / CHAR_BIT;
|
return BitsPerBlock(pixel_format) / CHAR_BIT;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#include "video_core/gpu.h"
|
||||||
|
#include "video_core/textures/texture.h"
|
||||||
|
|
||||||
|
namespace VideoCore::Surface {
|
||||||
|
|
||||||
SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type);
|
SurfaceTarget SurfaceTargetFromTextureType(Tegra::Texture::TextureType texture_type);
|
||||||
bool SurfaceTargetIsLayered(SurfaceTarget target);
|
bool SurfaceTargetIsLayered(SurfaceTarget target);
|
||||||
bool SurfaceTargetIsArray(SurfaceTarget target);
|
bool SurfaceTargetIsArray(SurfaceTarget target);
|
||||||
|
|||||||
@@ -3,6 +3,7 @@
|
|||||||
|
|
||||||
// Qt on macOS doesn't define VMA shit
|
// Qt on macOS doesn't define VMA shit
|
||||||
#include <boost/algorithm/string/split.hpp>
|
#include <boost/algorithm/string/split.hpp>
|
||||||
|
#include "common/fs/path_util.h"
|
||||||
#include "common/settings.h"
|
#include "common/settings.h"
|
||||||
#include "common/settings_enums.h"
|
#include "common/settings_enums.h"
|
||||||
#include "frontend_common/settings_generator.h"
|
#include "frontend_common/settings_generator.h"
|
||||||
@@ -635,6 +636,7 @@ MainWindow::MainWindow(bool has_broken_vulkan)
|
|||||||
|
|
||||||
QString game_path;
|
QString game_path;
|
||||||
bool should_launch_qlaunch = false;
|
bool should_launch_qlaunch = false;
|
||||||
|
bool should_launch_hlaunch = false;
|
||||||
bool should_launch_setup = false;
|
bool should_launch_setup = false;
|
||||||
bool has_gamepath = false;
|
bool has_gamepath = false;
|
||||||
bool is_fullscreen = false;
|
bool is_fullscreen = false;
|
||||||
@@ -676,6 +678,8 @@ MainWindow::MainWindow(bool has_broken_vulkan)
|
|||||||
players[0].profile_name = args[++i].toStdString();
|
players[0].profile_name = args[++i].toStdString();
|
||||||
} else if (args[i] == QStringLiteral("-qlaunch")) {
|
} else if (args[i] == QStringLiteral("-qlaunch")) {
|
||||||
should_launch_qlaunch = true;
|
should_launch_qlaunch = true;
|
||||||
|
} else if (args[i] == QStringLiteral("-hlaunch")) {
|
||||||
|
should_launch_hlaunch = true;
|
||||||
} else if (args[i] == QStringLiteral("-setup")) {
|
} else if (args[i] == QStringLiteral("-setup")) {
|
||||||
should_launch_setup = true;
|
should_launch_setup = true;
|
||||||
} else {
|
} else {
|
||||||
@@ -694,10 +698,12 @@ MainWindow::MainWindow(bool has_broken_vulkan)
|
|||||||
} else {
|
} else {
|
||||||
if (!game_path.isEmpty()) {
|
if (!game_path.isEmpty()) {
|
||||||
BootGame(game_path, ApplicationAppletParameters());
|
BootGame(game_path, ApplicationAppletParameters());
|
||||||
} else {
|
} else if (should_launch_qlaunch) {
|
||||||
if (should_launch_qlaunch) {
|
LaunchFirmwareApplet(u64(Service::AM::AppletProgramId::QLaunch), std::nullopt);
|
||||||
LaunchFirmwareApplet(u64(Service::AM::AppletProgramId::QLaunch), std::nullopt);
|
} else if (should_launch_hlaunch) {
|
||||||
}
|
std::filesystem::path const sd_dir = Common::FS::GetEdenPathString(Common::FS::EdenPath::SDMCDir);
|
||||||
|
auto const hbl_path = (sd_dir / "atmosphere" / "hbl.nsp").string();
|
||||||
|
BootGame(QString::fromStdString(hbl_path), ApplicationAppletParameters());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user