mirror of
				https://git.zaroz.cloud/nintendo-back-up/yuzu/yuzu-mainline.git
				synced 2025-03-21 01:53:15 +00:00 
			
		
		
		
	Buffer_Cache: Optimize and track written areas.
This commit is contained in:
		
							parent
							
								
									5f4b746a1e
								
							
						
					
					
						commit
						286f4c446a
					
				@ -43,8 +43,24 @@ public:
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        const auto cache_addr = ToCacheAddr(host_ptr);
 | 
					        const auto cache_addr = ToCacheAddr(host_ptr);
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					        // Cache management is a big overhead, so only cache entries with a given size.
 | 
				
			||||||
 | 
					        // TODO: Figure out which size is the best for given games.
 | 
				
			||||||
 | 
					        constexpr std::size_t max_stream_size = 0x800;
 | 
				
			||||||
 | 
					        if (size < max_stream_size) {
 | 
				
			||||||
 | 
					            if (!is_written && !IsRegionWritten(cache_addr, cache_addr + size - 1)) {
 | 
				
			||||||
 | 
					                return StreamBufferUpload(host_ptr, size, alignment);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        auto block = GetBlock(cache_addr, size);
 | 
					        auto block = GetBlock(cache_addr, size);
 | 
				
			||||||
        MapAddress(block, gpu_addr, cache_addr, size);
 | 
					        auto map = MapAddress(block, gpu_addr, cache_addr, size);
 | 
				
			||||||
 | 
					        if (is_written) {
 | 
				
			||||||
 | 
					            map->MarkAsModified(true, GetModifiedTicks());
 | 
				
			||||||
 | 
					            if (!map->IsWritten()) {
 | 
				
			||||||
 | 
					                map->MarkAsWritten(true);
 | 
				
			||||||
 | 
					                MarkRegionAsWritten(map->GetStart(), map->GetEnd() - 1);
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const u64 offset = static_cast<u64>(block->GetOffset(cache_addr));
 | 
					        const u64 offset = static_cast<u64>(block->GetOffset(cache_addr));
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -124,7 +140,7 @@ protected:
 | 
				
			|||||||
                           std::size_t dst_offset, std::size_t size) = 0;
 | 
					                           std::size_t dst_offset, std::size_t size) = 0;
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Register an object into the cache
 | 
					    /// Register an object into the cache
 | 
				
			||||||
    void Register(const MapInterval& new_map) {
 | 
					    void Register(const MapInterval& new_map, bool inherit_written = false) {
 | 
				
			||||||
        const CacheAddr cache_ptr = new_map->GetStart();
 | 
					        const CacheAddr cache_ptr = new_map->GetStart();
 | 
				
			||||||
        const std::optional<VAddr> cpu_addr =
 | 
					        const std::optional<VAddr> cpu_addr =
 | 
				
			||||||
            system.GPU().MemoryManager().GpuToCpuAddress(new_map->GetGpuAddress());
 | 
					            system.GPU().MemoryManager().GpuToCpuAddress(new_map->GetGpuAddress());
 | 
				
			||||||
@ -139,6 +155,10 @@ protected:
 | 
				
			|||||||
        const IntervalType interval{new_map->GetStart(), new_map->GetEnd()};
 | 
					        const IntervalType interval{new_map->GetStart(), new_map->GetEnd()};
 | 
				
			||||||
        mapped_addresses.insert({interval, new_map});
 | 
					        mapped_addresses.insert({interval, new_map});
 | 
				
			||||||
        rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1);
 | 
					        rasterizer.UpdatePagesCachedCount(*cpu_addr, size, 1);
 | 
				
			||||||
 | 
					        if (inherit_written) {
 | 
				
			||||||
 | 
					            MarkRegionAsWritten(new_map->GetStart(), new_map->GetEnd() - 1);
 | 
				
			||||||
 | 
					            new_map->MarkAsWritten(true);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    /// Unregisters an object from the cache
 | 
					    /// Unregisters an object from the cache
 | 
				
			||||||
@ -146,6 +166,9 @@ protected:
 | 
				
			|||||||
        const std::size_t size = map->GetEnd() - map->GetStart();
 | 
					        const std::size_t size = map->GetEnd() - map->GetStart();
 | 
				
			||||||
        rasterizer.UpdatePagesCachedCount(map->GetCpuAddress(), size, -1);
 | 
					        rasterizer.UpdatePagesCachedCount(map->GetCpuAddress(), size, -1);
 | 
				
			||||||
        map->MarkAsRegistered(false);
 | 
					        map->MarkAsRegistered(false);
 | 
				
			||||||
 | 
					        if (map->IsWritten()) {
 | 
				
			||||||
 | 
					            UnmarkRegionAsWritten(map->GetStart(), map->GetEnd() - 1);
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
        const IntervalType delete_interval{map->GetStart(), map->GetEnd()};
 | 
					        const IntervalType delete_interval{map->GetStart(), map->GetEnd()};
 | 
				
			||||||
        mapped_addresses.erase(delete_interval);
 | 
					        mapped_addresses.erase(delete_interval);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
@ -155,8 +178,8 @@ private:
 | 
				
			|||||||
        return std::make_shared<MapIntervalBase>(start, end, gpu_addr);
 | 
					        return std::make_shared<MapIntervalBase>(start, end, gpu_addr);
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void MapAddress(const TBuffer& block, const GPUVAddr gpu_addr, const CacheAddr cache_addr,
 | 
					    MapInterval MapAddress(const TBuffer& block, const GPUVAddr gpu_addr,
 | 
				
			||||||
                    const std::size_t size) {
 | 
					                           const CacheAddr cache_addr, const std::size_t size) {
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        std::vector<MapInterval> overlaps = GetMapsInRange(cache_addr, size);
 | 
					        std::vector<MapInterval> overlaps = GetMapsInRange(cache_addr, size);
 | 
				
			||||||
        if (overlaps.empty()) {
 | 
					        if (overlaps.empty()) {
 | 
				
			||||||
@ -165,22 +188,24 @@ private:
 | 
				
			|||||||
            u8* host_ptr = FromCacheAddr(cache_addr);
 | 
					            u8* host_ptr = FromCacheAddr(cache_addr);
 | 
				
			||||||
            UploadBlockData(block, block->GetOffset(cache_addr), size, host_ptr);
 | 
					            UploadBlockData(block, block->GetOffset(cache_addr), size, host_ptr);
 | 
				
			||||||
            Register(new_map);
 | 
					            Register(new_map);
 | 
				
			||||||
            return;
 | 
					            return new_map;
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
        const CacheAddr cache_addr_end = cache_addr + size;
 | 
					        const CacheAddr cache_addr_end = cache_addr + size;
 | 
				
			||||||
        if (overlaps.size() == 1) {
 | 
					        if (overlaps.size() == 1) {
 | 
				
			||||||
            const MapInterval& current_map = overlaps[0];
 | 
					            MapInterval& current_map = overlaps[0];
 | 
				
			||||||
            if (current_map->IsInside(cache_addr, cache_addr_end)) {
 | 
					            if (current_map->IsInside(cache_addr, cache_addr_end)) {
 | 
				
			||||||
                return;
 | 
					                return current_map;
 | 
				
			||||||
            }
 | 
					            }
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        CacheAddr new_start = cache_addr;
 | 
					        CacheAddr new_start = cache_addr;
 | 
				
			||||||
        CacheAddr new_end = cache_addr_end;
 | 
					        CacheAddr new_end = cache_addr_end;
 | 
				
			||||||
 | 
					        bool write_inheritance = false;
 | 
				
			||||||
        // Calculate new buffer parameters
 | 
					        // Calculate new buffer parameters
 | 
				
			||||||
        for (auto& overlap : overlaps) {
 | 
					        for (auto& overlap : overlaps) {
 | 
				
			||||||
            new_start = std::min(overlap->GetStart(), new_start);
 | 
					            new_start = std::min(overlap->GetStart(), new_start);
 | 
				
			||||||
            new_end = std::max(overlap->GetEnd(), new_end);
 | 
					            new_end = std::max(overlap->GetEnd(), new_end);
 | 
				
			||||||
 | 
					            write_inheritance |= overlap->IsWritten();
 | 
				
			||||||
        }
 | 
					        }
 | 
				
			||||||
        GPUVAddr new_gpu_addr = gpu_addr + new_start - cache_addr;
 | 
					        GPUVAddr new_gpu_addr = gpu_addr + new_start - cache_addr;
 | 
				
			||||||
        for (auto& overlap : overlaps) {
 | 
					        for (auto& overlap : overlaps) {
 | 
				
			||||||
@ -188,7 +213,8 @@ private:
 | 
				
			|||||||
        }
 | 
					        }
 | 
				
			||||||
        UpdateBlock(block, new_start, new_end, overlaps);
 | 
					        UpdateBlock(block, new_start, new_end, overlaps);
 | 
				
			||||||
        MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr);
 | 
					        MapInterval new_map = CreateMap(new_start, new_end, new_gpu_addr);
 | 
				
			||||||
        Register(new_map);
 | 
					        Register(new_map, write_inheritance);
 | 
				
			||||||
 | 
					        return new_map;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    void UpdateBlock(const TBuffer& block, CacheAddr start, CacheAddr end,
 | 
					    void UpdateBlock(const TBuffer& block, CacheAddr start, CacheAddr end,
 | 
				
			||||||
@ -320,6 +346,48 @@ private:
 | 
				
			|||||||
        return found;
 | 
					        return found;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void MarkRegionAsWritten(const CacheAddr start, const CacheAddr end) {
 | 
				
			||||||
 | 
					        u64 page_start = start >> write_page_bit;
 | 
				
			||||||
 | 
					        const u64 page_end = end >> write_page_bit;
 | 
				
			||||||
 | 
					        while (page_start <= page_end) {
 | 
				
			||||||
 | 
					            auto it = written_pages.find(page_start);
 | 
				
			||||||
 | 
					            if (it != written_pages.end()) {
 | 
				
			||||||
 | 
					                it->second = it->second + 1;
 | 
				
			||||||
 | 
					            } else {
 | 
				
			||||||
 | 
					                written_pages[page_start] = 1;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            page_start++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void UnmarkRegionAsWritten(const CacheAddr start, const CacheAddr end) {
 | 
				
			||||||
 | 
					        u64 page_start = start >> write_page_bit;
 | 
				
			||||||
 | 
					        const u64 page_end = end >> write_page_bit;
 | 
				
			||||||
 | 
					        while (page_start <= page_end) {
 | 
				
			||||||
 | 
					            auto it = written_pages.find(page_start);
 | 
				
			||||||
 | 
					            if (it != written_pages.end()) {
 | 
				
			||||||
 | 
					                if (it->second > 1) {
 | 
				
			||||||
 | 
					                    it->second = it->second - 1;
 | 
				
			||||||
 | 
					                } else {
 | 
				
			||||||
 | 
					                    written_pages.erase(it);
 | 
				
			||||||
 | 
					                }
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            page_start++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool IsRegionWritten(const CacheAddr start, const CacheAddr end) const {
 | 
				
			||||||
 | 
					        u64 page_start = start >> write_page_bit;
 | 
				
			||||||
 | 
					        const u64 page_end = end >> write_page_bit;
 | 
				
			||||||
 | 
					        while (page_start <= page_end) {
 | 
				
			||||||
 | 
					            if (written_pages.count(page_start) > 0) {
 | 
				
			||||||
 | 
					                return true;
 | 
				
			||||||
 | 
					            }
 | 
				
			||||||
 | 
					            page_start++;
 | 
				
			||||||
 | 
					        }
 | 
				
			||||||
 | 
					        return false;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::unique_ptr<StreamBuffer> stream_buffer;
 | 
					    std::unique_ptr<StreamBuffer> stream_buffer;
 | 
				
			||||||
    TBufferType stream_buffer_handle{};
 | 
					    TBufferType stream_buffer_handle{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
@ -334,11 +402,14 @@ private:
 | 
				
			|||||||
    using IntervalType = typename IntervalCache::interval_type;
 | 
					    using IntervalType = typename IntervalCache::interval_type;
 | 
				
			||||||
    IntervalCache mapped_addresses{};
 | 
					    IntervalCache mapped_addresses{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
    static constexpr u64 block_page_bits{24};
 | 
					    static constexpr u64 write_page_bit{11};
 | 
				
			||||||
    static constexpr u64 block_page_size{1 << block_page_bits};
 | 
					    std::unordered_map<u64, u32> written_pages{};
 | 
				
			||||||
    std::unordered_map<u64, TBuffer> blocks;
 | 
					 | 
				
			||||||
 | 
					
 | 
				
			||||||
    std::list<TBuffer> pending_destruction;
 | 
					    static constexpr u64 block_page_bits{21};
 | 
				
			||||||
 | 
					    static constexpr u64 block_page_size{1 << block_page_bits};
 | 
				
			||||||
 | 
					    std::unordered_map<u64, TBuffer> blocks{};
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    std::list<TBuffer> pending_destruction{};
 | 
				
			||||||
    u64 epoch{};
 | 
					    u64 epoch{};
 | 
				
			||||||
    u64 modified_ticks{};
 | 
					    u64 modified_ticks{};
 | 
				
			||||||
    VideoCore::RasterizerInterface& rasterizer;
 | 
					    VideoCore::RasterizerInterface& rasterizer;
 | 
				
			||||||
 | 
				
			|||||||
@ -54,12 +54,33 @@ public:
 | 
				
			|||||||
        return end;
 | 
					        return end;
 | 
				
			||||||
    }
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void MarkAsModified(const bool is_modified_, const u64 tick) {
 | 
				
			||||||
 | 
					        is_modified = is_modified_;
 | 
				
			||||||
 | 
					        ticks = tick;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool IsModified() const {
 | 
				
			||||||
 | 
					        return is_modified;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    u64 GetModificationTick() const {
 | 
				
			||||||
 | 
					        return ticks;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    void MarkAsWritten(const bool is_written_) {
 | 
				
			||||||
 | 
					        is_written = is_written_;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
 | 
					    bool IsWritten() const {
 | 
				
			||||||
 | 
					        return is_written;
 | 
				
			||||||
 | 
					    }
 | 
				
			||||||
 | 
					
 | 
				
			||||||
private:
 | 
					private:
 | 
				
			||||||
    CacheAddr start;
 | 
					    CacheAddr start;
 | 
				
			||||||
    CacheAddr end;
 | 
					    CacheAddr end;
 | 
				
			||||||
    GPUVAddr gpu_addr;
 | 
					    GPUVAddr gpu_addr;
 | 
				
			||||||
    VAddr cpu_addr{};
 | 
					    VAddr cpu_addr{};
 | 
				
			||||||
    bool is_write{};
 | 
					    bool is_written{};
 | 
				
			||||||
    bool is_modified{};
 | 
					    bool is_modified{};
 | 
				
			||||||
    bool is_registered{};
 | 
					    bool is_registered{};
 | 
				
			||||||
    u64 ticks{};
 | 
					    u64 ticks{};
 | 
				
			||||||
 | 
				
			|||||||
		Loading…
	
		Reference in New Issue
	
	Block a user