mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-21 03:16:54 +02:00
graphics: copy sparse buffer uploads through resident mappings
This commit is contained in:
@@ -962,7 +962,11 @@ static bool IsInPrtAperture(uint64_t address, uint64_t size = 1) {
|
||||
}
|
||||
|
||||
bool TryReadSparseBacking(uint64_t vaddr, void* data, uint64_t size) {
|
||||
return g_guest_address_space->TryReadSparseBacking(vaddr, data, size);
|
||||
return g_guest_address_space->CopySparseMemory<false>(vaddr, data, size);
|
||||
}
|
||||
|
||||
bool CopySparseMemory(uint64_t vaddr, void* data, uint64_t size) {
|
||||
return g_guest_address_space->CopySparseMemory<true>(vaddr, data, size);
|
||||
}
|
||||
|
||||
static bool SelfTestSub64SharedPlaceholderAlias() {
|
||||
|
||||
@@ -116,6 +116,7 @@ bool TryWriteBacking(uint64_t vaddr, const void* data, uint64_
|
||||
bool TryReadBacking(uint64_t vaddr, void* data, uint64_t size);
|
||||
bool TryReadBufferBacking(uint64_t vaddr, void* data, uint64_t size);
|
||||
bool TryReadSparseBacking(uint64_t vaddr, void* data, uint64_t size);
|
||||
bool CopySparseMemory(uint64_t vaddr, void* data, uint64_t size);
|
||||
[[nodiscard]] uint64_t ClampRangeSize(uint64_t vaddr, uint64_t size);
|
||||
void WriteBacking(uint64_t vaddr, const void* data, uint64_t size) noexcept;
|
||||
void InvalidateMemory(uint64_t vaddr, uint64_t size);
|
||||
|
||||
@@ -28,6 +28,35 @@ static bool CoalescePlaceholders(uint64_t vaddr, uint64_t size) {
|
||||
}
|
||||
#endif
|
||||
|
||||
template <typename Regions, typename Source, typename Gap>
|
||||
static void CopySparseRange(const Regions& regions, uint64_t vaddr, void* data, uint64_t size,
|
||||
Source&& source, Gap&& gap) {
|
||||
const auto end = vaddr + size;
|
||||
auto mapping = regions.lower_bound(vaddr);
|
||||
if (mapping != regions.begin()) {
|
||||
auto previous = std::prev(mapping);
|
||||
if (previous->second.vaddr + previous->second.size > vaddr) {
|
||||
mapping = previous;
|
||||
}
|
||||
}
|
||||
|
||||
auto* destination = static_cast<uint8_t*>(data);
|
||||
auto cursor = vaddr;
|
||||
for (; mapping != regions.end() && mapping->second.vaddr < end; ++mapping) {
|
||||
const auto& entry = mapping->second;
|
||||
const auto start = std::max(vaddr, entry.vaddr);
|
||||
const auto bytes = std::min(end, entry.vaddr + entry.size) - start;
|
||||
if (cursor < start) {
|
||||
gap(cursor, destination + (cursor - vaddr), start - cursor);
|
||||
}
|
||||
std::memcpy(destination + (start - vaddr), source(entry, start), bytes);
|
||||
cursor = start + bytes;
|
||||
}
|
||||
if (cursor < end) {
|
||||
gap(cursor, destination + (cursor - vaddr), end - cursor);
|
||||
}
|
||||
}
|
||||
|
||||
class GuestBackingStore {
|
||||
public:
|
||||
enum class FailureReason {
|
||||
@@ -247,7 +276,8 @@ public:
|
||||
return true;
|
||||
}
|
||||
|
||||
bool TryReadSparseBacking(uint64_t vaddr, void* data, uint64_t size) {
|
||||
template <typename Gap>
|
||||
bool TryReadSparseBacking(uint64_t vaddr, void* data, uint64_t size, Gap&& gap) {
|
||||
if (!IsAvailable() || data == nullptr || size == 0 || UINT64_MAX - vaddr < size) {
|
||||
return false;
|
||||
}
|
||||
@@ -258,31 +288,11 @@ public:
|
||||
g_test_backing_read(vaddr, size);
|
||||
}
|
||||
#endif
|
||||
const auto end = vaddr + size;
|
||||
auto mapping = m_maps.lower_bound(vaddr);
|
||||
if (mapping != m_maps.begin()) {
|
||||
auto previous = std::prev(mapping);
|
||||
if (previous->second.vaddr + previous->second.size > vaddr) {
|
||||
mapping = previous;
|
||||
}
|
||||
}
|
||||
|
||||
auto* destination = static_cast<uint8_t*>(data);
|
||||
auto cursor = vaddr;
|
||||
for (; mapping != m_maps.end() && mapping->second.vaddr < end; ++mapping) {
|
||||
const auto& entry = mapping->second;
|
||||
const auto start = std::max(vaddr, entry.vaddr);
|
||||
const auto bytes = std::min(end, entry.vaddr + entry.size) - start;
|
||||
const auto offset = entry.backing_offset + start - entry.vaddr;
|
||||
if (cursor < start) {
|
||||
std::memset(destination + (cursor - vaddr), 0, start - cursor);
|
||||
}
|
||||
std::memcpy(destination + (start - vaddr), m_backing_base + offset, bytes);
|
||||
cursor = start + bytes;
|
||||
}
|
||||
if (cursor < end) {
|
||||
std::memset(destination + (cursor - vaddr), 0, end - cursor);
|
||||
}
|
||||
CopySparseRange(m_maps, vaddr, data, size,
|
||||
[this](const auto& entry, uint64_t start) {
|
||||
return m_backing_base + (entry.backing_offset + start - entry.vaddr);
|
||||
},
|
||||
gap);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -773,22 +783,41 @@ public:
|
||||
return m_backing->TryReadBacking(vaddr, data, size);
|
||||
}
|
||||
|
||||
bool TryReadSparseBacking(uint64_t vaddr, void* data, uint64_t size) {
|
||||
if (!Owns(vaddr, size)) {
|
||||
template <bool copy_private>
|
||||
bool CopySparseMemory(uint64_t vaddr, void* data, uint64_t size) {
|
||||
if (data == nullptr || !Owns(vaddr, size)) {
|
||||
return false;
|
||||
}
|
||||
std::shared_lock lock(m_mutex);
|
||||
auto mapping = m_mapped.upper_bound(vaddr);
|
||||
if (mapping != m_mapped.begin()) {
|
||||
--mapping;
|
||||
}
|
||||
for (; mapping != m_mapped.end() && mapping->second.vaddr < vaddr + size; ++mapping) {
|
||||
const auto& region = mapping->second;
|
||||
if (region.type == MappingType::Private && region.vaddr + region.size > vaddr) {
|
||||
return false;
|
||||
if constexpr (!copy_private) {
|
||||
auto mapping = m_mapped.upper_bound(vaddr);
|
||||
if (mapping != m_mapped.begin()) {
|
||||
--mapping;
|
||||
}
|
||||
for (; mapping != m_mapped.end() && mapping->second.vaddr < vaddr + size; ++mapping) {
|
||||
const auto& region = mapping->second;
|
||||
if (region.type == MappingType::Private && region.vaddr + region.size > vaddr) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
return m_backing->TryReadSparseBacking(vaddr, data, size);
|
||||
return m_backing->TryReadSparseBacking(
|
||||
vaddr, data, size, [&](uint64_t start, uint8_t* destination, uint64_t bytes) {
|
||||
const auto zero = [](uint64_t, uint8_t* output, uint64_t length) {
|
||||
std::memset(output, 0, length);
|
||||
};
|
||||
if constexpr (copy_private) {
|
||||
// Backing gaps can contain private mappings or reservations only.
|
||||
CopySparseRange(m_mapped, start, destination, bytes,
|
||||
[](const auto& region, uint64_t address) {
|
||||
EXIT_IF(region.type != MappingType::Private);
|
||||
return reinterpret_cast<const void*>(address);
|
||||
},
|
||||
zero);
|
||||
} else {
|
||||
zero(start, destination, bytes);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
bool BackingContains(uint64_t vaddr, uint64_t size) { return m_backing->Contains(vaddr, size); }
|
||||
|
||||
Reference in New Issue
Block a user