forked from suyu/suyu
Buffer_Cache: Optimize and track written areas.
This commit is contained in:
parent
5f4b746a1e
commit
286f4c446a
2 changed files with 105 additions and 13 deletions
|
@ -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 a new issue