buffer_cache: Avoid passing references of shared pointers and misc style changes
Instead of using as template argument a shared pointer, use the underlying type and manage shared pointers explicitly. This can make removing shared pointers from the cache more easy. While we are at it, make some misc style changes and general improvements (like insert_or_assign instead of operator[] + operator=).
This commit is contained in:
parent
3626254f48
commit
6508cdd003
9 changed files with 150 additions and 174 deletions
|
@ -15,48 +15,47 @@ namespace VideoCommon {
|
||||||
|
|
||||||
class BufferBlock {
|
class BufferBlock {
|
||||||
public:
|
public:
|
||||||
bool Overlaps(const VAddr start, const VAddr end) const {
|
bool Overlaps(VAddr start, VAddr end) const {
|
||||||
return (cpu_addr < end) && (cpu_addr_end > start);
|
return (cpu_addr < end) && (cpu_addr_end > start);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsInside(const VAddr other_start, const VAddr other_end) const {
|
bool IsInside(VAddr other_start, VAddr other_end) const {
|
||||||
return cpu_addr <= other_start && other_end <= cpu_addr_end;
|
return cpu_addr <= other_start && other_end <= cpu_addr_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t GetOffset(const VAddr in_addr) {
|
std::size_t Offset(VAddr in_addr) const {
|
||||||
return static_cast<std::size_t>(in_addr - cpu_addr);
|
return static_cast<std::size_t>(in_addr - cpu_addr);
|
||||||
}
|
}
|
||||||
|
|
||||||
VAddr GetCpuAddr() const {
|
VAddr CpuAddr() const {
|
||||||
return cpu_addr;
|
return cpu_addr;
|
||||||
}
|
}
|
||||||
|
|
||||||
VAddr GetCpuAddrEnd() const {
|
VAddr CpuAddrEnd() const {
|
||||||
return cpu_addr_end;
|
return cpu_addr_end;
|
||||||
}
|
}
|
||||||
|
|
||||||
void SetCpuAddr(const VAddr new_addr) {
|
void SetCpuAddr(VAddr new_addr) {
|
||||||
cpu_addr = new_addr;
|
cpu_addr = new_addr;
|
||||||
cpu_addr_end = new_addr + size;
|
cpu_addr_end = new_addr + size;
|
||||||
}
|
}
|
||||||
|
|
||||||
std::size_t GetSize() const {
|
std::size_t Size() const {
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
u64 Epoch() const {
|
||||||
|
return epoch;
|
||||||
|
}
|
||||||
|
|
||||||
void SetEpoch(u64 new_epoch) {
|
void SetEpoch(u64 new_epoch) {
|
||||||
epoch = new_epoch;
|
epoch = new_epoch;
|
||||||
}
|
}
|
||||||
|
|
||||||
u64 GetEpoch() {
|
|
||||||
return epoch;
|
|
||||||
}
|
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit BufferBlock(VAddr cpu_addr, const std::size_t size) : size{size} {
|
explicit BufferBlock(VAddr cpu_addr_, std::size_t size_) : size{size_} {
|
||||||
SetCpuAddr(cpu_addr);
|
SetCpuAddr(cpu_addr_);
|
||||||
}
|
}
|
||||||
~BufferBlock() = default;
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
VAddr cpu_addr{};
|
VAddr cpu_addr{};
|
||||||
|
|
|
@ -30,12 +30,16 @@
|
||||||
|
|
||||||
namespace VideoCommon {
|
namespace VideoCommon {
|
||||||
|
|
||||||
template <typename OwnerBuffer, typename BufferType, typename StreamBuffer>
|
template <typename Buffer, typename BufferType, typename StreamBuffer>
|
||||||
class BufferCache {
|
class BufferCache {
|
||||||
using IntervalSet = boost::icl::interval_set<VAddr>;
|
using IntervalSet = boost::icl::interval_set<VAddr>;
|
||||||
using IntervalType = typename IntervalSet::interval_type;
|
using IntervalType = typename IntervalSet::interval_type;
|
||||||
using VectorMapInterval = boost::container::small_vector<MapInterval*, 1>;
|
using VectorMapInterval = boost::container::small_vector<MapInterval*, 1>;
|
||||||
|
|
||||||
|
static constexpr u64 WRITE_PAGE_BIT = 11;
|
||||||
|
static constexpr u64 BLOCK_PAGE_BITS = 21;
|
||||||
|
static constexpr u64 BLOCK_PAGE_SIZE = 1ULL << BLOCK_PAGE_BITS;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using BufferInfo = std::pair<BufferType, u64>;
|
using BufferInfo = std::pair<BufferType, u64>;
|
||||||
|
|
||||||
|
@ -82,7 +86,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
OwnerBuffer block = GetBlock(cpu_addr, size);
|
Buffer* const 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};
|
||||||
|
@ -98,7 +102,7 @@ public:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {ToHandle(block), static_cast<u64>(block->GetOffset(cpu_addr))};
|
return {block->Handle(), static_cast<u64>(block->Offset(cpu_addr))};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Uploads from a host memory. Returns the OpenGL buffer where it's located and its offset.
|
/// Uploads from a host memory. Returns the OpenGL buffer where it's located and its offset.
|
||||||
|
@ -125,16 +129,18 @@ public:
|
||||||
return std::exchange(invalidated, false);
|
return std::exchange(invalidated, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Function called at the end of each frame, inteded for deferred operations
|
||||||
void TickFrame() {
|
void TickFrame() {
|
||||||
++epoch;
|
++epoch;
|
||||||
|
|
||||||
while (!pending_destruction.empty()) {
|
while (!pending_destruction.empty()) {
|
||||||
// Delay at least 4 frames before destruction.
|
// Delay at least 4 frames before destruction.
|
||||||
// This is due to triple buffering happening on some drivers.
|
// This is due to triple buffering happening on some drivers.
|
||||||
static constexpr u64 epochs_to_destroy = 5;
|
static constexpr u64 epochs_to_destroy = 5;
|
||||||
if (pending_destruction.front()->GetEpoch() + epochs_to_destroy > epoch) {
|
if (pending_destruction.front()->Epoch() + epochs_to_destroy > epoch) {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
pending_destruction.pop_front();
|
pending_destruction.pop();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -249,23 +255,21 @@ public:
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
explicit BufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
|
explicit BufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
|
||||||
std::unique_ptr<StreamBuffer> stream_buffer)
|
std::unique_ptr<StreamBuffer> stream_buffer_)
|
||||||
: rasterizer{rasterizer}, system{system}, stream_buffer{std::move(stream_buffer)},
|
: rasterizer{rasterizer}, system{system}, stream_buffer{std::move(stream_buffer_)},
|
||||||
stream_buffer_handle{this->stream_buffer->GetHandle()} {}
|
stream_buffer_handle{stream_buffer->Handle()} {}
|
||||||
|
|
||||||
~BufferCache() = default;
|
~BufferCache() = default;
|
||||||
|
|
||||||
virtual BufferType ToHandle(const OwnerBuffer& storage) = 0;
|
virtual std::shared_ptr<Buffer> CreateBlock(VAddr cpu_addr, std::size_t size) = 0;
|
||||||
|
|
||||||
virtual OwnerBuffer CreateBlock(VAddr cpu_addr, std::size_t size) = 0;
|
virtual void UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||||
|
|
||||||
virtual void UploadBlockData(const OwnerBuffer& buffer, std::size_t offset, std::size_t size,
|
|
||||||
const u8* data) = 0;
|
const u8* data) = 0;
|
||||||
|
|
||||||
virtual void DownloadBlockData(const OwnerBuffer& buffer, std::size_t offset, std::size_t size,
|
virtual void DownloadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||||
u8* data) = 0;
|
u8* data) = 0;
|
||||||
|
|
||||||
virtual void CopyBlock(const OwnerBuffer& src, const OwnerBuffer& dst, std::size_t src_offset,
|
virtual void CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
|
||||||
std::size_t dst_offset, std::size_t size) = 0;
|
std::size_t dst_offset, std::size_t size) = 0;
|
||||||
|
|
||||||
virtual BufferInfo ConstBufferUpload(const void* raw_pointer, std::size_t size) {
|
virtual BufferInfo ConstBufferUpload(const void* raw_pointer, std::size_t size) {
|
||||||
|
@ -321,7 +325,7 @@ protected:
|
||||||
}
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
MapInterval* MapAddress(const OwnerBuffer& block, GPUVAddr gpu_addr, VAddr cpu_addr,
|
MapInterval* MapAddress(const Buffer* block, GPUVAddr gpu_addr, VAddr cpu_addr,
|
||||||
std::size_t size) {
|
std::size_t size) {
|
||||||
const VectorMapInterval overlaps = GetMapsInRange(cpu_addr, size);
|
const VectorMapInterval overlaps = GetMapsInRange(cpu_addr, size);
|
||||||
if (overlaps.empty()) {
|
if (overlaps.empty()) {
|
||||||
|
@ -329,11 +333,11 @@ private:
|
||||||
const VAddr cpu_addr_end = cpu_addr + size;
|
const VAddr cpu_addr_end = cpu_addr + size;
|
||||||
if (memory_manager.IsGranularRange(gpu_addr, size)) {
|
if (memory_manager.IsGranularRange(gpu_addr, size)) {
|
||||||
u8* host_ptr = memory_manager.GetPointer(gpu_addr);
|
u8* host_ptr = memory_manager.GetPointer(gpu_addr);
|
||||||
UploadBlockData(block, block->GetOffset(cpu_addr), size, host_ptr);
|
UploadBlockData(*block, block->Offset(cpu_addr), size, host_ptr);
|
||||||
} else {
|
} else {
|
||||||
staging_buffer.resize(size);
|
staging_buffer.resize(size);
|
||||||
memory_manager.ReadBlockUnsafe(gpu_addr, staging_buffer.data(), size);
|
memory_manager.ReadBlockUnsafe(gpu_addr, staging_buffer.data(), size);
|
||||||
UploadBlockData(block, block->GetOffset(cpu_addr), size, staging_buffer.data());
|
UploadBlockData(*block, block->Offset(cpu_addr), size, staging_buffer.data());
|
||||||
}
|
}
|
||||||
return Register(MapInterval(cpu_addr, cpu_addr_end, gpu_addr));
|
return Register(MapInterval(cpu_addr, cpu_addr_end, gpu_addr));
|
||||||
}
|
}
|
||||||
|
@ -376,7 +380,7 @@ private:
|
||||||
return map;
|
return map;
|
||||||
}
|
}
|
||||||
|
|
||||||
void UpdateBlock(const OwnerBuffer& block, VAddr start, VAddr end,
|
void UpdateBlock(const Buffer* block, VAddr start, VAddr end,
|
||||||
const VectorMapInterval& overlaps) {
|
const VectorMapInterval& overlaps) {
|
||||||
const IntervalType base_interval{start, end};
|
const IntervalType base_interval{start, end};
|
||||||
IntervalSet interval_set{};
|
IntervalSet interval_set{};
|
||||||
|
@ -386,13 +390,13 @@ private:
|
||||||
interval_set.subtract(subtract);
|
interval_set.subtract(subtract);
|
||||||
}
|
}
|
||||||
for (auto& interval : interval_set) {
|
for (auto& interval : interval_set) {
|
||||||
std::size_t size = interval.upper() - interval.lower();
|
const std::size_t size = interval.upper() - interval.lower();
|
||||||
if (size > 0) {
|
if (size == 0) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
staging_buffer.resize(size);
|
staging_buffer.resize(size);
|
||||||
system.Memory().ReadBlockUnsafe(interval.lower(), staging_buffer.data(), size);
|
system.Memory().ReadBlockUnsafe(interval.lower(), staging_buffer.data(), size);
|
||||||
UploadBlockData(block, block->GetOffset(interval.lower()), size,
|
UploadBlockData(*block, block->Offset(interval.lower()), size, staging_buffer.data());
|
||||||
staging_buffer.data());
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -422,10 +426,14 @@ private:
|
||||||
}
|
}
|
||||||
|
|
||||||
void FlushMap(MapInterval* map) {
|
void FlushMap(MapInterval* map) {
|
||||||
|
const auto it = blocks.find(map->start >> BLOCK_PAGE_BITS);
|
||||||
|
ASSERT_OR_EXECUTE(it != blocks.end(), return;);
|
||||||
|
|
||||||
|
std::shared_ptr<Buffer> block = it->second;
|
||||||
|
|
||||||
const std::size_t size = map->end - map->start;
|
const std::size_t size = map->end - map->start;
|
||||||
OwnerBuffer block = blocks[map->start >> block_page_bits];
|
|
||||||
staging_buffer.resize(size);
|
staging_buffer.resize(size);
|
||||||
DownloadBlockData(block, block->GetOffset(map->start), size, staging_buffer.data());
|
DownloadBlockData(*block, block->Offset(map->start), size, staging_buffer.data());
|
||||||
system.Memory().WriteBlockUnsafe(map->start, staging_buffer.data(), size);
|
system.Memory().WriteBlockUnsafe(map->start, staging_buffer.data(), size);
|
||||||
map->MarkAsModified(false, 0);
|
map->MarkAsModified(false, 0);
|
||||||
}
|
}
|
||||||
|
@ -448,97 +456,89 @@ private:
|
||||||
buffer_offset = offset_aligned;
|
buffer_offset = offset_aligned;
|
||||||
}
|
}
|
||||||
|
|
||||||
OwnerBuffer EnlargeBlock(OwnerBuffer buffer) {
|
std::shared_ptr<Buffer> EnlargeBlock(std::shared_ptr<Buffer> buffer) {
|
||||||
const std::size_t old_size = buffer->GetSize();
|
const std::size_t old_size = buffer->Size();
|
||||||
const std::size_t new_size = old_size + block_page_size;
|
const std::size_t new_size = old_size + BLOCK_PAGE_SIZE;
|
||||||
const VAddr cpu_addr = buffer->GetCpuAddr();
|
const VAddr cpu_addr = buffer->CpuAddr();
|
||||||
OwnerBuffer new_buffer = CreateBlock(cpu_addr, new_size);
|
std::shared_ptr<Buffer> new_buffer = CreateBlock(cpu_addr, new_size);
|
||||||
CopyBlock(buffer, new_buffer, 0, 0, old_size);
|
CopyBlock(*buffer, *new_buffer, 0, 0, old_size);
|
||||||
buffer->SetEpoch(epoch);
|
QueueDestruction(std::move(buffer));
|
||||||
pending_destruction.push_back(buffer);
|
|
||||||
const VAddr cpu_addr_end = cpu_addr + new_size - 1;
|
const VAddr cpu_addr_end = cpu_addr + new_size - 1;
|
||||||
u64 page_start = cpu_addr >> block_page_bits;
|
const u64 page_end = cpu_addr_end >> BLOCK_PAGE_BITS;
|
||||||
const u64 page_end = cpu_addr_end >> block_page_bits;
|
for (u64 page_start = cpu_addr >> BLOCK_PAGE_BITS; page_start <= page_end; ++page_start) {
|
||||||
while (page_start <= page_end) {
|
blocks.insert_or_assign(page_start, new_buffer);
|
||||||
blocks[page_start] = new_buffer;
|
|
||||||
++page_start;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return new_buffer;
|
return new_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
OwnerBuffer MergeBlocks(OwnerBuffer first, OwnerBuffer second) {
|
std::shared_ptr<Buffer> MergeBlocks(std::shared_ptr<Buffer> first,
|
||||||
const std::size_t size_1 = first->GetSize();
|
std::shared_ptr<Buffer> second) {
|
||||||
const std::size_t size_2 = second->GetSize();
|
const std::size_t size_1 = first->Size();
|
||||||
const VAddr first_addr = first->GetCpuAddr();
|
const std::size_t size_2 = second->Size();
|
||||||
const VAddr second_addr = second->GetCpuAddr();
|
const VAddr first_addr = first->CpuAddr();
|
||||||
|
const VAddr second_addr = second->CpuAddr();
|
||||||
const VAddr new_addr = std::min(first_addr, second_addr);
|
const VAddr new_addr = std::min(first_addr, second_addr);
|
||||||
const std::size_t new_size = size_1 + size_2;
|
const std::size_t new_size = size_1 + size_2;
|
||||||
OwnerBuffer new_buffer = CreateBlock(new_addr, new_size);
|
|
||||||
CopyBlock(first, new_buffer, 0, new_buffer->GetOffset(first_addr), size_1);
|
std::shared_ptr<Buffer> new_buffer = CreateBlock(new_addr, new_size);
|
||||||
CopyBlock(second, new_buffer, 0, new_buffer->GetOffset(second_addr), size_2);
|
CopyBlock(*first, *new_buffer, 0, new_buffer->Offset(first_addr), size_1);
|
||||||
first->SetEpoch(epoch);
|
CopyBlock(*second, *new_buffer, 0, new_buffer->Offset(second_addr), size_2);
|
||||||
second->SetEpoch(epoch);
|
QueueDestruction(std::move(first));
|
||||||
pending_destruction.push_back(first);
|
QueueDestruction(std::move(second));
|
||||||
pending_destruction.push_back(second);
|
|
||||||
const VAddr cpu_addr_end = new_addr + new_size - 1;
|
const VAddr cpu_addr_end = new_addr + new_size - 1;
|
||||||
u64 page_start = new_addr >> block_page_bits;
|
const u64 page_end = cpu_addr_end >> BLOCK_PAGE_BITS;
|
||||||
const u64 page_end = cpu_addr_end >> block_page_bits;
|
for (u64 page_start = new_addr >> BLOCK_PAGE_BITS; page_start <= page_end; ++page_start) {
|
||||||
while (page_start <= page_end) {
|
blocks.insert_or_assign(page_start, new_buffer);
|
||||||
blocks[page_start] = new_buffer;
|
|
||||||
++page_start;
|
|
||||||
}
|
}
|
||||||
return new_buffer;
|
return new_buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
OwnerBuffer GetBlock(const VAddr cpu_addr, const std::size_t size) {
|
Buffer* GetBlock(VAddr cpu_addr, std::size_t size) {
|
||||||
OwnerBuffer found;
|
std::shared_ptr<Buffer> found;
|
||||||
|
|
||||||
const VAddr cpu_addr_end = cpu_addr + size - 1;
|
const VAddr cpu_addr_end = cpu_addr + size - 1;
|
||||||
u64 page_start = cpu_addr >> block_page_bits;
|
const u64 page_end = cpu_addr_end >> BLOCK_PAGE_BITS;
|
||||||
const u64 page_end = cpu_addr_end >> block_page_bits;
|
for (u64 page_start = cpu_addr >> BLOCK_PAGE_BITS; page_start <= page_end; ++page_start) {
|
||||||
while (page_start <= page_end) {
|
|
||||||
auto it = blocks.find(page_start);
|
auto it = blocks.find(page_start);
|
||||||
if (it == blocks.end()) {
|
if (it == blocks.end()) {
|
||||||
if (found) {
|
if (found) {
|
||||||
found = EnlargeBlock(found);
|
found = EnlargeBlock(found);
|
||||||
} else {
|
|
||||||
const VAddr start_addr = (page_start << block_page_bits);
|
|
||||||
found = CreateBlock(start_addr, block_page_size);
|
|
||||||
blocks[page_start] = found;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (found) {
|
|
||||||
if (found == it->second) {
|
|
||||||
++page_start;
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
found = MergeBlocks(found, it->second);
|
const VAddr start_addr = page_start << BLOCK_PAGE_BITS;
|
||||||
} else {
|
found = CreateBlock(start_addr, BLOCK_PAGE_SIZE);
|
||||||
|
blocks.insert_or_assign(page_start, found);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (!found) {
|
||||||
found = it->second;
|
found = it->second;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
if (found != it->second) {
|
||||||
|
found = MergeBlocks(std::move(found), it->second);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++page_start;
|
return found.get();
|
||||||
}
|
|
||||||
return found;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void MarkRegionAsWritten(const VAddr start, const VAddr end) {
|
void MarkRegionAsWritten(VAddr start, VAddr end) {
|
||||||
u64 page_start = start >> write_page_bit;
|
const u64 page_end = end >> WRITE_PAGE_BIT;
|
||||||
const u64 page_end = end >> write_page_bit;
|
for (u64 page_start = start >> WRITE_PAGE_BIT; page_start <= page_end; ++page_start) {
|
||||||
while (page_start <= page_end) {
|
|
||||||
auto it = written_pages.find(page_start);
|
auto it = written_pages.find(page_start);
|
||||||
if (it != written_pages.end()) {
|
if (it != written_pages.end()) {
|
||||||
it->second = it->second + 1;
|
it->second = it->second + 1;
|
||||||
} else {
|
} else {
|
||||||
written_pages[page_start] = 1;
|
written_pages.insert_or_assign(page_start, 1);
|
||||||
}
|
}
|
||||||
++page_start;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void UnmarkRegionAsWritten(const VAddr start, const VAddr end) {
|
void UnmarkRegionAsWritten(VAddr start, VAddr end) {
|
||||||
u64 page_start = start >> write_page_bit;
|
const u64 page_end = end >> WRITE_PAGE_BIT;
|
||||||
const u64 page_end = end >> write_page_bit;
|
for (u64 page_start = start >> WRITE_PAGE_BIT; page_start <= page_end; ++page_start) {
|
||||||
while (page_start <= page_end) {
|
|
||||||
auto it = written_pages.find(page_start);
|
auto it = written_pages.find(page_start);
|
||||||
if (it != written_pages.end()) {
|
if (it != written_pages.end()) {
|
||||||
if (it->second > 1) {
|
if (it->second > 1) {
|
||||||
|
@ -547,22 +547,24 @@ private:
|
||||||
written_pages.erase(it);
|
written_pages.erase(it);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
++page_start;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool IsRegionWritten(const VAddr start, const VAddr end) const {
|
bool IsRegionWritten(VAddr start, VAddr end) const {
|
||||||
u64 page_start = start >> write_page_bit;
|
const u64 page_end = end >> WRITE_PAGE_BIT;
|
||||||
const u64 page_end = end >> write_page_bit;
|
for (u64 page_start = start >> WRITE_PAGE_BIT; page_start <= page_end; ++page_start) {
|
||||||
while (page_start <= page_end) {
|
|
||||||
if (written_pages.count(page_start) > 0) {
|
if (written_pages.count(page_start) > 0) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
++page_start;
|
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void QueueDestruction(std::shared_ptr<Buffer> buffer) {
|
||||||
|
buffer->SetEpoch(epoch);
|
||||||
|
pending_destruction.push(std::move(buffer));
|
||||||
|
}
|
||||||
|
|
||||||
void MarkForAsyncFlush(MapInterval* map) {
|
void MarkForAsyncFlush(MapInterval* map) {
|
||||||
if (!uncommitted_flushes) {
|
if (!uncommitted_flushes) {
|
||||||
uncommitted_flushes = std::make_shared<std::unordered_set<MapInterval*>>();
|
uncommitted_flushes = std::make_shared<std::unordered_set<MapInterval*>>();
|
||||||
|
@ -574,7 +576,7 @@ private:
|
||||||
Core::System& system;
|
Core::System& system;
|
||||||
|
|
||||||
std::unique_ptr<StreamBuffer> stream_buffer;
|
std::unique_ptr<StreamBuffer> stream_buffer;
|
||||||
BufferType stream_buffer_handle{};
|
BufferType stream_buffer_handle;
|
||||||
|
|
||||||
bool invalidated = false;
|
bool invalidated = false;
|
||||||
|
|
||||||
|
@ -586,18 +588,15 @@ private:
|
||||||
boost::intrusive::set<MapInterval, boost::intrusive::compare<MapIntervalCompare>>
|
boost::intrusive::set<MapInterval, boost::intrusive::compare<MapIntervalCompare>>
|
||||||
mapped_addresses;
|
mapped_addresses;
|
||||||
|
|
||||||
static constexpr u64 write_page_bit = 11;
|
|
||||||
std::unordered_map<u64, u32> written_pages;
|
std::unordered_map<u64, u32> written_pages;
|
||||||
|
std::unordered_map<u64, std::shared_ptr<Buffer>> blocks;
|
||||||
|
|
||||||
static constexpr u64 block_page_bits = 21;
|
std::queue<std::shared_ptr<Buffer>> pending_destruction;
|
||||||
static constexpr u64 block_page_size = 1ULL << block_page_bits;
|
|
||||||
std::unordered_map<u64, OwnerBuffer> blocks;
|
|
||||||
|
|
||||||
std::list<OwnerBuffer> pending_destruction;
|
|
||||||
u64 epoch = 0;
|
u64 epoch = 0;
|
||||||
u64 modified_ticks = 0;
|
u64 modified_ticks = 0;
|
||||||
|
|
||||||
std::vector<u8> staging_buffer;
|
std::vector<u8> staging_buffer;
|
||||||
|
|
||||||
std::list<MapInterval*> marked_for_unregister;
|
std::list<MapInterval*> marked_for_unregister;
|
||||||
|
|
||||||
std::shared_ptr<std::unordered_set<MapInterval*>> uncommitted_flushes;
|
std::shared_ptr<std::unordered_set<MapInterval*>> uncommitted_flushes;
|
||||||
|
|
|
@ -22,13 +22,12 @@ using Maxwell = Tegra::Engines::Maxwell3D::Regs;
|
||||||
|
|
||||||
MICROPROFILE_DEFINE(OpenGL_Buffer_Download, "OpenGL", "Buffer Download", MP_RGB(192, 192, 128));
|
MICROPROFILE_DEFINE(OpenGL_Buffer_Download, "OpenGL", "Buffer Download", MP_RGB(192, 192, 128));
|
||||||
|
|
||||||
CachedBufferBlock::CachedBufferBlock(VAddr cpu_addr, const std::size_t size)
|
Buffer::Buffer(VAddr cpu_addr, const std::size_t size) : VideoCommon::BufferBlock{cpu_addr, size} {
|
||||||
: VideoCommon::BufferBlock{cpu_addr, size} {
|
|
||||||
gl_buffer.Create();
|
gl_buffer.Create();
|
||||||
glNamedBufferData(gl_buffer.handle, static_cast<GLsizeiptr>(size), nullptr, GL_DYNAMIC_DRAW);
|
glNamedBufferData(gl_buffer.handle, static_cast<GLsizeiptr>(size), nullptr, GL_DYNAMIC_DRAW);
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedBufferBlock::~CachedBufferBlock() = default;
|
Buffer::~Buffer() = default;
|
||||||
|
|
||||||
OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
|
OGLBufferCache::OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
|
||||||
const Device& device, std::size_t stream_size)
|
const Device& device, std::size_t stream_size)
|
||||||
|
@ -48,12 +47,8 @@ OGLBufferCache::~OGLBufferCache() {
|
||||||
glDeleteBuffers(static_cast<GLsizei>(std::size(cbufs)), std::data(cbufs));
|
glDeleteBuffers(static_cast<GLsizei>(std::size(cbufs)), std::data(cbufs));
|
||||||
}
|
}
|
||||||
|
|
||||||
Buffer OGLBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) {
|
std::shared_ptr<Buffer> OGLBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) {
|
||||||
return std::make_shared<CachedBufferBlock>(cpu_addr, size);
|
return std::make_shared<Buffer>(cpu_addr, size);
|
||||||
}
|
|
||||||
|
|
||||||
GLuint OGLBufferCache::ToHandle(const Buffer& buffer) {
|
|
||||||
return buffer->GetHandle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint OGLBufferCache::GetEmptyBuffer(std::size_t) {
|
GLuint OGLBufferCache::GetEmptyBuffer(std::size_t) {
|
||||||
|
@ -62,7 +57,7 @@ GLuint OGLBufferCache::GetEmptyBuffer(std::size_t) {
|
||||||
|
|
||||||
void OGLBufferCache::UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
void OGLBufferCache::UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||||
const u8* data) {
|
const u8* data) {
|
||||||
glNamedBufferSubData(buffer->GetHandle(), static_cast<GLintptr>(offset),
|
glNamedBufferSubData(buffer.Handle(), static_cast<GLintptr>(offset),
|
||||||
static_cast<GLsizeiptr>(size), data);
|
static_cast<GLsizeiptr>(size), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -70,20 +65,20 @@ void OGLBufferCache::DownloadBlockData(const Buffer& buffer, std::size_t offset,
|
||||||
u8* data) {
|
u8* data) {
|
||||||
MICROPROFILE_SCOPE(OpenGL_Buffer_Download);
|
MICROPROFILE_SCOPE(OpenGL_Buffer_Download);
|
||||||
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
|
glMemoryBarrier(GL_BUFFER_UPDATE_BARRIER_BIT);
|
||||||
glGetNamedBufferSubData(buffer->GetHandle(), static_cast<GLintptr>(offset),
|
glGetNamedBufferSubData(buffer.Handle(), static_cast<GLintptr>(offset),
|
||||||
static_cast<GLsizeiptr>(size), data);
|
static_cast<GLsizeiptr>(size), data);
|
||||||
}
|
}
|
||||||
|
|
||||||
void OGLBufferCache::CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
|
void OGLBufferCache::CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
|
||||||
std::size_t dst_offset, std::size_t size) {
|
std::size_t dst_offset, std::size_t size) {
|
||||||
glCopyNamedBufferSubData(src->GetHandle(), dst->GetHandle(), static_cast<GLintptr>(src_offset),
|
glCopyNamedBufferSubData(src.Handle(), dst.Handle(), static_cast<GLintptr>(src_offset),
|
||||||
static_cast<GLintptr>(dst_offset), static_cast<GLsizeiptr>(size));
|
static_cast<GLintptr>(dst_offset), static_cast<GLsizeiptr>(size));
|
||||||
}
|
}
|
||||||
|
|
||||||
OGLBufferCache::BufferInfo OGLBufferCache::ConstBufferUpload(const void* raw_pointer,
|
OGLBufferCache::BufferInfo OGLBufferCache::ConstBufferUpload(const void* raw_pointer,
|
||||||
std::size_t size) {
|
std::size_t size) {
|
||||||
DEBUG_ASSERT(cbuf_cursor < std::size(cbufs));
|
DEBUG_ASSERT(cbuf_cursor < std::size(cbufs));
|
||||||
const GLuint& cbuf = cbufs[cbuf_cursor++];
|
const GLuint cbuf = cbufs[cbuf_cursor++];
|
||||||
glNamedBufferSubData(cbuf, 0, static_cast<GLsizeiptr>(size), raw_pointer);
|
glNamedBufferSubData(cbuf, 0, static_cast<GLsizeiptr>(size), raw_pointer);
|
||||||
return {cbuf, 0};
|
return {cbuf, 0};
|
||||||
}
|
}
|
||||||
|
|
|
@ -24,17 +24,12 @@ class Device;
|
||||||
class OGLStreamBuffer;
|
class OGLStreamBuffer;
|
||||||
class RasterizerOpenGL;
|
class RasterizerOpenGL;
|
||||||
|
|
||||||
class CachedBufferBlock;
|
class Buffer : public VideoCommon::BufferBlock {
|
||||||
|
|
||||||
using Buffer = std::shared_ptr<CachedBufferBlock>;
|
|
||||||
using GenericBufferCache = VideoCommon::BufferCache<Buffer, GLuint, OGLStreamBuffer>;
|
|
||||||
|
|
||||||
class CachedBufferBlock : public VideoCommon::BufferBlock {
|
|
||||||
public:
|
public:
|
||||||
explicit CachedBufferBlock(VAddr cpu_addr, const std::size_t size);
|
explicit Buffer(VAddr cpu_addr, const std::size_t size);
|
||||||
~CachedBufferBlock();
|
~Buffer();
|
||||||
|
|
||||||
GLuint GetHandle() const {
|
GLuint Handle() const {
|
||||||
return gl_buffer.handle;
|
return gl_buffer.handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -42,6 +37,7 @@ private:
|
||||||
OGLBuffer gl_buffer;
|
OGLBuffer gl_buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
using GenericBufferCache = VideoCommon::BufferCache<Buffer, GLuint, OGLStreamBuffer>;
|
||||||
class OGLBufferCache final : public GenericBufferCache {
|
class OGLBufferCache final : public GenericBufferCache {
|
||||||
public:
|
public:
|
||||||
explicit OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
|
explicit OGLBufferCache(RasterizerOpenGL& rasterizer, Core::System& system,
|
||||||
|
@ -55,9 +51,7 @@ public:
|
||||||
}
|
}
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
Buffer CreateBlock(VAddr cpu_addr, std::size_t size) override;
|
std::shared_ptr<Buffer> CreateBlock(VAddr cpu_addr, std::size_t size) override;
|
||||||
|
|
||||||
GLuint ToHandle(const Buffer& buffer) override;
|
|
||||||
|
|
||||||
void UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
void UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||||
const u8* data) override;
|
const u8* data) override;
|
||||||
|
|
|
@ -49,14 +49,6 @@ OGLStreamBuffer::~OGLStreamBuffer() {
|
||||||
gl_buffer.Release();
|
gl_buffer.Release();
|
||||||
}
|
}
|
||||||
|
|
||||||
GLuint OGLStreamBuffer::GetHandle() const {
|
|
||||||
return gl_buffer.handle;
|
|
||||||
}
|
|
||||||
|
|
||||||
GLsizeiptr OGLStreamBuffer::GetSize() const {
|
|
||||||
return buffer_size;
|
|
||||||
}
|
|
||||||
|
|
||||||
std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr alignment) {
|
std::tuple<u8*, GLintptr, bool> OGLStreamBuffer::Map(GLsizeiptr size, GLintptr alignment) {
|
||||||
ASSERT(size <= buffer_size);
|
ASSERT(size <= buffer_size);
|
||||||
ASSERT(alignment <= buffer_size);
|
ASSERT(alignment <= buffer_size);
|
||||||
|
|
|
@ -17,9 +17,6 @@ public:
|
||||||
bool use_persistent = true);
|
bool use_persistent = true);
|
||||||
~OGLStreamBuffer();
|
~OGLStreamBuffer();
|
||||||
|
|
||||||
GLuint GetHandle() const;
|
|
||||||
GLsizeiptr GetSize() const;
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Allocates a linear chunk of memory in the GPU buffer with at least "size" bytes
|
* Allocates a linear chunk of memory in the GPU buffer with at least "size" bytes
|
||||||
* and the optional alignment requirement.
|
* and the optional alignment requirement.
|
||||||
|
@ -32,6 +29,14 @@ public:
|
||||||
|
|
||||||
void Unmap(GLsizeiptr size);
|
void Unmap(GLsizeiptr size);
|
||||||
|
|
||||||
|
GLuint Handle() const {
|
||||||
|
return gl_buffer.handle;
|
||||||
|
}
|
||||||
|
|
||||||
|
GLsizeiptr Size() const {
|
||||||
|
return buffer_size;
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
OGLBuffer gl_buffer;
|
OGLBuffer gl_buffer;
|
||||||
|
|
||||||
|
|
|
@ -37,8 +37,8 @@ std::unique_ptr<VKStreamBuffer> CreateStreamBuffer(const VKDevice& device, VKSch
|
||||||
|
|
||||||
} // Anonymous namespace
|
} // Anonymous namespace
|
||||||
|
|
||||||
CachedBufferBlock::CachedBufferBlock(const VKDevice& device, VKMemoryManager& memory_manager,
|
Buffer::Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VAddr cpu_addr,
|
||||||
VAddr cpu_addr, std::size_t size)
|
std::size_t size)
|
||||||
: VideoCommon::BufferBlock{cpu_addr, size} {
|
: VideoCommon::BufferBlock{cpu_addr, size} {
|
||||||
VkBufferCreateInfo ci;
|
VkBufferCreateInfo ci;
|
||||||
ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
ci.sType = VK_STRUCTURE_TYPE_BUFFER_CREATE_INFO;
|
||||||
|
@ -54,7 +54,7 @@ CachedBufferBlock::CachedBufferBlock(const VKDevice& device, VKMemoryManager& me
|
||||||
buffer.commit = memory_manager.Commit(buffer.handle, false);
|
buffer.commit = memory_manager.Commit(buffer.handle, false);
|
||||||
}
|
}
|
||||||
|
|
||||||
CachedBufferBlock::~CachedBufferBlock() = default;
|
Buffer::~Buffer() = default;
|
||||||
|
|
||||||
VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
|
VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
|
||||||
const VKDevice& device, VKMemoryManager& memory_manager,
|
const VKDevice& device, VKMemoryManager& memory_manager,
|
||||||
|
@ -67,12 +67,8 @@ VKBufferCache::VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::S
|
||||||
|
|
||||||
VKBufferCache::~VKBufferCache() = default;
|
VKBufferCache::~VKBufferCache() = default;
|
||||||
|
|
||||||
Buffer VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) {
|
std::shared_ptr<Buffer> VKBufferCache::CreateBlock(VAddr cpu_addr, std::size_t size) {
|
||||||
return std::make_shared<CachedBufferBlock>(device, memory_manager, cpu_addr, size);
|
return std::make_shared<Buffer>(device, memory_manager, cpu_addr, size);
|
||||||
}
|
|
||||||
|
|
||||||
VkBuffer VKBufferCache::ToHandle(const Buffer& buffer) {
|
|
||||||
return buffer->GetHandle();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
VkBuffer VKBufferCache::GetEmptyBuffer(std::size_t size) {
|
VkBuffer VKBufferCache::GetEmptyBuffer(std::size_t size) {
|
||||||
|
@ -91,7 +87,7 @@ void VKBufferCache::UploadBlockData(const Buffer& buffer, std::size_t offset, st
|
||||||
std::memcpy(staging.commit->Map(size), data, size);
|
std::memcpy(staging.commit->Map(size), data, size);
|
||||||
|
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
scheduler.Record([staging = *staging.handle, buffer = buffer->GetHandle(), offset,
|
scheduler.Record([staging = *staging.handle, buffer = buffer.Handle(), offset,
|
||||||
size](vk::CommandBuffer cmdbuf) {
|
size](vk::CommandBuffer cmdbuf) {
|
||||||
cmdbuf.CopyBuffer(staging, buffer, VkBufferCopy{0, offset, size});
|
cmdbuf.CopyBuffer(staging, buffer, VkBufferCopy{0, offset, size});
|
||||||
|
|
||||||
|
@ -114,7 +110,7 @@ void VKBufferCache::DownloadBlockData(const Buffer& buffer, std::size_t offset,
|
||||||
u8* data) {
|
u8* data) {
|
||||||
const auto& staging = staging_pool.GetUnusedBuffer(size, true);
|
const auto& staging = staging_pool.GetUnusedBuffer(size, true);
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
scheduler.Record([staging = *staging.handle, buffer = buffer->GetHandle(), offset,
|
scheduler.Record([staging = *staging.handle, buffer = buffer.Handle(), offset,
|
||||||
size](vk::CommandBuffer cmdbuf) {
|
size](vk::CommandBuffer cmdbuf) {
|
||||||
VkBufferMemoryBarrier barrier;
|
VkBufferMemoryBarrier barrier;
|
||||||
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
|
barrier.sType = VK_STRUCTURE_TYPE_BUFFER_MEMORY_BARRIER;
|
||||||
|
@ -141,8 +137,8 @@ void VKBufferCache::DownloadBlockData(const Buffer& buffer, std::size_t offset,
|
||||||
void VKBufferCache::CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
|
void VKBufferCache::CopyBlock(const Buffer& src, const Buffer& dst, std::size_t src_offset,
|
||||||
std::size_t dst_offset, std::size_t size) {
|
std::size_t dst_offset, std::size_t size) {
|
||||||
scheduler.RequestOutsideRenderPassOperationContext();
|
scheduler.RequestOutsideRenderPassOperationContext();
|
||||||
scheduler.Record([src_buffer = src->GetHandle(), dst_buffer = dst->GetHandle(), src_offset,
|
scheduler.Record([src_buffer = src.Handle(), dst_buffer = dst.Handle(), src_offset, dst_offset,
|
||||||
dst_offset, size](vk::CommandBuffer cmdbuf) {
|
size](vk::CommandBuffer cmdbuf) {
|
||||||
cmdbuf.CopyBuffer(src_buffer, dst_buffer, VkBufferCopy{src_offset, dst_offset, size});
|
cmdbuf.CopyBuffer(src_buffer, dst_buffer, VkBufferCopy{src_offset, dst_offset, size});
|
||||||
|
|
||||||
std::array<VkBufferMemoryBarrier, 2> barriers;
|
std::array<VkBufferMemoryBarrier, 2> barriers;
|
||||||
|
|
|
@ -24,13 +24,13 @@ class VKDevice;
|
||||||
class VKMemoryManager;
|
class VKMemoryManager;
|
||||||
class VKScheduler;
|
class VKScheduler;
|
||||||
|
|
||||||
class CachedBufferBlock final : public VideoCommon::BufferBlock {
|
class Buffer final : public VideoCommon::BufferBlock {
|
||||||
public:
|
public:
|
||||||
explicit CachedBufferBlock(const VKDevice& device, VKMemoryManager& memory_manager,
|
explicit Buffer(const VKDevice& device, VKMemoryManager& memory_manager, VAddr cpu_addr,
|
||||||
VAddr cpu_addr, std::size_t size);
|
std::size_t size);
|
||||||
~CachedBufferBlock();
|
~Buffer();
|
||||||
|
|
||||||
VkBuffer GetHandle() const {
|
VkBuffer Handle() const {
|
||||||
return *buffer.handle;
|
return *buffer.handle;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -38,8 +38,6 @@ private:
|
||||||
VKBuffer buffer;
|
VKBuffer buffer;
|
||||||
};
|
};
|
||||||
|
|
||||||
using Buffer = std::shared_ptr<CachedBufferBlock>;
|
|
||||||
|
|
||||||
class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> {
|
class VKBufferCache final : public VideoCommon::BufferCache<Buffer, VkBuffer, VKStreamBuffer> {
|
||||||
public:
|
public:
|
||||||
explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
|
explicit VKBufferCache(VideoCore::RasterizerInterface& rasterizer, Core::System& system,
|
||||||
|
@ -50,9 +48,7 @@ public:
|
||||||
VkBuffer GetEmptyBuffer(std::size_t size) override;
|
VkBuffer GetEmptyBuffer(std::size_t size) override;
|
||||||
|
|
||||||
protected:
|
protected:
|
||||||
VkBuffer ToHandle(const Buffer& buffer) override;
|
std::shared_ptr<Buffer> CreateBlock(VAddr cpu_addr, std::size_t size) override;
|
||||||
|
|
||||||
Buffer CreateBlock(VAddr cpu_addr, std::size_t size) override;
|
|
||||||
|
|
||||||
void UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
void UploadBlockData(const Buffer& buffer, std::size_t offset, std::size_t size,
|
||||||
const u8* data) override;
|
const u8* data) override;
|
||||||
|
|
|
@ -35,7 +35,7 @@ public:
|
||||||
/// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy.
|
/// Ensures that "size" bytes of memory are available to the GPU, potentially recording a copy.
|
||||||
void Unmap(u64 size);
|
void Unmap(u64 size);
|
||||||
|
|
||||||
VkBuffer GetHandle() const {
|
VkBuffer Handle() const {
|
||||||
return *buffer;
|
return *buffer;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue