mirror of
https://github.com/RPCSX/rpcsx.git
synced 2026-01-01 22:30:08 +01:00
107 lines
2.6 KiB
C++
107 lines
2.6 KiB
C++
#pragma once
|
|
|
|
#include <util/types.hpp>
|
|
#include "../RSXThread.h"
|
|
|
|
namespace rsx
|
|
{
|
|
template<bool IsFullLock = false, uint Stride = 128>
|
|
class reservation_lock
|
|
{
|
|
u32 addr = 0;
|
|
u32 length = 0;
|
|
|
|
inline void lock_range(u32 addr, u32 length)
|
|
{
|
|
if (!get_current_renderer()->iomap_table.lock<IsFullLock, Stride>(addr, length, get_current_cpu_thread()))
|
|
{
|
|
length = 0;
|
|
}
|
|
|
|
this->addr = addr;
|
|
this->length = length;
|
|
}
|
|
|
|
public:
|
|
reservation_lock(u32 addr, u32 length)
|
|
{
|
|
if (g_cfg.core.rsx_accurate_res_access &&
|
|
addr < constants::local_mem_base)
|
|
{
|
|
lock_range(addr, length);
|
|
}
|
|
}
|
|
|
|
reservation_lock(u32 addr, u32 length, bool setting)
|
|
{
|
|
if (setting)
|
|
{
|
|
lock_range(addr, length);
|
|
}
|
|
}
|
|
|
|
// Multi-range lock. If ranges overlap, the combined range will be acquired.
|
|
// If ranges do not overlap, the first range that is in main memory will be acquired.
|
|
reservation_lock(u32 dst_addr, u32 dst_length, u32 src_addr, u32 src_length)
|
|
{
|
|
if (g_cfg.core.rsx_accurate_res_access)
|
|
{
|
|
const auto range1 = utils::address_range::start_length(dst_addr, dst_length);
|
|
const auto range2 = utils::address_range::start_length(src_addr, src_length);
|
|
utils::address_range target_range;
|
|
|
|
if (!range1.overlaps(range2)) [[likely]]
|
|
{
|
|
target_range = (dst_addr < constants::local_mem_base) ? range1 : range2;
|
|
}
|
|
else
|
|
{
|
|
// Very unlikely
|
|
target_range = range1.get_min_max(range2);
|
|
}
|
|
|
|
if (target_range.start < constants::local_mem_base)
|
|
{
|
|
lock_range(target_range.start, target_range.length());
|
|
}
|
|
}
|
|
}
|
|
|
|
// Very special utility for batched transfers (SPU related)
|
|
template <typename T = void>
|
|
void update_if_enabled(u32 addr, u32 _length, const std::add_pointer_t<T>& lock_release = std::add_pointer_t<void>{})
|
|
{
|
|
// This check is not perfect but it covers the important cases fast (this check is only an optimization - forcing true disables it)
|
|
if (length && (this->addr / rsx_iomap_table::c_lock_stride != addr / rsx_iomap_table::c_lock_stride || (addr % rsx_iomap_table::c_lock_stride + _length) > rsx_iomap_table::c_lock_stride) && _length > 1)
|
|
{
|
|
if constexpr (!std::is_void_v<T>)
|
|
{
|
|
// See SPUThread.cpp
|
|
lock_release->release(0);
|
|
}
|
|
|
|
unlock();
|
|
lock_range(addr, _length);
|
|
}
|
|
}
|
|
|
|
void unlock(bool destructor = false)
|
|
{
|
|
if (length)
|
|
{
|
|
get_current_renderer()->iomap_table.unlock<IsFullLock, Stride>(addr, length);
|
|
|
|
if (!destructor)
|
|
{
|
|
length = 0;
|
|
}
|
|
}
|
|
}
|
|
|
|
~reservation_lock()
|
|
{
|
|
unlock(true);
|
|
}
|
|
};
|
|
}
|