mirror of
				https://git.suyu.dev/suyu/suyu
				synced 2025-11-04 08:59:03 -06:00 
			
		
		
		
	map_interval: Add interval allocator and drop hack
Drop the std::list hack to allocate memory indefinitely. Instead use a custom allocator that keeps references valid until destruction. This allocates fixed chunks of memory and puts pointers in a free list. When an allocation is no longer used put it back to the free list, this doesn't heap allocate because std::vector doesn't change the capacity. If the free list is empty, allocate a new chunk.
This commit is contained in:
		@@ -1,6 +1,7 @@
 | 
			
		||||
add_library(video_core STATIC
 | 
			
		||||
    buffer_cache/buffer_block.h
 | 
			
		||||
    buffer_cache/buffer_cache.h
 | 
			
		||||
    buffer_cache/map_interval.cpp
 | 
			
		||||
    buffer_cache/map_interval.h
 | 
			
		||||
    dirty_flags.cpp
 | 
			
		||||
    dirty_flags.h
 | 
			
		||||
 
 | 
			
		||||
@@ -284,8 +284,8 @@ protected:
 | 
			
		||||
            MarkRegionAsWritten(new_map.start, new_map.end - 1);
 | 
			
		||||
            new_map.is_written = true;
 | 
			
		||||
        }
 | 
			
		||||
        // Temporary hack, leaks memory and it's not cache local
 | 
			
		||||
        MapInterval* const storage = &mapped_addresses_storage.emplace_back(new_map);
 | 
			
		||||
        MapInterval* const storage = mapped_addresses_allocator.Allocate();
 | 
			
		||||
        *storage = new_map;
 | 
			
		||||
        mapped_addresses.insert(*storage);
 | 
			
		||||
        return storage;
 | 
			
		||||
    }
 | 
			
		||||
@@ -313,6 +313,7 @@ protected:
 | 
			
		||||
        const auto it = mapped_addresses.find(*map);
 | 
			
		||||
        ASSERT(it != mapped_addresses.end());
 | 
			
		||||
        mapped_addresses.erase(it);
 | 
			
		||||
        mapped_addresses_allocator.Release(map);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
@@ -577,7 +578,7 @@ private:
 | 
			
		||||
    u64 buffer_offset = 0;
 | 
			
		||||
    u64 buffer_offset_base = 0;
 | 
			
		||||
 | 
			
		||||
    std::list<MapInterval> mapped_addresses_storage; // Temporary hack
 | 
			
		||||
    MapIntervalAllocator mapped_addresses_allocator;
 | 
			
		||||
    boost::intrusive::set<MapInterval, boost::intrusive::compare<MapIntervalCompare>>
 | 
			
		||||
        mapped_addresses;
 | 
			
		||||
 | 
			
		||||
 
 | 
			
		||||
							
								
								
									
										33
									
								
								src/video_core/buffer_cache/map_interval.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										33
									
								
								src/video_core/buffer_cache/map_interval.cpp
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,33 @@
 | 
			
		||||
// Copyright 2020 yuzu Emulator Project
 | 
			
		||||
// Licensed under GPLv2 or any later version
 | 
			
		||||
// Refer to the license.txt file included.
 | 
			
		||||
 | 
			
		||||
#include <algorithm>
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <memory>
 | 
			
		||||
 | 
			
		||||
#include "video_core/buffer_cache/map_interval.h"
 | 
			
		||||
 | 
			
		||||
namespace VideoCommon {
 | 
			
		||||
 | 
			
		||||
MapIntervalAllocator::MapIntervalAllocator() {
 | 
			
		||||
    FillFreeList(first_chunk);
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
MapIntervalAllocator::~MapIntervalAllocator() = default;
 | 
			
		||||
 | 
			
		||||
void MapIntervalAllocator::AllocateNewChunk() {
 | 
			
		||||
    *new_chunk = std::make_unique<Chunk>();
 | 
			
		||||
    FillFreeList(**new_chunk);
 | 
			
		||||
    new_chunk = &(*new_chunk)->next;
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
void MapIntervalAllocator::FillFreeList(Chunk& chunk) {
 | 
			
		||||
    const std::size_t old_size = free_list.size();
 | 
			
		||||
    free_list.resize(old_size + chunk.data.size());
 | 
			
		||||
    std::transform(chunk.data.rbegin(), chunk.data.rend(), free_list.begin() + old_size,
 | 
			
		||||
                   [](MapInterval& interval) { return &interval; });
 | 
			
		||||
}
 | 
			
		||||
 | 
			
		||||
} // namespace VideoCommon
 | 
			
		||||
@@ -4,6 +4,11 @@
 | 
			
		||||
 | 
			
		||||
#pragma once
 | 
			
		||||
 | 
			
		||||
#include <array>
 | 
			
		||||
#include <cstddef>
 | 
			
		||||
#include <memory>
 | 
			
		||||
#include <vector>
 | 
			
		||||
 | 
			
		||||
#include <boost/intrusive/set_hook.hpp>
 | 
			
		||||
 | 
			
		||||
#include "common/common_types.h"
 | 
			
		||||
@@ -12,6 +17,8 @@
 | 
			
		||||
namespace VideoCommon {
 | 
			
		||||
 | 
			
		||||
struct MapInterval : public boost::intrusive::set_base_hook<boost::intrusive::optimize_size<true>> {
 | 
			
		||||
    MapInterval() = default;
 | 
			
		||||
 | 
			
		||||
    /*implicit*/ MapInterval(VAddr start_) noexcept : start{start_} {}
 | 
			
		||||
 | 
			
		||||
    explicit MapInterval(VAddr start_, VAddr end_, GPUVAddr gpu_addr_) noexcept
 | 
			
		||||
@@ -48,4 +55,38 @@ struct MapIntervalCompare {
 | 
			
		||||
    }
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
class MapIntervalAllocator {
 | 
			
		||||
public:
 | 
			
		||||
    MapIntervalAllocator();
 | 
			
		||||
    ~MapIntervalAllocator();
 | 
			
		||||
 | 
			
		||||
    MapInterval* Allocate() {
 | 
			
		||||
        if (free_list.empty()) {
 | 
			
		||||
            AllocateNewChunk();
 | 
			
		||||
        }
 | 
			
		||||
        MapInterval* const interval = free_list.back();
 | 
			
		||||
        free_list.pop_back();
 | 
			
		||||
        return interval;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    void Release(MapInterval* interval) {
 | 
			
		||||
        free_list.push_back(interval);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
private:
 | 
			
		||||
    struct Chunk {
 | 
			
		||||
        std::unique_ptr<Chunk> next;
 | 
			
		||||
        std::array<MapInterval, 0x8000> data;
 | 
			
		||||
    };
 | 
			
		||||
 | 
			
		||||
    void AllocateNewChunk();
 | 
			
		||||
 | 
			
		||||
    void FillFreeList(Chunk& chunk);
 | 
			
		||||
 | 
			
		||||
    std::vector<MapInterval*> free_list;
 | 
			
		||||
    std::unique_ptr<Chunk>* new_chunk = &first_chunk.next;
 | 
			
		||||
 | 
			
		||||
    Chunk first_chunk;
 | 
			
		||||
};
 | 
			
		||||
 | 
			
		||||
} // namespace VideoCommon
 | 
			
		||||
 
 | 
			
		||||
		Reference in New Issue
	
	Block a user