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:
parent
19d4f28001
commit
a2dcc642c1
|
@ -1,6 +1,7 @@
|
||||||
add_library(video_core STATIC
|
add_library(video_core STATIC
|
||||||
buffer_cache/buffer_block.h
|
buffer_cache/buffer_block.h
|
||||||
buffer_cache/buffer_cache.h
|
buffer_cache/buffer_cache.h
|
||||||
|
buffer_cache/map_interval.cpp
|
||||||
buffer_cache/map_interval.h
|
buffer_cache/map_interval.h
|
||||||
dirty_flags.cpp
|
dirty_flags.cpp
|
||||||
dirty_flags.h
|
dirty_flags.h
|
||||||
|
|
|
@ -284,8 +284,8 @@ protected:
|
||||||
MarkRegionAsWritten(new_map.start, new_map.end - 1);
|
MarkRegionAsWritten(new_map.start, new_map.end - 1);
|
||||||
new_map.is_written = true;
|
new_map.is_written = true;
|
||||||
}
|
}
|
||||||
// Temporary hack, leaks memory and it's not cache local
|
MapInterval* const storage = mapped_addresses_allocator.Allocate();
|
||||||
MapInterval* const storage = &mapped_addresses_storage.emplace_back(new_map);
|
*storage = new_map;
|
||||||
mapped_addresses.insert(*storage);
|
mapped_addresses.insert(*storage);
|
||||||
return storage;
|
return storage;
|
||||||
}
|
}
|
||||||
|
@ -313,6 +313,7 @@ protected:
|
||||||
const auto it = mapped_addresses.find(*map);
|
const auto it = mapped_addresses.find(*map);
|
||||||
ASSERT(it != mapped_addresses.end());
|
ASSERT(it != mapped_addresses.end());
|
||||||
mapped_addresses.erase(it);
|
mapped_addresses.erase(it);
|
||||||
|
mapped_addresses_allocator.Release(map);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
@ -577,7 +578,7 @@ private:
|
||||||
u64 buffer_offset = 0;
|
u64 buffer_offset = 0;
|
||||||
u64 buffer_offset_base = 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>>
|
boost::intrusive::set<MapInterval, boost::intrusive::compare<MapIntervalCompare>>
|
||||||
mapped_addresses;
|
mapped_addresses;
|
||||||
|
|
||||||
|
|
|
@ -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
|
#pragma once
|
||||||
|
|
||||||
|
#include <array>
|
||||||
|
#include <cstddef>
|
||||||
|
#include <memory>
|
||||||
|
#include <vector>
|
||||||
|
|
||||||
#include <boost/intrusive/set_hook.hpp>
|
#include <boost/intrusive/set_hook.hpp>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
|
@ -12,6 +17,8 @@
|
||||||
namespace VideoCommon {
|
namespace VideoCommon {
|
||||||
|
|
||||||
struct MapInterval : public boost::intrusive::set_base_hook<boost::intrusive::optimize_size<true>> {
|
struct MapInterval : public boost::intrusive::set_base_hook<boost::intrusive::optimize_size<true>> {
|
||||||
|
MapInterval() = default;
|
||||||
|
|
||||||
/*implicit*/ MapInterval(VAddr start_) noexcept : start{start_} {}
|
/*implicit*/ MapInterval(VAddr start_) noexcept : start{start_} {}
|
||||||
|
|
||||||
explicit MapInterval(VAddr start_, VAddr end_, GPUVAddr gpu_addr_) noexcept
|
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
|
} // namespace VideoCommon
|
||||||
|
|
Loading…
Reference in New Issue