buffer_cache: Use boost::intrusive::set for caching
Instead of using boost::icl::interval_map for caching, use boost::intrusive::set. interval_map is intended as a container where the keys can overlap with one another; we don't need this for caching buffers and a std::set-like data structure that allows us to search with lower_bound is enough.
This commit is contained in:
parent
3b0baf746e
commit
891236124c
@ -14,9 +14,11 @@
|
|||||||
|
|
||||||
#include <boost/icl/interval_map.hpp>
|
#include <boost/icl/interval_map.hpp>
|
||||||
#include <boost/icl/interval_set.hpp>
|
#include <boost/icl/interval_set.hpp>
|
||||||
|
#include <boost/intrusive/set.hpp>
|
||||||
#include <boost/range/iterator_range.hpp>
|
#include <boost/range/iterator_range.hpp>
|
||||||
|
|
||||||
#include "common/alignment.h"
|
#include "common/alignment.h"
|
||||||
|
#include "common/assert.h"
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "common/logging/log.h"
|
#include "common/logging/log.h"
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
@ -73,7 +75,7 @@ public:
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto block = GetBlock(cpu_addr, size);
|
OwnerBuffer block = GetBlock(cpu_addr, size);
|
||||||
MapInterval* const map = MapAddress(block, gpu_addr, cpu_addr, size);
|
MapInterval* const map = MapAddress(block, gpu_addr, cpu_addr, size);
|
||||||
if (!map) {
|
if (!map) {
|
||||||
return {GetEmptyBuffer(size), 0};
|
return {GetEmptyBuffer(size), 0};
|
||||||
@ -272,16 +274,16 @@ protected:
|
|||||||
}
|
}
|
||||||
const std::size_t size = new_map.end - new_map.start;
|
const std::size_t size = new_map.end - new_map.start;
|
||||||
new_map.is_registered = true;
|
new_map.is_registered = true;
|
||||||
const IntervalType interval{new_map.start, new_map.end};
|
|
||||||
rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1);
|
rasterizer.UpdatePagesCachedCount(cpu_addr, size, 1);
|
||||||
new_map.is_memory_marked = true;
|
new_map.is_memory_marked = true;
|
||||||
if (inherit_written) {
|
if (inherit_written) {
|
||||||
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;
|
||||||
}
|
}
|
||||||
mapped_addresses.insert({interval, new_map});
|
// Temporary hack, leaks memory and it's not cache local
|
||||||
// Temporary hack until this is replaced with boost::intrusive::rbtree
|
MapInterval* const storage = &mapped_addresses_storage.emplace_back(new_map);
|
||||||
return const_cast<MapInterval*>(&mapped_addresses.find(interval)->second);
|
mapped_addresses.insert(*storage);
|
||||||
|
return storage;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnmarkMemory(MapInterval* map) {
|
void UnmarkMemory(MapInterval* map) {
|
||||||
@ -304,8 +306,9 @@ protected:
|
|||||||
if (map->is_written) {
|
if (map->is_written) {
|
||||||
UnmarkRegionAsWritten(map->start, map->end - 1);
|
UnmarkRegionAsWritten(map->start, map->end - 1);
|
||||||
}
|
}
|
||||||
const IntervalType delete_interval{map->start, map->end};
|
const auto it = mapped_addresses.find(*map);
|
||||||
mapped_addresses.erase(delete_interval);
|
ASSERT(it != mapped_addresses.end());
|
||||||
|
mapped_addresses.erase(it);
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
@ -389,13 +392,20 @@ private:
|
|||||||
return {};
|
return {};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<MapInterval*> objects;
|
std::vector<MapInterval*> result;
|
||||||
const IntervalType interval{addr, addr + size};
|
const VAddr addr_end = addr + size;
|
||||||
for (auto& pair : boost::make_iterator_range(mapped_addresses.equal_range(interval))) {
|
|
||||||
objects.push_back(&pair.second);
|
|
||||||
}
|
|
||||||
|
|
||||||
return objects;
|
auto it = mapped_addresses.lower_bound(addr);
|
||||||
|
if (it != mapped_addresses.begin()) {
|
||||||
|
--it;
|
||||||
|
}
|
||||||
|
while (it != mapped_addresses.end() && it->start < addr_end) {
|
||||||
|
if (it->Overlaps(addr, addr_end)) {
|
||||||
|
result.push_back(&*it);
|
||||||
|
}
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a ticks counter used for tracking when cached objects were last modified
|
/// Returns a ticks counter used for tracking when cached objects were last modified
|
||||||
@ -565,9 +575,9 @@ private:
|
|||||||
u64 buffer_offset_base = 0;
|
u64 buffer_offset_base = 0;
|
||||||
|
|
||||||
using IntervalSet = boost::icl::interval_set<VAddr>;
|
using IntervalSet = boost::icl::interval_set<VAddr>;
|
||||||
using IntervalCache = boost::icl::interval_map<VAddr, MapInterval>;
|
using IntervalType = typename IntervalSet::interval_type;
|
||||||
using IntervalType = typename IntervalCache::interval_type;
|
std::list<MapInterval> mapped_addresses_storage; // Temporary hack
|
||||||
IntervalCache mapped_addresses;
|
boost::intrusive::set<MapInterval, boost::intrusive::compare<MapIntervalCompare>> mapped_addresses;
|
||||||
|
|
||||||
static constexpr u64 write_page_bit = 11;
|
static constexpr u64 write_page_bit = 11;
|
||||||
std::unordered_map<u64, u32> written_pages;
|
std::unordered_map<u64, u32> written_pages;
|
||||||
|
@ -4,38 +4,36 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <boost/intrusive/set_hook.hpp>
|
||||||
|
|
||||||
#include "common/common_types.h"
|
#include "common/common_types.h"
|
||||||
#include "video_core/gpu.h"
|
#include "video_core/gpu.h"
|
||||||
|
|
||||||
namespace VideoCommon {
|
namespace VideoCommon {
|
||||||
|
|
||||||
struct MapInterval {
|
struct MapInterval : public boost::intrusive::set_base_hook<boost::intrusive::optimize_size<true>> {
|
||||||
constexpr explicit MapInterval() noexcept = default;
|
/*implicit*/ MapInterval(VAddr start_) noexcept : start{start_} {}
|
||||||
|
|
||||||
constexpr explicit MapInterval(VAddr start, VAddr end, GPUVAddr gpu_addr) noexcept
|
explicit MapInterval(VAddr start_, VAddr end_, GPUVAddr gpu_addr_) noexcept
|
||||||
: start{start}, end{end}, gpu_addr{gpu_addr} {}
|
: start{start_}, end{end_}, gpu_addr{gpu_addr_} {}
|
||||||
|
|
||||||
constexpr bool IsInside(VAddr other_start, VAddr other_end) const noexcept {
|
bool IsInside(VAddr other_start, VAddr other_end) const noexcept {
|
||||||
return (start <= other_start && other_end <= end);
|
return start <= other_start && other_end <= end;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator==(const MapInterval& rhs) const noexcept {
|
bool Overlaps(VAddr other_start, VAddr other_end) const noexcept {
|
||||||
return start == rhs.start && end == rhs.end;
|
return start < other_end && other_start < end;
|
||||||
}
|
}
|
||||||
|
|
||||||
constexpr bool operator!=(const MapInterval& rhs) const noexcept {
|
void MarkAsModified(bool is_modified_, u64 ticks_) noexcept {
|
||||||
return !operator==(rhs);
|
|
||||||
}
|
|
||||||
|
|
||||||
constexpr void MarkAsModified(bool is_modified_, u64 ticks_) noexcept {
|
|
||||||
is_modified = is_modified_;
|
is_modified = is_modified_;
|
||||||
ticks = ticks_;
|
ticks = ticks_;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
boost::intrusive::set_member_hook<> member_hook_;
|
||||||
VAddr start = 0;
|
VAddr start = 0;
|
||||||
VAddr end = 0;
|
VAddr end = 0;
|
||||||
GPUVAddr gpu_addr = 0;
|
GPUVAddr gpu_addr = 0;
|
||||||
VAddr cpu_addr = 0;
|
|
||||||
u64 ticks = 0;
|
u64 ticks = 0;
|
||||||
bool is_written = false;
|
bool is_written = false;
|
||||||
bool is_modified = false;
|
bool is_modified = false;
|
||||||
@ -44,4 +42,10 @@ struct MapInterval {
|
|||||||
bool is_sync_pending = false;
|
bool is_sync_pending = false;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
struct MapIntervalCompare {
|
||||||
|
constexpr bool operator()(const MapInterval& lhs, const MapInterval& rhs) const noexcept {
|
||||||
|
return lhs.start < rhs.start;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
} // namespace VideoCommon
|
} // namespace VideoCommon
|
||||||
|
@ -8,6 +8,7 @@
|
|||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
#include "common/microprofile.h"
|
#include "common/microprofile.h"
|
||||||
|
#include "video_core/buffer_cache/buffer_cache.h"
|
||||||
#include "video_core/engines/maxwell_3d.h"
|
#include "video_core/engines/maxwell_3d.h"
|
||||||
#include "video_core/rasterizer_interface.h"
|
#include "video_core/rasterizer_interface.h"
|
||||||
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||||
|
@ -4,6 +4,7 @@
|
|||||||
|
|
||||||
#include "common/assert.h"
|
#include "common/assert.h"
|
||||||
|
|
||||||
|
#include "video_core/renderer_opengl/gl_buffer_cache.h"
|
||||||
#include "video_core/renderer_opengl/gl_fence_manager.h"
|
#include "video_core/renderer_opengl/gl_fence_manager.h"
|
||||||
|
|
||||||
namespace OpenGL {
|
namespace OpenGL {
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "core/core.h"
|
#include "core/core.h"
|
||||||
|
#include "video_core/buffer_cache/buffer_cache.h"
|
||||||
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||||
#include "video_core/renderer_vulkan/vk_device.h"
|
#include "video_core/renderer_vulkan/vk_device.h"
|
||||||
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
#include "video_core/renderer_vulkan/vk_scheduler.h"
|
||||||
|
@ -7,6 +7,7 @@
|
|||||||
#include <memory>
|
#include <memory>
|
||||||
|
|
||||||
#include "video_core/fence_manager.h"
|
#include "video_core/fence_manager.h"
|
||||||
|
#include "video_core/renderer_vulkan/vk_buffer_cache.h"
|
||||||
#include "video_core/renderer_vulkan/wrapper.h"
|
#include "video_core/renderer_vulkan/wrapper.h"
|
||||||
|
|
||||||
namespace Core {
|
namespace Core {
|
||||||
|
Loading…
Reference in New Issue
Block a user