mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-28 13:28:01 +03:00
119 lines
3.1 KiB
C++
119 lines
3.1 KiB
C++
#pragma once
|
|
|
|
#include <util/types.hpp>
|
|
#include "Utilities/address_range.h"
|
|
|
|
namespace rsx
|
|
{
|
|
template <typename Traits, int BlockSize>
|
|
class surface_cache_dma
|
|
{
|
|
protected:
|
|
static inline u32 block_for(u32 address)
|
|
{
|
|
return address / BlockSize;
|
|
}
|
|
|
|
static inline u32 block_address(u32 block_id)
|
|
{
|
|
return block_id * BlockSize;
|
|
}
|
|
|
|
using buffer_object_storage_type = typename Traits::buffer_object_storage_type;
|
|
using buffer_object_type = typename Traits::buffer_object_type;
|
|
using command_list_type = typename Traits::command_list_type;
|
|
|
|
struct memory_buffer_entry_t
|
|
{
|
|
u32 id;
|
|
buffer_object_storage_type bo;
|
|
u64 memory_tag = 0;
|
|
u32 base_address = 0;
|
|
|
|
inline buffer_object_type get() { return Traits::get(bo); }
|
|
inline operator bool () const { return base_address != 0; }
|
|
|
|
inline void release() { bo.release(); }
|
|
inline void acquire(buffer_object_type b) { bo = b; }
|
|
};
|
|
|
|
using buffer_block_array = typename std::array<memory_buffer_entry_t, 0x100000000ull / BlockSize>;
|
|
buffer_block_array m_buffer_list;
|
|
|
|
public:
|
|
surface_cache_dma()
|
|
{
|
|
for (usz i = 0; i < m_buffer_list.size(); ++i)
|
|
{
|
|
m_buffer_list[i].id = i;
|
|
}
|
|
}
|
|
|
|
surface_cache_dma& with_range(command_list_type cmd, const utils::address_range& range)
|
|
{
|
|
// Prepare underlying memory so that the range specified is provisioned and contiguous
|
|
// 1. Check if we have a pre-existing bo layer
|
|
const auto& this_entry = m_buffer_list[block_for(range.start)];
|
|
if (this_entry)
|
|
{
|
|
const auto bo = this_entry.get();
|
|
const auto buffer_range = utils::address_range::start_length(bo.base_address, ::size32(*bo));
|
|
|
|
if (range.inside(buffer_range))
|
|
{
|
|
// All is well
|
|
return *this;
|
|
}
|
|
}
|
|
|
|
// Data does not exist or is not contiguous. Merge the layer
|
|
std::vector<buffer_object_type> bo_list;
|
|
const auto start_address = this_entry ? this_entry.base_address : block_address(this_entry.id);
|
|
|
|
for (u32 address = start_address; address <= range.end;)
|
|
{
|
|
auto& bo_storage = m_buffer_list[block_for(address)];
|
|
bo_storage.base_address = start_address;
|
|
|
|
if (auto bo = bo_storage.get())
|
|
{
|
|
bo_list.push_back(bo);
|
|
bo_storage.release();
|
|
address += ::size32(*bo);
|
|
continue;
|
|
}
|
|
|
|
bo_list.push_back(nullptr);
|
|
address += BlockSize;
|
|
}
|
|
|
|
auto unified = Traits::template merge_bo_list<BlockSize>(cmd, bo_list);
|
|
ensure(unified);
|
|
|
|
m_buffer_list[block_for(start_address)].acquire(unified);
|
|
return *this;
|
|
}
|
|
|
|
utils::address_range to_block_range(const utils::address_range& range)
|
|
{
|
|
u32 start = block_address(block_for(range.start));
|
|
u32 end = block_address(block_for(range.end + BlockSize - 1));
|
|
return utils::address_range::start_end(start, end - 1);
|
|
}
|
|
|
|
std::tuple<buffer_object_type, u32, u64> get(u32 address)
|
|
{
|
|
const auto& block = m_buffer_list[block_for(address)];
|
|
return { block.get(), block.base_address - address };
|
|
}
|
|
|
|
void touch(const utils::address_range& range)
|
|
{
|
|
const u64 stamp = rsx::get_shared_tag();
|
|
for (usz i = block_for(range.start); i <= block_for(range.end); i++)
|
|
{
|
|
m_buffer_list[i].memory_tag = stamp;
|
|
}
|
|
}
|
|
};
|
|
}
|