mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 10:56:58 +02:00
renderer: grow repeatedly joined buffer ranges (perf)
This commit is contained in:
+69
-26
@@ -311,38 +311,81 @@ BufferId BufferCache::FindBuffer(uint64_t vaddr, uint64_t size) {
|
||||
return CreateBuffer(vaddr, size);
|
||||
}
|
||||
|
||||
BufferId BufferCache::CreateBuffer(uint64_t vaddr, uint64_t size) {
|
||||
auto& command = m_scheduler.Current();
|
||||
EXIT_IF(command.IsInvalid());
|
||||
auto begin = vaddr & ~(CACHING_PAGESIZE - 1);
|
||||
auto end = (vaddr + size + CACHING_PAGESIZE - 1) & ~(CACHING_PAGESIZE - 1);
|
||||
auto first = m_buffers.lower_bound(begin);
|
||||
if (first != m_buffers.begin()) {
|
||||
const auto previous = std::prev(first);
|
||||
if (const auto& buffer = m_slot_buffers[previous->second];
|
||||
buffer.CpuAddress() + buffer.Size() > begin) {
|
||||
first = previous;
|
||||
BufferCache::OverlapResult BufferCache::ResolveOverlaps(uint64_t vaddr, uint64_t size) {
|
||||
static constexpr int StreamLeapThreshold = 16;
|
||||
static constexpr uint64_t StreamLeapSize = CACHING_PAGESIZE * 128;
|
||||
|
||||
auto begin = vaddr;
|
||||
auto end = vaddr + size;
|
||||
const auto find_first = [&](uint64_t address) {
|
||||
auto first = m_buffers.lower_bound(address);
|
||||
if (first != m_buffers.begin()) {
|
||||
const auto previous = std::prev(first);
|
||||
const auto& buffer = m_slot_buffers[previous->second];
|
||||
if (buffer.CpuAddress() + buffer.Size() > address) {
|
||||
first = previous;
|
||||
}
|
||||
}
|
||||
return first;
|
||||
};
|
||||
auto first = find_first(begin);
|
||||
auto last = first;
|
||||
int stream_score = 0;
|
||||
bool has_stream_leap = false;
|
||||
for (; last != m_buffers.end() && last->first < end; ++last) {
|
||||
const auto& buffer = m_slot_buffers[last->second];
|
||||
const auto buffer_begin = buffer.CpuAddress();
|
||||
const auto buffer_end = buffer_begin + buffer.Size();
|
||||
const bool expands_left = buffer_begin < begin;
|
||||
const bool expands_right = buffer_end > end;
|
||||
begin = std::min(begin, buffer_begin);
|
||||
end = std::max(end, buffer_end);
|
||||
if (!has_stream_leap && (stream_score += buffer.StreamScore()) > StreamLeapThreshold) {
|
||||
has_stream_leap = true;
|
||||
if (expands_right) {
|
||||
end += std::min(StreamLeapSize, PageTable::kAddressSpaceSize - end);
|
||||
}
|
||||
if (expands_left) {
|
||||
const auto minimum = CACHING_PAGESIZE * 2;
|
||||
if (begin > minimum) {
|
||||
begin -= std::min(StreamLeapSize, begin - minimum);
|
||||
}
|
||||
first = find_first(begin);
|
||||
begin = std::min(begin, first->first);
|
||||
}
|
||||
}
|
||||
}
|
||||
auto last = first;
|
||||
for (; last != m_buffers.end() && last->first < end; ++last) {
|
||||
const auto& buffer = m_slot_buffers[last->second];
|
||||
begin = std::min(begin, buffer.CpuAddress());
|
||||
end = std::max(end, buffer.CpuAddress() + buffer.Size());
|
||||
return {first, last, begin, end, has_stream_leap};
|
||||
}
|
||||
|
||||
void BufferCache::JoinOverlap(BufferId new_id, BufferId overlap_id, bool accumulate_stream_score) {
|
||||
auto& new_buffer = m_slot_buffers[new_id];
|
||||
auto& overlap = m_slot_buffers[overlap_id];
|
||||
if (accumulate_stream_score) {
|
||||
new_buffer.IncreaseStreamScore(overlap.StreamScore() + 1);
|
||||
}
|
||||
new_buffer.CopyFrom(m_scheduler.Current(), overlap, 0,
|
||||
overlap.CpuAddress() - new_buffer.CpuAddress(), overlap.Size());
|
||||
DeleteBuffer(overlap_id);
|
||||
}
|
||||
|
||||
BufferId BufferCache::CreateBuffer(uint64_t vaddr, uint64_t size) {
|
||||
EXIT_IF(m_scheduler.Current().IsInvalid());
|
||||
const auto end = (vaddr + size + CACHING_PAGESIZE - 1) & ~(CACHING_PAGESIZE - 1);
|
||||
vaddr &= ~(CACHING_PAGESIZE - 1);
|
||||
size = end - vaddr;
|
||||
const auto overlap = ResolveOverlaps(vaddr, size);
|
||||
|
||||
const auto id = m_slot_buffers.insert(
|
||||
m_graphics, m_scheduler, MemoryUsage::DeviceLocal, begin,
|
||||
AllFlags | vk::BufferUsageFlagBits::eShaderDeviceAddress, end - begin);
|
||||
auto& buffer = m_slot_buffers[id];
|
||||
m_graphics, m_scheduler, MemoryUsage::DeviceLocal, overlap.begin,
|
||||
AllFlags | vk::BufferUsageFlagBits::eShaderDeviceAddress, overlap.end - overlap.begin);
|
||||
const auto& buffer = m_slot_buffers[id];
|
||||
SetVulkanObjectNameF(m_graphics.device, buffer.Handle(),
|
||||
"Kyty.GameBuffer[guest=0x{:016x} size=0x{:x}]", begin, end - begin);
|
||||
for (auto overlap = first; overlap != last;) {
|
||||
const auto current = overlap++;
|
||||
const auto old_id = current->second;
|
||||
const auto& old = m_slot_buffers[old_id];
|
||||
buffer.CopyFrom(command, old, 0, old.CpuAddress() - begin, old.Size());
|
||||
DeleteBuffer(old_id);
|
||||
"Kyty.GameBuffer[guest=0x{:016x} size=0x{:x}]", overlap.begin,
|
||||
overlap.end - overlap.begin);
|
||||
for (auto it = overlap.first; it != overlap.last;) {
|
||||
const auto old_id = (it++)->second;
|
||||
JoinOverlap(id, old_id, !overlap.has_stream_leap);
|
||||
}
|
||||
Register(id);
|
||||
return id;
|
||||
|
||||
+12
-1
@@ -74,6 +74,15 @@ public:
|
||||
private:
|
||||
friend struct BufferCacheTestAccess;
|
||||
|
||||
using BufferMap = std::map<uint64_t, BufferId>;
|
||||
struct OverlapResult {
|
||||
BufferMap::iterator first;
|
||||
BufferMap::iterator last;
|
||||
uint64_t begin;
|
||||
uint64_t end;
|
||||
bool has_stream_leap;
|
||||
};
|
||||
|
||||
struct DownloadCopy;
|
||||
using PageTable = MultiLevelPageTable<BufferId, CACHING_PAGEBITS, 40, 16>;
|
||||
static_assert(CACHING_PAGESIZE == (uint64_t {1} << PageTable::kPageBits));
|
||||
@@ -84,6 +93,8 @@ private:
|
||||
[[nodiscard]] static std::pair<uint64_t, uint64_t> DownloadEnvelope(const DownloadCopy& copy);
|
||||
void WriteDataBuffer(Buffer& buffer, uint64_t address, const void* source, uint64_t size);
|
||||
void TouchBuffer(const Buffer& buffer);
|
||||
[[nodiscard]] OverlapResult ResolveOverlaps(uint64_t vaddr, uint64_t size);
|
||||
void JoinOverlap(BufferId new_id, BufferId overlap_id, bool accumulate_stream_score);
|
||||
[[nodiscard]] BufferId CreateBuffer(uint64_t vaddr, uint64_t size);
|
||||
void Register(BufferId id);
|
||||
void Unregister(BufferId id);
|
||||
@@ -106,7 +117,7 @@ private:
|
||||
Buffer m_bda_pagetable_buffer;
|
||||
Common::SlotVector<Buffer> m_slot_buffers;
|
||||
Common::LeastRecentlyUsedCache<BufferId, uint64_t> m_lru_cache;
|
||||
std::map<uint64_t, BufferId> m_buffers;
|
||||
BufferMap m_buffers;
|
||||
PageTable m_page_table;
|
||||
RangeSet m_gpu_modified_ranges;
|
||||
MemoryTracker m_memory_tracker;
|
||||
|
||||
+5
-2
@@ -53,6 +53,8 @@ public:
|
||||
return address - m_cpu_address;
|
||||
}
|
||||
[[nodiscard]] bool IsInBounds(uint64_t address, uint64_t size) const noexcept;
|
||||
void IncreaseStreamScore(int score) noexcept { stream_score += score; }
|
||||
[[nodiscard]] int StreamScore() const noexcept { return stream_score; }
|
||||
void Write(uint64_t offset, const void* source, uint64_t size);
|
||||
void Flush(uint64_t offset, uint64_t size);
|
||||
void Invalidate(uint64_t offset, uint64_t size);
|
||||
@@ -68,8 +70,9 @@ public:
|
||||
void Fill(uint64_t offset, uint64_t size, uint32_t value);
|
||||
|
||||
// BufferCache state lives directly on the resource.
|
||||
bool is_deleted = false;
|
||||
size_t lru_id = 0;
|
||||
bool is_deleted = false;
|
||||
int stream_score = 0;
|
||||
size_t lru_id = 0;
|
||||
|
||||
protected:
|
||||
[[nodiscard]] GraphicContext& Graphics() const noexcept { return *m_graphics; }
|
||||
|
||||
Reference in New Issue
Block a user