mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 00:49:02 -06:00 
			
		
		
		
	BufferCache: Rework mapping caching.
This commit is contained in:
		
				
					committed by
					
						
						FernandoS27
					
				
			
			
				
	
			
			
			
						parent
						
							86d8563314
						
					
				
				
					commit
					5f4b746a1e
				
			@@ -25,6 +25,8 @@ class RasterizerInterface;
 | 
			
		||||
 | 
			
		||||
namespace VideoCommon {
 | 
			
		||||
 | 
			
		||||
using MapInterval = std::shared_ptr<MapIntervalBase>;
 | 
			
		||||
 | 
			
		||||
template <typename TBuffer, typename TBufferType, typename StreamBuffer>
 | 
			
		||||
class BufferCache {
 | 
			
		||||
public:
 | 
			
		||||
@@ -90,7 +92,9 @@ public:
 | 
			
		||||
 | 
			
		||||
        std::vector<MapInterval> objects = GetMapsInRange(addr, size);
 | 
			
		||||
        for (auto& object : objects) {
 | 
			
		||||
            Unregister(object);
 | 
			
		||||
            if (object->IsRegistered()) {
 | 
			
		||||
                Unregister(object);
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
@@ -120,51 +124,54 @@ protected:
 | 
			
		||||
                           std::size_t dst_offset, std::size_t size) = 0;
 | 
			
		||||
 | 
			
		||||
    /// Register an object into the cache
 | 
			
		||||
    void Register(const MapInterval& new_interval, const GPUVAddr gpu_addr) {
 | 
			
		||||
        const CacheAddr cache_ptr = new_interval.start;
 | 
			
		||||
        const std::size_t size = new_interval.end - new_interval.start;
 | 
			
		||||
    void Register(const MapInterval& new_map) {
 | 
			
		||||
        const CacheAddr cache_ptr = new_map->GetStart();
 | 
			
		||||
        const std::optional<VAddr> cpu_addr =
 | 
			
		||||
            system.GPU().MemoryManager().GpuToCpuAddress(gpu_addr);
 | 
			
		||||
            system.GPU().MemoryManager().GpuToCpuAddress(new_map->GetGpuAddress());
 | 
			
		||||
        if (!cache_ptr || !cpu_addr) {
 | 
			
		||||
            LOG_CRITICAL(HW_GPU, "Failed to register buffer with unmapped gpu_address 0x{:016x}",
 | 
			
		||||
                         gpu_addr);
 | 
			
		||||
                         new_map->GetGpuAddress());
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
        const IntervalType interval{new_interval.start, new_interval.end};
 | 
			
		||||
        mapped_addresses.insert(interval);
 | 
			
		||||
        map_storage[new_interval] = MapInfo{gpu_addr, *cpu_addr};
 | 
			
		||||
 | 
			
		||||
        const std::size_t size = new_map->GetEnd() - new_map->GetStart();
 | 
			
		||||
        new_map->SetCpuAddress(*cpu_addr);
 | 
			
		||||
        new_map->MarkAsRegistered(true);
 | 
			
		||||
        const IntervalType interval{new_map->GetStart(), new_map->GetEnd()};
 | 
			
		||||
        mapped_addresses.insert({interval, new_map});
 | 
			
		||||
        rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /// Unregisters an object from the cache
 | 
			
		||||
    void Unregister(const MapInterval& interval) {
 | 
			
		||||
        const MapInfo info = map_storage[interval];
 | 
			
		||||
        const std::size_t size = interval.end - interval.start;
 | 
			
		||||
        rasterizer.UpdatePagesCachedCount(info.cpu_addr, size, -1);
 | 
			
		||||
        const IntervalType delete_interval{interval.start, interval.end};
 | 
			
		||||
    void Unregister(MapInterval& map) {
 | 
			
		||||
        const std::size_t size = map->GetEnd() - map->GetStart();
 | 
			
		||||
        rasterizer.UpdatePagesCachedCount(map->GetCpuAddress(), size, -1);
 | 
			
		||||
        map->MarkAsRegistered(false);
 | 
			
		||||
        const IntervalType delete_interval{map->GetStart(), map->GetEnd()};
 | 
			
		||||
        mapped_addresses.erase(delete_interval);
 | 
			
		||||
        map_storage.erase(interval);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    MapInterval CreateMap(const CacheAddr start, const CacheAddr end, const GPUVAddr gpu_addr) {
 | 
			
		||||
        return std::make_shared<MapIntervalBase>(start, end, gpu_addr);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void MapAddress(const TBuffer& block, const GPUVAddr gpu_addr, const CacheAddr cache_addr,
 | 
			
		||||
                    const std::size_t size) {
 | 
			
		||||
 | 
			
		||||
        std::vector<MapInterval> overlaps = GetMapsInRange(cache_addr, size);
 | 
			
		||||
        if (overlaps.empty()) {
 | 
			
		||||
            const CacheAddr cache_addr_end = cache_addr + size;
 | 
			
		||||
            MapInterval new_interval{cache_addr, cache_addr_end};
 | 
			
		||||
            MapInterval new_map = CreateMap(cache_addr, cache_addr_end, gpu_addr);
 | 
			
		||||
            u8* host_ptr = FromCacheAddr(cache_addr);
 | 
			
		||||
            UploadBlockData(block, block->GetOffset(cache_addr), size, host_ptr);
 | 
			
		||||
            Register(new_interval, gpu_addr);
 | 
			
		||||
            Register(new_map);
 | 
			
		||||
            return;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        const CacheAddr cache_addr_end = cache_addr + size;
 | 
			
		||||
        if (overlaps.size() == 1) {
 | 
			
		||||
            const MapInterval& current_map = overlaps[0];
 | 
			
		||||
            if (current_map.IsInside(cache_addr, cache_addr_end)) {
 | 
			
		||||
            if (current_map->IsInside(cache_addr, cache_addr_end)) {
 | 
			
		||||
                return;
 | 
			
		||||
            }
 | 
			
		||||
        }
 | 
			
		||||
@@ -172,25 +179,25 @@ private:
 | 
			
		||||
        CacheAddr new_end = cache_addr_end;
 | 
			
		||||
        // Calculate new buffer parameters
 | 
			
		||||
        for (auto& overlap : overlaps) {
 | 
			
		||||
            new_start = std::min(overlap.start, new_start);
 | 
			
		||||
            new_end = std::max(overlap.end, new_end);
 | 
			
		||||
            new_start = std::min(overlap->GetStart(), new_start);
 | 
			
		||||
            new_end = std::max(overlap->GetEnd(), new_end);
 | 
			
		||||
        }
 | 
			
		||||
        GPUVAddr new_gpu_addr = gpu_addr + new_start - cache_addr;
 | 
			
		||||
        for (auto& overlap : overlaps) {
 | 
			
		||||
            Unregister(overlap);
 | 
			
		||||
        }
 | 
			
		||||
        UpdateBlock(block, new_start, new_end, overlaps);
 | 
			
		||||
        MapInterval new_interval{new_start, new_end};
 | 
			
		||||
        Register(new_interval, new_gpu_addr);
 | 
			
		||||
        MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr);
 | 
			
		||||
        Register(new_map);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void UpdateBlock(const TBuffer& block, CacheAddr start, CacheAddr end,
 | 
			
		||||
                     std::vector<MapInterval>& overlaps) {
 | 
			
		||||
        const IntervalType base_interval{start, end};
 | 
			
		||||
        IntervalCache interval_set{};
 | 
			
		||||
        IntervalSet interval_set{};
 | 
			
		||||
        interval_set.add(base_interval);
 | 
			
		||||
        for (auto& overlap : overlaps) {
 | 
			
		||||
            const IntervalType subtract{overlap.start, overlap.end};
 | 
			
		||||
            const IntervalType subtract{overlap->GetStart(), overlap->GetEnd()};
 | 
			
		||||
            interval_set.subtract(subtract);
 | 
			
		||||
        }
 | 
			
		||||
        for (auto& interval : interval_set) {
 | 
			
		||||
@@ -210,7 +217,7 @@ private:
 | 
			
		||||
        std::vector<MapInterval> objects{};
 | 
			
		||||
        const IntervalType interval{addr, addr + size};
 | 
			
		||||
        for (auto& pair : boost::make_iterator_range(mapped_addresses.equal_range(interval))) {
 | 
			
		||||
            objects.emplace_back(pair.lower(), pair.upper());
 | 
			
		||||
            objects.push_back(pair.second);
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return objects;
 | 
			
		||||
@@ -322,10 +329,10 @@ private:
 | 
			
		||||
    u64 buffer_offset = 0;
 | 
			
		||||
    u64 buffer_offset_base = 0;
 | 
			
		||||
 | 
			
		||||
    using IntervalCache = boost::icl::interval_set<CacheAddr>;
 | 
			
		||||
    using IntervalSet = boost::icl::interval_set<CacheAddr>;
 | 
			
		||||
    using IntervalCache = boost::icl::interval_map<CacheAddr, MapInterval>;
 | 
			
		||||
    using IntervalType = typename IntervalCache::interval_type;
 | 
			
		||||
    IntervalCache mapped_addresses{};
 | 
			
		||||
    std::unordered_map<MapInterval, MapInfo> map_storage;
 | 
			
		||||
 | 
			
		||||
    static constexpr u64 block_page_bits{24};
 | 
			
		||||
    static constexpr u64 block_page_size{1 << block_page_bits};
 | 
			
		||||
 
 | 
			
		||||
@@ -4,45 +4,65 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <boost/functional/hash.hpp>
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
#include "video_core/gpu.h"
 | 
			
		||||
 | 
			
		||||
namespace VideoCommon {
 | 
			
		||||
 | 
			
		||||
struct MapInterval {
 | 
			
		||||
    MapInterval(const CacheAddr start, const CacheAddr end) : start{start}, end{end} {}
 | 
			
		||||
    CacheAddr start;
 | 
			
		||||
    CacheAddr end;
 | 
			
		||||
class MapIntervalBase {
 | 
			
		||||
public:
 | 
			
		||||
    MapIntervalBase(const CacheAddr start, const CacheAddr end, const GPUVAddr gpu_addr)
 | 
			
		||||
        : start{start}, end{end}, gpu_addr{gpu_addr} {}
 | 
			
		||||
 | 
			
		||||
    void SetCpuAddress(VAddr new_cpu_addr) {
 | 
			
		||||
        cpu_addr = new_cpu_addr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    VAddr GetCpuAddress() const {
 | 
			
		||||
        return cpu_addr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    GPUVAddr GetGpuAddress() const {
 | 
			
		||||
        return gpu_addr;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool IsInside(const CacheAddr other_start, const CacheAddr other_end) const {
 | 
			
		||||
        return (start <= other_start && other_end <= end);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool operator==(const MapInterval& rhs) const {
 | 
			
		||||
    bool operator==(const MapIntervalBase& rhs) const {
 | 
			
		||||
        return std::tie(start, end) == std::tie(rhs.start, rhs.end);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool operator!=(const MapInterval& rhs) const {
 | 
			
		||||
    bool operator!=(const MapIntervalBase& rhs) const {
 | 
			
		||||
        return !operator==(rhs);
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
struct MapInfo {
 | 
			
		||||
    void MarkAsRegistered(const bool registered) {
 | 
			
		||||
        is_registered = registered;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    bool IsRegistered() const {
 | 
			
		||||
        return is_registered;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CacheAddr GetStart() const {
 | 
			
		||||
        return start;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    CacheAddr GetEnd() const {
 | 
			
		||||
        return end;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    CacheAddr start;
 | 
			
		||||
    CacheAddr end;
 | 
			
		||||
    GPUVAddr gpu_addr;
 | 
			
		||||
    VAddr cpu_addr;
 | 
			
		||||
    VAddr cpu_addr{};
 | 
			
		||||
    bool is_write{};
 | 
			
		||||
    bool is_modified{};
 | 
			
		||||
    bool is_registered{};
 | 
			
		||||
    u64 ticks{};
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace VideoCommon
 | 
			
		||||
 | 
			
		||||
namespace std {
 | 
			
		||||
 | 
			
		||||
template <>
 | 
			
		||||
struct hash<VideoCommon::MapInterval> {
 | 
			
		||||
    std::size_t operator()(const VideoCommon::MapInterval& k) const noexcept {
 | 
			
		||||
        std::size_t a = std::hash<CacheAddr>()(k.start);
 | 
			
		||||
        boost::hash_combine(a, std::hash<CacheAddr>()(k.end));
 | 
			
		||||
        return a;
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace std
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user