mirror of
https://github.com/KytyPS5/KytyPS5.git
synced 2026-10-20 02:47:02 +02:00
138 lines
6.5 KiB
C++
138 lines
6.5 KiB
C++
#ifndef EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_BUFFERCACHE_H_
|
|
#define EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_BUFFERCACHE_H_
|
|
|
|
#include "common/abi.h"
|
|
#include "common/common.h"
|
|
#include "common/lruCache.h"
|
|
#include "common/slotVector.h"
|
|
#include "graphics/host_gpu/memoryTracker.h"
|
|
#include "graphics/host_gpu/rangeSet.h"
|
|
#include "graphics/host_gpu/renderer/cache/faultManager.h"
|
|
#include "graphics/host_gpu/renderer/cache/multiLevelPageTable.h"
|
|
#include "graphics/host_gpu/renderer/cache/streamBuffer.h"
|
|
|
|
#include <map>
|
|
#include <span>
|
|
#include <utility>
|
|
#include <vector>
|
|
|
|
namespace Libs::Graphics {
|
|
|
|
struct GraphicContext;
|
|
class CommandScheduler;
|
|
class TextureCache;
|
|
|
|
using BufferId = Common::SlotId;
|
|
inline constexpr BufferId NULL_BUFFER_ID {0};
|
|
|
|
class BufferCache {
|
|
public:
|
|
static constexpr uint32_t CACHING_PAGEBITS = 14;
|
|
static constexpr uint64_t CACHING_PAGESIZE = uint64_t {1} << CACHING_PAGEBITS;
|
|
static constexpr uint64_t CACHING_NUMPAGES = uint64_t {1} << (40 - CACHING_PAGEBITS);
|
|
static constexpr uint64_t BDA_PAGETABLE_SIZE =
|
|
CACHING_NUMPAGES * sizeof(vk::DeviceAddress);
|
|
|
|
BufferCache(GraphicContext& graphics, CommandScheduler& scheduler, PageManager& page_manager,
|
|
TextureCache& texture_cache);
|
|
~BufferCache();
|
|
KYTY_CLASS_NO_COPY(BufferCache);
|
|
|
|
void InvalidateMemory(uint64_t vaddr, uint64_t size);
|
|
void ReadMemory(uint64_t vaddr, uint64_t size, bool is_write = false);
|
|
[[nodiscard]] Buffer& GetBuffer(BufferId id) { return m_slot_buffers[id]; }
|
|
[[nodiscard]] BufferId FindBuffer(uint64_t vaddr, uint64_t size);
|
|
[[nodiscard]] std::pair<Buffer*, uint64_t> ObtainBuffer(uint64_t vaddr, uint64_t size,
|
|
bool is_written,
|
|
bool is_texel_buffer = false,
|
|
BufferId id = {});
|
|
[[nodiscard]] StreamBuffer& GetUtilityBuffer(MemoryUsage usage) noexcept {
|
|
switch (usage) {
|
|
case MemoryUsage::Upload: return m_staging_buffer;
|
|
case MemoryUsage::Stream: return m_stream_buffer;
|
|
case MemoryUsage::Download: return m_download_buffer;
|
|
case MemoryUsage::DeviceLocal: return m_device_buffer;
|
|
}
|
|
EXIT("BufferCache: invalid utility-buffer usage\n");
|
|
}
|
|
[[nodiscard]] const Buffer* GetGdsBuffer() const noexcept { return &m_gds_buffer; }
|
|
[[nodiscard]] Buffer* GetBdaPageTableBuffer() noexcept { return &m_bda_pagetable_buffer; }
|
|
[[nodiscard]] Buffer* GetFaultBuffer() noexcept { return m_fault_manager.GetFaultBuffer(); }
|
|
[[nodiscard]] std::pair<Buffer*, uint64_t> ObtainBufferForImage(uint64_t vaddr, uint64_t size);
|
|
void FillBuffer(uint64_t vaddr, uint64_t size, uint32_t value, bool is_gds);
|
|
void CopyBuffer(uint64_t dst_vaddr, uint64_t src_vaddr, uint64_t size, bool dst_gds,
|
|
bool src_gds);
|
|
// Cache-index and exact dirty-range queries require GPU-thread serialization.
|
|
[[nodiscard]] bool IsRegionRegistered(uint64_t vaddr, uint64_t size);
|
|
[[nodiscard]] bool HasGpuDirtyBytes(uint64_t vaddr, uint64_t size);
|
|
[[nodiscard]] bool IsRegionCpuModified(uint64_t vaddr, uint64_t size);
|
|
[[nodiscard]] bool IsRegionGpuModified(uint64_t vaddr, uint64_t size);
|
|
void ProcessFaultBuffer();
|
|
void SynchronizeBuffersInRange(uint64_t vaddr, uint64_t size);
|
|
void RunGarbageCollector();
|
|
|
|
private:
|
|
friend struct BufferCacheTestAccess;
|
|
|
|
bool IsBufferInvalid(BufferId id) const {
|
|
const auto* buffer = m_slot_buffers.try_get(id);
|
|
return buffer == nullptr || buffer->is_deleted;
|
|
}
|
|
|
|
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));
|
|
static constexpr uint64_t DOWNLOAD_ALIGNMENT = 64;
|
|
[[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);
|
|
template <bool insert>
|
|
void ChangeRegister(BufferId id);
|
|
void DeleteBuffer(BufferId id);
|
|
[[nodiscard]] bool SynchronizeBuffer(Buffer& buffer, uint64_t vaddr, uint64_t size,
|
|
bool is_written, bool is_texel_buffer);
|
|
[[nodiscard]] vk::Buffer UploadCopies(Buffer& buffer, std::span<vk::BufferCopy> copies,
|
|
uint64_t total_size);
|
|
[[nodiscard]] bool SynchronizeBufferFromImage(Buffer& buffer, uint64_t vaddr, uint64_t size);
|
|
void DownloadBufferMemory(std::span<const DownloadCopy> copies);
|
|
|
|
GraphicContext& m_graphics;
|
|
CommandScheduler& m_scheduler;
|
|
FaultManager m_fault_manager;
|
|
Buffer m_gds_buffer;
|
|
Buffer m_bda_pagetable_buffer;
|
|
Common::SlotVector<Buffer> m_slot_buffers;
|
|
Common::LeastRecentlyUsedCache<BufferId, uint64_t> m_lru_cache;
|
|
BufferMap m_buffers;
|
|
PageTable m_page_table;
|
|
RangeSet m_gpu_modified_ranges;
|
|
MemoryTracker m_memory_tracker;
|
|
StreamBuffer m_staging_buffer;
|
|
StreamBuffer m_stream_buffer;
|
|
StreamBuffer m_download_buffer;
|
|
StreamBuffer m_device_buffer;
|
|
TextureCache& m_texture_cache;
|
|
uint64_t m_total_used_memory = 0;
|
|
uint64_t m_trigger_gc_memory = 1ull * 1024 * 1024 * 1024;
|
|
uint64_t m_critical_gc_memory = 2ull * 1024 * 1024 * 1024;
|
|
uint64_t m_gc_tick = 0;
|
|
};
|
|
|
|
} // namespace Libs::Graphics
|
|
|
|
#endif // EMULATOR_SRC_GRAPHICS_HOST_GPU_RENDERER_BUFFERCACHE_H_
|