summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--src/video_core/buffer_cache/buffer_cache.h93
-rw-r--r--src/video_core/buffer_cache/map_interval.h23
2 files changed, 104 insertions, 12 deletions
diff --git a/src/video_core/buffer_cache/buffer_cache.h b/src/video_core/buffer_cache/buffer_cache.h
index 7c1737fe2..4ea43a6c4 100644
--- a/src/video_core/buffer_cache/buffer_cache.h
+++ b/src/video_core/buffer_cache/buffer_cache.h
@@ -43,8 +43,24 @@ public:
}
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);
- 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));
@@ -124,7 +140,7 @@ protected:
std::size_t dst_offset, std::size_t size) = 0;
/// 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 std::optional<VAddr> cpu_addr =
system.GPU().MemoryManager().GpuToCpuAddress(new_map->GetGpuAddress());
@@ -139,6 +155,10 @@ protected:
const IntervalType interval{new_map->GetStart(), new_map->GetEnd()};
mapped_addresses.insert({interval, new_map});
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
@@ -146,6 +166,9 @@ protected:
const std::size_t size = map->GetEnd() - map->GetStart();
rasterizer.UpdatePagesCachedCount(map->GetCpuAddress(), size, -1);
map->MarkAsRegistered(false);
+ if (map->IsWritten()) {
+ UnmarkRegionAsWritten(map->GetStart(), map->GetEnd() - 1);
+ }
const IntervalType delete_interval{map->GetStart(), map->GetEnd()};
mapped_addresses.erase(delete_interval);
}
@@ -155,8 +178,8 @@ private:
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) {
+ MapInterval 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()) {
@@ -165,22 +188,24 @@ private:
u8* host_ptr = FromCacheAddr(cache_addr);
UploadBlockData(block, block->GetOffset(cache_addr), size, host_ptr);
Register(new_map);
- return;
+ return new_map;
}
const CacheAddr cache_addr_end = cache_addr + size;
if (overlaps.size() == 1) {
- const MapInterval& current_map = overlaps[0];
+ MapInterval& current_map = overlaps[0];
if (current_map->IsInside(cache_addr, cache_addr_end)) {
- return;
+ return current_map;
}
}
CacheAddr new_start = cache_addr;
CacheAddr new_end = cache_addr_end;
+ bool write_inheritance = false;
// Calculate new buffer parameters
for (auto& overlap : overlaps) {
new_start = std::min(overlap->GetStart(), new_start);
new_end = std::max(overlap->GetEnd(), new_end);
+ write_inheritance |= overlap->IsWritten();
}
GPUVAddr new_gpu_addr = gpu_addr + new_start - cache_addr;
for (auto& overlap : overlaps) {
@@ -188,7 +213,8 @@ private:
}
UpdateBlock(block, new_start, new_end, overlaps);
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,
@@ -320,6 +346,48 @@ private:
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;
TBufferType stream_buffer_handle{};
@@ -334,11 +402,14 @@ private:
using IntervalType = typename IntervalCache::interval_type;
IntervalCache mapped_addresses{};
- static constexpr u64 block_page_bits{24};
+ static constexpr u64 write_page_bit{11};
+ std::unordered_map<u64, u32> written_pages{};
+
+ static constexpr u64 block_page_bits{21};
static constexpr u64 block_page_size{1 << block_page_bits};
- std::unordered_map<u64, TBuffer> blocks;
+ std::unordered_map<u64, TBuffer> blocks{};
- std::list<TBuffer> pending_destruction;
+ std::list<TBuffer> pending_destruction{};
u64 epoch{};
u64 modified_ticks{};
VideoCore::RasterizerInterface& rasterizer;
diff --git a/src/video_core/buffer_cache/map_interval.h b/src/video_core/buffer_cache/map_interval.h
index a01eddf49..3a104d5cd 100644
--- a/src/video_core/buffer_cache/map_interval.h
+++ b/src/video_core/buffer_cache/map_interval.h
@@ -54,12 +54,33 @@ public:
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:
CacheAddr start;
CacheAddr end;
GPUVAddr gpu_addr;
VAddr cpu_addr{};
- bool is_write{};
+ bool is_written{};
bool is_modified{};
bool is_registered{};
u64 ticks{};