mirror of
https://github.com/RPCS3/rpcs3.git
synced 2025-04-21 03:55:32 +00:00
Merge branch 'master' into myfix
This commit is contained in:
commit
37bf1acbbe
23 changed files with 305 additions and 119 deletions
|
@ -19,7 +19,7 @@ The following tools are required to build RPCS3 on Windows 10 or later:
|
|||
with standalone **CMake** tool.
|
||||
|
||||
- [Python 3.6+](https://www.python.org/downloads/) (add to PATH)
|
||||
- [Qt 6.7.3](https://www.qt.io/download-qt-installer)
|
||||
- [Qt 6.7.3](https://www.qt.io/download-qt-installer) In case you can't download from the official installer, you can use [Another Qt installer](https://github.com/miurahr/aqtinstall) (In that case you will need to manually add the "qtmultimedia" module when installing Qt)
|
||||
- [Vulkan SDK 1.3.268.0](https://vulkan.lunarg.com/sdk/home) (see "Install the SDK" [here](https://vulkan.lunarg.com/doc/sdk/latest/windows/getting_started.html)) for now future SDKs don't work. You need precisely 1.3.268.0.
|
||||
|
||||
The `sln` solution available only on **Visual Studio** is the preferred building solution. It easily allows to build the **RPCS3** application in `Release` and `Debug` mode.
|
||||
|
|
|
@ -2475,7 +2475,6 @@ bool fs::pending_file::commit(bool overwrite)
|
|||
{
|
||||
file.sync();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -2486,15 +2485,98 @@ bool fs::pending_file::commit(bool overwrite)
|
|||
disp.DeleteFileW = false;
|
||||
ensure(SetFileInformationByHandle(file.get_handle(), FileDispositionInfo, &disp, sizeof(disp)));
|
||||
}
|
||||
|
||||
std::vector<std::wstring> hardlink_paths;
|
||||
|
||||
const auto ws1 = to_wchar(m_path);
|
||||
|
||||
const HANDLE file_handle = !overwrite ? INVALID_HANDLE_VALUE
|
||||
: CreateFileW(ws1.get(), GENERIC_READ, FILE_SHARE_READ | FILE_SHARE_WRITE | FILE_SHARE_DELETE, nullptr, OPEN_EXISTING, FILE_FLAG_BACKUP_SEMANTICS, nullptr);
|
||||
|
||||
while (file_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
// Get file ID (used to check for hardlinks)
|
||||
BY_HANDLE_FILE_INFORMATION file_info;
|
||||
|
||||
if (!GetFileInformationByHandle(file_handle, &file_info) || file_info.nNumberOfLinks == 1)
|
||||
{
|
||||
CloseHandle(file_handle);
|
||||
break;
|
||||
}
|
||||
|
||||
// Buffer for holding link name
|
||||
std::wstring link_name_buffer(MAX_PATH, wchar_t{});
|
||||
DWORD buffer_size{};
|
||||
HANDLE find_handle = INVALID_HANDLE_VALUE;
|
||||
|
||||
while (true)
|
||||
{
|
||||
buffer_size = static_cast<DWORD>(link_name_buffer.size() - 1);
|
||||
find_handle = FindFirstFileNameW(ws1.get(), 0, &buffer_size, link_name_buffer.data());
|
||||
|
||||
if (find_handle != INVALID_HANDLE_VALUE || GetLastError() != ERROR_MORE_DATA)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
link_name_buffer.resize(buffer_size + 1);
|
||||
}
|
||||
|
||||
if (find_handle != INVALID_HANDLE_VALUE)
|
||||
{
|
||||
const std::wstring_view ws1_sv = ws1.get();
|
||||
|
||||
while (true)
|
||||
{
|
||||
if (link_name_buffer.c_str() != ws1_sv)
|
||||
{
|
||||
// Note: link_name_buffer is a buffer which may contain zeroes so truncate it
|
||||
hardlink_paths.push_back(link_name_buffer.c_str());
|
||||
}
|
||||
|
||||
buffer_size = static_cast<DWORD>(link_name_buffer.size() - 1);
|
||||
if (!FindNextFileNameW(find_handle, &buffer_size, link_name_buffer.data()))
|
||||
{
|
||||
if (GetLastError() != ERROR_MORE_DATA)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
link_name_buffer.resize(buffer_size + 1);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Clean up
|
||||
FindClose(find_handle);
|
||||
CloseHandle(file_handle);
|
||||
break;
|
||||
}
|
||||
|
||||
if (!hardlink_paths.empty())
|
||||
{
|
||||
// REPLACEFILE_WRITE_THROUGH is not supported
|
||||
file.sync();
|
||||
}
|
||||
#endif
|
||||
|
||||
file.close();
|
||||
|
||||
#ifdef _WIN32
|
||||
const auto ws1 = to_wchar(m_path);
|
||||
const auto ws2 = to_wchar(m_dest);
|
||||
|
||||
if (MoveFileExW(ws1.get(), ws2.get(), overwrite ? MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH : MOVEFILE_WRITE_THROUGH))
|
||||
bool ok = false;
|
||||
|
||||
if (hardlink_paths.empty())
|
||||
{
|
||||
ok = MoveFileExW(ws1.get(), ws2.get(), overwrite ? MOVEFILE_REPLACE_EXISTING | MOVEFILE_WRITE_THROUGH : MOVEFILE_WRITE_THROUGH);
|
||||
}
|
||||
else
|
||||
{
|
||||
ok = ReplaceFileW(ws1.get(), ws2.get(), nullptr, 0, nullptr, nullptr);
|
||||
}
|
||||
|
||||
if (ok)
|
||||
{
|
||||
// Disable the destructor
|
||||
m_path.clear();
|
||||
|
|
|
@ -119,8 +119,13 @@ std::shared_ptr<lv2_event_queue> lv2_event_queue::find(u64 ipc_key)
|
|||
|
||||
extern void resume_spu_thread_group_from_waiting(spu_thread& spu);
|
||||
|
||||
CellError lv2_event_queue::send(lv2_event event)
|
||||
CellError lv2_event_queue::send(lv2_event event, bool* notified_thread, lv2_event_port* port)
|
||||
{
|
||||
if (notified_thread)
|
||||
{
|
||||
*notified_thread = false;
|
||||
}
|
||||
|
||||
std::lock_guard lock(mutex);
|
||||
|
||||
if (!exists)
|
||||
|
@ -162,6 +167,15 @@ CellError lv2_event_queue::send(lv2_event event)
|
|||
std::tie(ppu.gpr[4], ppu.gpr[5], ppu.gpr[6], ppu.gpr[7]) = event;
|
||||
|
||||
awake(&ppu);
|
||||
|
||||
if (port && ppu.prio.load().prio < ensure(cpu_thread::get_current<ppu_thread>())->prio.load().prio)
|
||||
{
|
||||
// Block event port disconnection for the time being of sending events
|
||||
// PPU -> lower prio PPU is the only case that can cause thread blocking
|
||||
port->is_busy++;
|
||||
ensure(notified_thread);
|
||||
*notified_thread = true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
|
@ -709,7 +723,10 @@ error_code sys_event_port_disconnect(ppu_thread& ppu, u32 eport_id)
|
|||
return CELL_ENOTCONN;
|
||||
}
|
||||
|
||||
// TODO: return CELL_EBUSY if necessary (can't detect the condition)
|
||||
if (port->is_busy)
|
||||
{
|
||||
return CELL_EBUSY;
|
||||
}
|
||||
|
||||
port->queue.reset();
|
||||
|
||||
|
@ -718,20 +735,32 @@ error_code sys_event_port_disconnect(ppu_thread& ppu, u32 eport_id)
|
|||
|
||||
error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
|
||||
{
|
||||
if (auto cpu = get_current_cpu_thread())
|
||||
const auto cpu = cpu_thread::get_current();
|
||||
const auto ppu = cpu ? cpu->try_get<ppu_thread>() : nullptr;
|
||||
|
||||
if (cpu)
|
||||
{
|
||||
cpu->state += cpu_flag::wait;
|
||||
}
|
||||
|
||||
sys_event.trace("sys_event_port_send(eport_id=0x%x, data1=0x%llx, data2=0x%llx, data3=0x%llx)", eport_id, data1, data2, data3);
|
||||
|
||||
bool notified_thread = false;
|
||||
|
||||
const auto port = idm::check<lv2_obj, lv2_event_port>(eport_id, [&, notify = lv2_obj::notify_all_t()](lv2_event_port& port) -> CellError
|
||||
{
|
||||
if (ppu && ppu->loaded_from_savestate)
|
||||
{
|
||||
port.is_busy++;
|
||||
notified_thread = true;
|
||||
return {};
|
||||
}
|
||||
|
||||
if (lv2_obj::check(port.queue))
|
||||
{
|
||||
const u64 source = port.name ? port.name : (u64{process_getpid() + 0u} << 32) | u64{eport_id};
|
||||
|
||||
return port.queue->send(source, data1, data2, data3);
|
||||
return port.queue->send(source, data1, data2, data3, ¬ified_thread, ppu && port.queue->type == SYS_PPU_QUEUE ? &port : nullptr);
|
||||
}
|
||||
|
||||
return CELL_ENOTCONN;
|
||||
|
@ -742,6 +771,19 @@ error_code sys_event_port_send(u32 eport_id, u64 data1, u64 data2, u64 data3)
|
|||
return CELL_ESRCH;
|
||||
}
|
||||
|
||||
if (ppu && port->queue->type == SYS_PPU_QUEUE && notified_thread)
|
||||
{
|
||||
// Wait to be requeued
|
||||
if (ppu->test_stopped())
|
||||
{
|
||||
// Wait again on savestate load
|
||||
ppu->state += cpu_flag::again;
|
||||
}
|
||||
|
||||
port->is_busy--;
|
||||
return CELL_OK;
|
||||
}
|
||||
|
||||
if (port.ret)
|
||||
{
|
||||
if (port.ret == CELL_EAGAIN)
|
||||
|
|
|
@ -79,6 +79,8 @@ struct sys_event_t
|
|||
// Source, data1, data2, data3
|
||||
using lv2_event = std::tuple<u64, u64, u64, u64>;
|
||||
|
||||
struct lv2_event_port;
|
||||
|
||||
struct lv2_event_queue final : public lv2_obj
|
||||
{
|
||||
static const u32 id_base = 0x8d000000;
|
||||
|
@ -103,11 +105,11 @@ struct lv2_event_queue final : public lv2_obj
|
|||
static void save_ptr(utils::serial&, lv2_event_queue*);
|
||||
static std::shared_ptr<lv2_event_queue> load_ptr(utils::serial& ar, std::shared_ptr<lv2_event_queue>& queue, std::string_view msg = {});
|
||||
|
||||
CellError send(lv2_event event);
|
||||
CellError send(lv2_event event, bool* notified_thread = nullptr, lv2_event_port* port = nullptr);
|
||||
|
||||
CellError send(u64 source, u64 d1, u64 d2, u64 d3)
|
||||
CellError send(u64 source, u64 d1, u64 d2, u64 d3, bool* notified_thread = nullptr, lv2_event_port* port = nullptr)
|
||||
{
|
||||
return send(std::make_tuple(source, d1, d2, d3));
|
||||
return send(std::make_tuple(source, d1, d2, d3), notified_thread, port);
|
||||
}
|
||||
|
||||
// Get event queue by its global key
|
||||
|
@ -121,6 +123,7 @@ struct lv2_event_port final : lv2_obj
|
|||
const s32 type; // Port type, either IPC or local
|
||||
const u64 name; // Event source (generated from id and process id if not set)
|
||||
|
||||
atomic_t<usz> is_busy = 0; // Counts threads waiting on event sending
|
||||
std::shared_ptr<lv2_event_queue> queue; // Event queue this port is connected to
|
||||
|
||||
lv2_event_port(s32 type, u64 name)
|
||||
|
|
|
@ -424,6 +424,8 @@ error_code sys_event_flag_set(cpu_thread& cpu, u32 id, u64 bitptn)
|
|||
}
|
||||
}
|
||||
|
||||
dependant_mask &= ~bitptn;
|
||||
|
||||
auto [new_val, ok] = flag->pattern.fetch_op([&](u64& x)
|
||||
{
|
||||
if ((x ^ pattern) & dependant_mask)
|
||||
|
|
|
@ -212,9 +212,9 @@ u64 get_system_time()
|
|||
const u64 tsc = utils::get_tsc();
|
||||
|
||||
#if _MSC_VER
|
||||
const u64 result = static_cast<u64>(u128_from_mul(tsc, 1000000ull) / freq) * g_cfg.core.clocks_scale / 100u;
|
||||
const u64 result = static_cast<u64>(u128_from_mul(tsc, 1000000ull) / freq);
|
||||
#else
|
||||
const u64 result = (tsc / freq * 1000000ull + tsc % freq * 1000000ull / freq) * g_cfg.core.clocks_scale / 100u;
|
||||
const u64 result = (tsc / freq * 1000000ull + tsc % freq * 1000000ull / freq);
|
||||
#endif
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -1009,7 +1009,7 @@ namespace vm
|
|||
// the RSX might try to call VirtualProtect on memory that is already unmapped
|
||||
if (auto rsxthr = g_fxo->try_get<rsx::thread>())
|
||||
{
|
||||
rsxthr->on_notify_memory_unmapped(addr, size);
|
||||
rsxthr->on_notify_pre_memory_unmapped(addr, size);
|
||||
}
|
||||
|
||||
// Deregister PPU related data
|
||||
|
@ -1309,7 +1309,7 @@ namespace vm
|
|||
}
|
||||
}
|
||||
|
||||
bool block_t::unmap()
|
||||
bool block_t::unmap(std::vector<std::pair<u32, u32>>* unmapped)
|
||||
{
|
||||
auto& m_map = (m.*block_map)();
|
||||
|
||||
|
@ -1320,7 +1320,13 @@ namespace vm
|
|||
{
|
||||
const auto next = std::next(it);
|
||||
const auto size = it->second.first;
|
||||
_page_unmap(it->first, size, this->flags, it->second.second.get());
|
||||
auto unmap = std::make_pair(it->first, _page_unmap(it->first, size, this->flags, it->second.second.get()));
|
||||
|
||||
if (unmapped)
|
||||
{
|
||||
unmapped->emplace_back(unmap);
|
||||
}
|
||||
|
||||
it = next;
|
||||
}
|
||||
|
||||
|
@ -1480,6 +1486,20 @@ namespace vm
|
|||
{
|
||||
auto& m_map = (m.*block_map)();
|
||||
{
|
||||
struct notify_t
|
||||
{
|
||||
u32 addr{};
|
||||
u32 size{};
|
||||
|
||||
~notify_t() noexcept
|
||||
{
|
||||
if (auto rsxthr = g_fxo->try_get<rsx::thread>(); rsxthr && size)
|
||||
{
|
||||
rsxthr->on_notify_post_memory_unmapped(addr, size);
|
||||
}
|
||||
}
|
||||
} unmap_notification;
|
||||
|
||||
vm::writer_lock lock;
|
||||
|
||||
const auto found = m_map.find(addr - (flags & stack_guarded ? 0x1000 : 0));
|
||||
|
@ -1517,6 +1537,8 @@ namespace vm
|
|||
// Remove entry
|
||||
m_map.erase(found);
|
||||
|
||||
unmap_notification.size = size;
|
||||
unmap_notification.addr = addr;
|
||||
return size;
|
||||
}
|
||||
}
|
||||
|
@ -1815,9 +1837,9 @@ namespace vm
|
|||
}
|
||||
}
|
||||
|
||||
bool _unmap_block(const std::shared_ptr<block_t>& block)
|
||||
bool _unmap_block(const std::shared_ptr<block_t>& block, std::vector<std::pair<u32, u32>>* unmapped = nullptr)
|
||||
{
|
||||
return block->unmap();
|
||||
return block->unmap(unmapped);
|
||||
}
|
||||
|
||||
static bool _test_map(u32 addr, u32 size)
|
||||
|
@ -1964,6 +1986,22 @@ namespace vm
|
|||
|
||||
std::pair<std::shared_ptr<block_t>, bool> result{};
|
||||
|
||||
struct notify_t
|
||||
{
|
||||
std::vector<std::pair<u32, u32>> addr_size_pairs;
|
||||
|
||||
~notify_t() noexcept
|
||||
{
|
||||
for (const auto [addr, size] : addr_size_pairs)
|
||||
{
|
||||
if (auto rsxthr = g_fxo->try_get<rsx::thread>())
|
||||
{
|
||||
rsxthr->on_notify_post_memory_unmapped(addr, size);
|
||||
}
|
||||
}
|
||||
}
|
||||
} unmap_notifications;
|
||||
|
||||
vm::writer_lock lock;
|
||||
|
||||
for (auto it = g_locations.begin() + memory_location_max; it != g_locations.end(); it++)
|
||||
|
@ -1993,7 +2031,7 @@ namespace vm
|
|||
|
||||
result.first = std::move(*it);
|
||||
g_locations.erase(it);
|
||||
ensure(_unmap_block(result.first));
|
||||
ensure(_unmap_block(result.first, &unmap_notifications.addr_size_pairs));
|
||||
result.second = true;
|
||||
return result;
|
||||
}
|
||||
|
|
|
@ -133,8 +133,8 @@ namespace vm
|
|||
bool try_alloc(u32 addr, u64 bflags, u32 size, std::shared_ptr<utils::shm>&&) const;
|
||||
|
||||
// Unmap block
|
||||
bool unmap();
|
||||
friend bool _unmap_block(const std::shared_ptr<block_t>&);
|
||||
bool unmap(std::vector<std::pair<u32, u32>>* unmapped = nullptr);
|
||||
friend bool _unmap_block(const std::shared_ptr<block_t>&, std::vector<std::pair<u32, u32>>* unmapped);
|
||||
|
||||
public:
|
||||
block_t(u32 addr, u32 size, u64 flags);
|
||||
|
|
|
@ -16,7 +16,7 @@ namespace rsx
|
|||
{
|
||||
if (enabled) [[unlikely]]
|
||||
{
|
||||
last = rsx::uclock();
|
||||
last = get_system_time();
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -28,7 +28,7 @@ namespace rsx
|
|||
}
|
||||
|
||||
auto old = last;
|
||||
last = rsx::uclock();
|
||||
last = get_system_time();
|
||||
return static_cast<s64>(last - old);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -4,20 +4,3 @@
|
|||
#include <util/sysinfo.hpp>
|
||||
|
||||
#include "Emu/Cell/timers.hpp"
|
||||
|
||||
namespace rsx
|
||||
{
|
||||
static inline u64 uclock()
|
||||
{
|
||||
static const ullong s_tsc_scaled_freq = (utils::get_tsc_freq() / 1000000);
|
||||
|
||||
if (s_tsc_scaled_freq)
|
||||
{
|
||||
return utils::get_tsc() / s_tsc_scaled_freq;
|
||||
}
|
||||
else
|
||||
{
|
||||
return get_system_time();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -1214,7 +1214,7 @@ void GLGSRender::notify_tile_unbound(u32 tile)
|
|||
if (false)
|
||||
{
|
||||
u32 addr = rsx::get_address(tiles[tile].offset, tiles[tile].location);
|
||||
on_notify_memory_unmapped(addr, tiles[tile].size);
|
||||
on_notify_pre_memory_unmapped(addr, tiles[tile].size);
|
||||
m_rtts.invalidate_surface_address(addr, false);
|
||||
}
|
||||
|
||||
|
|
|
@ -44,7 +44,7 @@ namespace rsx
|
|||
RSX(ctx)->flush_fifo();
|
||||
}
|
||||
|
||||
u64 start = rsx::uclock();
|
||||
u64 start = get_system_time();
|
||||
u64 last_check_val = start;
|
||||
|
||||
while (sema != arg)
|
||||
|
@ -57,7 +57,7 @@ namespace rsx
|
|||
|
||||
if (const auto tdr = static_cast<u64>(g_cfg.video.driver_recovery_timeout))
|
||||
{
|
||||
const u64 current = rsx::uclock();
|
||||
const u64 current = get_system_time();
|
||||
|
||||
if (current - last_check_val > 20'000)
|
||||
{
|
||||
|
@ -81,7 +81,7 @@ namespace rsx
|
|||
}
|
||||
|
||||
RSX(ctx)->fifo_wake_delay();
|
||||
RSX(ctx)->performance_counters.idle_time += (rsx::uclock() - start);
|
||||
RSX(ctx)->performance_counters.idle_time += (get_system_time() - start);
|
||||
}
|
||||
|
||||
void semaphore_release(context* ctx, u32 /*reg*/, u32 arg)
|
||||
|
|
|
@ -25,11 +25,11 @@ namespace rsx
|
|||
{
|
||||
if (m_last_update_timestamp_us == 0)
|
||||
{
|
||||
m_last_update_timestamp_us = rsx::uclock();
|
||||
m_last_update_timestamp_us = get_system_time();
|
||||
}
|
||||
else
|
||||
{
|
||||
const auto now = rsx::uclock();
|
||||
const auto now = get_system_time();
|
||||
m_current_frame_duration_us += (now - m_last_update_timestamp_us);
|
||||
m_last_update_timestamp_us = now;
|
||||
}
|
||||
|
|
|
@ -13,7 +13,7 @@ namespace rsx
|
|||
return duration;
|
||||
}
|
||||
|
||||
return rsx::uclock() + duration;
|
||||
return get_system_time() + duration;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
|
@ -168,7 +168,7 @@ namespace rsx
|
|||
|
||||
void message::update_queue(std::deque<message_item>& vis_set, std::deque<message_item>& ready_set, message_pin_location origin)
|
||||
{
|
||||
const u64 cur_time = rsx::uclock();
|
||||
const u64 cur_time = get_system_time();
|
||||
|
||||
for (auto it = vis_set.begin(); it != vis_set.end();)
|
||||
{
|
||||
|
|
|
@ -499,7 +499,7 @@ namespace rsx
|
|||
}
|
||||
|
||||
if (auto rsxthr = rsx::get_current_renderer(); rsxthr &&
|
||||
(min_refresh_duration_us + rsxthr->last_host_flip_timestamp) < rsx::uclock())
|
||||
(min_refresh_duration_us + rsxthr->last_host_flip_timestamp) < get_system_time())
|
||||
{
|
||||
rsxthr->async_flip_requested |= rsx::thread::flip_request::native_ui;
|
||||
}
|
||||
|
|
|
@ -173,10 +173,10 @@ namespace rsx
|
|||
break;
|
||||
}
|
||||
|
||||
start_time = rsx::uclock();
|
||||
start_time = get_system_time();
|
||||
}
|
||||
|
||||
auto now = rsx::uclock();
|
||||
auto now = get_system_time();
|
||||
if (now - start_time >= 50u)
|
||||
{
|
||||
if (m_thread->is_stopped())
|
||||
|
@ -186,7 +186,7 @@ namespace rsx
|
|||
|
||||
m_thread->cpu_wait({});
|
||||
|
||||
const auto then = std::exchange(now, rsx::uclock());
|
||||
const auto then = std::exchange(now, get_system_time());
|
||||
start_time = now;
|
||||
m_thread->performance_counters.idle_time += now - then;
|
||||
}
|
||||
|
@ -623,7 +623,7 @@ namespace rsx
|
|||
{
|
||||
if (performance_counters.state == FIFO::state::running)
|
||||
{
|
||||
performance_counters.FIFO_idle_timestamp = rsx::uclock();
|
||||
performance_counters.FIFO_idle_timestamp = get_system_time();
|
||||
performance_counters.state = FIFO::state::nop;
|
||||
}
|
||||
|
||||
|
@ -633,7 +633,7 @@ namespace rsx
|
|||
{
|
||||
if (performance_counters.state == FIFO::state::running)
|
||||
{
|
||||
performance_counters.FIFO_idle_timestamp = rsx::uclock();
|
||||
performance_counters.FIFO_idle_timestamp = get_system_time();
|
||||
performance_counters.state = FIFO::state::empty;
|
||||
}
|
||||
else
|
||||
|
@ -668,7 +668,7 @@ namespace rsx
|
|||
//Jump to self. Often preceded by NOP
|
||||
if (performance_counters.state == FIFO::state::running)
|
||||
{
|
||||
performance_counters.FIFO_idle_timestamp = rsx::uclock();
|
||||
performance_counters.FIFO_idle_timestamp = get_system_time();
|
||||
sync_point_request.release(true);
|
||||
}
|
||||
|
||||
|
@ -749,7 +749,7 @@ namespace rsx
|
|||
}
|
||||
|
||||
// Update performance counters with time spent in idle mode
|
||||
performance_counters.idle_time += (rsx::uclock() - performance_counters.FIFO_idle_timestamp);
|
||||
performance_counters.idle_time += (get_system_time() - performance_counters.FIFO_idle_timestamp);
|
||||
}
|
||||
|
||||
do
|
||||
|
|
|
@ -1024,7 +1024,7 @@ namespace rsx
|
|||
fifo_ctrl = std::make_unique<::rsx::FIFO::FIFO_control>(this);
|
||||
fifo_ctrl->set_get(ctrl->get);
|
||||
|
||||
last_guest_flip_timestamp = rsx::uclock() - 1000000;
|
||||
last_guest_flip_timestamp = get_system_time() - 1000000;
|
||||
|
||||
vblank_count = 0;
|
||||
|
||||
|
@ -1104,7 +1104,7 @@ namespace rsx
|
|||
if (Emu.IsPaused())
|
||||
{
|
||||
// Save the difference before pause
|
||||
start_time = rsx::uclock() - start_time;
|
||||
start_time = get_system_time() - start_time;
|
||||
|
||||
while (Emu.IsPaused() && !is_stopped())
|
||||
{
|
||||
|
@ -1112,7 +1112,7 @@ namespace rsx
|
|||
}
|
||||
|
||||
// Restore difference
|
||||
start_time = rsx::uclock() - start_time;
|
||||
start_time = get_system_time() - start_time;
|
||||
}
|
||||
}
|
||||
})));
|
||||
|
@ -3057,7 +3057,7 @@ namespace rsx
|
|||
}
|
||||
}
|
||||
|
||||
last_host_flip_timestamp = rsx::uclock();
|
||||
last_host_flip_timestamp = get_system_time();
|
||||
}
|
||||
|
||||
void thread::check_zcull_status(bool framebuffer_swap)
|
||||
|
@ -3299,7 +3299,7 @@ namespace rsx
|
|||
{
|
||||
bool kill_itself = g_cfg.core.rsx_fifo_accuracy == rsx_fifo_mode::as_ps3;
|
||||
|
||||
const u64 current_time = rsx::uclock();
|
||||
const u64 current_time = get_system_time();
|
||||
|
||||
if (recovered_fifo_cmds_history.size() == 20u)
|
||||
{
|
||||
|
@ -3381,7 +3381,7 @@ namespace rsx
|
|||
|
||||
// Some cases do not need full delay
|
||||
remaining = utils::aligned_div(remaining, div);
|
||||
const u64 until = rsx::uclock() + remaining;
|
||||
const u64 until = get_system_time() + remaining;
|
||||
|
||||
while (true)
|
||||
{
|
||||
|
@ -3412,7 +3412,7 @@ namespace rsx
|
|||
busy_wait(100);
|
||||
}
|
||||
|
||||
const u64 current = rsx::uclock();
|
||||
const u64 current = get_system_time();
|
||||
|
||||
if (current >= until)
|
||||
{
|
||||
|
@ -3508,7 +3508,40 @@ namespace rsx
|
|||
}
|
||||
}
|
||||
|
||||
void thread::on_notify_memory_unmapped(u32 address, u32 size)
|
||||
void thread::on_notify_pre_memory_unmapped(u32 address, u32 size)
|
||||
{
|
||||
if (rsx_thread_running && address < rsx::constants::local_mem_base)
|
||||
{
|
||||
// Pause RSX thread momentarily to handle unmapping
|
||||
eng_lock elock(this);
|
||||
|
||||
// Queue up memory invalidation
|
||||
std::lock_guard lock(m_mtx_task);
|
||||
const bool existing_range_valid = m_invalidated_memory_range.valid();
|
||||
const auto unmap_range = address_range::start_length(address, size);
|
||||
|
||||
if (existing_range_valid && m_invalidated_memory_range.touches(unmap_range))
|
||||
{
|
||||
// Merge range-to-invalidate in case of consecutive unmaps
|
||||
m_invalidated_memory_range.set_min_max(unmap_range);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (existing_range_valid)
|
||||
{
|
||||
// We can only delay consecutive unmaps.
|
||||
// Otherwise, to avoid VirtualProtect failures, we need to do the invalidation here
|
||||
handle_invalidated_memory_range();
|
||||
}
|
||||
|
||||
m_invalidated_memory_range = unmap_range;
|
||||
}
|
||||
|
||||
m_eng_interrupt_mask |= rsx::memory_config_interrupt;
|
||||
}
|
||||
}
|
||||
|
||||
void thread::on_notify_post_memory_unmapped(u32 address, u32 size)
|
||||
{
|
||||
if (rsx_thread_running && address < rsx::constants::local_mem_base)
|
||||
{
|
||||
|
@ -3559,33 +3592,6 @@ namespace rsx
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Pause RSX thread momentarily to handle unmapping
|
||||
eng_lock elock(this);
|
||||
|
||||
// Queue up memory invalidation
|
||||
std::lock_guard lock(m_mtx_task);
|
||||
const bool existing_range_valid = m_invalidated_memory_range.valid();
|
||||
const auto unmap_range = address_range::start_length(address, size);
|
||||
|
||||
if (existing_range_valid && m_invalidated_memory_range.touches(unmap_range))
|
||||
{
|
||||
// Merge range-to-invalidate in case of consecutive unmaps
|
||||
m_invalidated_memory_range.set_min_max(unmap_range);
|
||||
}
|
||||
else
|
||||
{
|
||||
if (existing_range_valid)
|
||||
{
|
||||
// We can only delay consecutive unmaps.
|
||||
// Otherwise, to avoid VirtualProtect failures, we need to do the invalidation here
|
||||
handle_invalidated_memory_range();
|
||||
}
|
||||
|
||||
m_invalidated_memory_range = unmap_range;
|
||||
}
|
||||
|
||||
m_eng_interrupt_mask |= rsx::memory_config_interrupt;
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -3654,7 +3660,7 @@ namespace rsx
|
|||
//Average load over around 30 frames
|
||||
if (!performance_counters.last_update_timestamp || performance_counters.sampled_frames > 30)
|
||||
{
|
||||
const auto timestamp = rsx::uclock();
|
||||
const auto timestamp = get_system_time();
|
||||
const auto idle = performance_counters.idle_time.load();
|
||||
const auto elapsed = timestamp - performance_counters.last_update_timestamp;
|
||||
|
||||
|
@ -3938,7 +3944,7 @@ namespace rsx
|
|||
|
||||
flip(m_queued_flip);
|
||||
|
||||
last_guest_flip_timestamp = rsx::uclock() - 1000000;
|
||||
last_guest_flip_timestamp = get_system_time() - 1000000;
|
||||
flip_status = CELL_GCM_DISPLAY_FLIP_STATUS_DONE;
|
||||
m_queued_flip.in_progress = false;
|
||||
|
||||
|
|
|
@ -499,11 +499,17 @@ namespace rsx
|
|||
*/
|
||||
void on_notify_memory_mapped(u32 address_base, u32 size);
|
||||
|
||||
/**
|
||||
* Notify that a section of memory is to be unmapped
|
||||
* Any data held in the defined range is discarded
|
||||
*/
|
||||
void on_notify_pre_memory_unmapped(u32 address_base, u32 size);
|
||||
|
||||
/**
|
||||
* Notify that a section of memory has been unmapped
|
||||
* Any data held in the defined range is discarded
|
||||
*/
|
||||
void on_notify_memory_unmapped(u32 address_base, u32 size);
|
||||
void on_notify_post_memory_unmapped(u32 address_base, u32 size);
|
||||
|
||||
/**
|
||||
* Notify to check internal state during semaphore wait
|
||||
|
|
|
@ -542,7 +542,7 @@ namespace rsx
|
|||
}
|
||||
}
|
||||
|
||||
if (m_tsc = rsx::uclock(); m_tsc < m_next_tsc)
|
||||
if (m_tsc = get_system_time(); m_tsc < m_next_tsc)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
|
|
@ -1257,7 +1257,7 @@ void VKGSRender::notify_tile_unbound(u32 tile)
|
|||
if (false)
|
||||
{
|
||||
u32 addr = rsx::get_address(tiles[tile].offset, tiles[tile].location);
|
||||
on_notify_memory_unmapped(addr, tiles[tile].size);
|
||||
on_notify_pre_memory_unmapped(addr, tiles[tile].size);
|
||||
m_rtts.invalidate_surface_address(addr, false);
|
||||
}
|
||||
|
||||
|
@ -1892,7 +1892,7 @@ void VKGSRender::sync_hint(rsx::FIFO::interrupt_hint hint, rsx::reports::sync_hi
|
|||
// OK, cell will be accessing the results, probably.
|
||||
// Try to avoid flush spam, it is more costly to flush the CB than it is to just upload the vertex data
|
||||
// This is supposed to be an optimization afterall.
|
||||
const auto now = rsx::uclock();
|
||||
const auto now = get_system_time();
|
||||
if ((now - m_last_cond_render_eval_hint) > 50)
|
||||
{
|
||||
// Schedule a sync on the next loop iteration
|
||||
|
|
|
@ -569,9 +569,6 @@ int main(int argc, char** argv)
|
|||
|
||||
ensure(thread_ctrl::is_main(), "Not main thread");
|
||||
|
||||
// Initialize TSC freq (in case it isn't)
|
||||
static_cast<void>(utils::ensure_tsc_freq_init());
|
||||
|
||||
// Initialize thread pool finalizer (on first use)
|
||||
static_cast<void>(named_thread("", [](int) {}));
|
||||
|
||||
|
|
|
@ -22,6 +22,8 @@
|
|||
#endif
|
||||
#endif
|
||||
|
||||
#include <thread>
|
||||
|
||||
#include "util/asm.hpp"
|
||||
#include "util/fence.hpp"
|
||||
|
||||
|
@ -734,9 +736,24 @@ bool utils::get_low_power_mode()
|
|||
#endif
|
||||
}
|
||||
|
||||
static constexpr ullong round_tsc(ullong val)
|
||||
static constexpr ullong round_tsc(ullong val, ullong known_error)
|
||||
{
|
||||
return utils::rounded_div(val, 100'000) * 100'000;
|
||||
if (known_error >= 500'000)
|
||||
{
|
||||
// Do not accept large errors
|
||||
return 0;
|
||||
}
|
||||
|
||||
ullong by = 1000;
|
||||
known_error /= 1000;
|
||||
|
||||
while (known_error && by < 100'000)
|
||||
{
|
||||
by *= 10;
|
||||
known_error /= 10;
|
||||
}
|
||||
|
||||
return utils::rounded_div(val, by) * by;
|
||||
}
|
||||
|
||||
namespace utils
|
||||
|
@ -744,7 +761,7 @@ namespace utils
|
|||
u64 s_tsc_freq = 0;
|
||||
}
|
||||
|
||||
named_thread<std::function<void()>> s_thread_evaluate_tsc_freq("TSC Evaluate Thread", []()
|
||||
static const bool s_tsc_freq_evaluated = []() -> bool
|
||||
{
|
||||
static const ullong cal_tsc = []() -> ullong
|
||||
{
|
||||
|
@ -763,14 +780,14 @@ named_thread<std::function<void()>> s_thread_evaluate_tsc_freq("TSC Evaluate Thr
|
|||
return 0;
|
||||
|
||||
if (freq.QuadPart <= 9'999'999)
|
||||
return round_tsc(freq.QuadPart * 1024);
|
||||
return 0;
|
||||
|
||||
const ullong timer_freq = freq.QuadPart;
|
||||
#else
|
||||
constexpr ullong timer_freq = 1'000'000'000;
|
||||
#endif
|
||||
|
||||
constexpr u64 retry_count = 1000;
|
||||
constexpr u64 retry_count = 1024;
|
||||
|
||||
// First is entry is for the onset measurements, last is for the end measurements
|
||||
constexpr usz sample_count = 2;
|
||||
|
@ -788,6 +805,8 @@ named_thread<std::function<void()>> s_thread_evaluate_tsc_freq("TSC Evaluate Thr
|
|||
const ullong sec_base = ts0.tv_sec;
|
||||
#endif
|
||||
|
||||
constexpr usz sleep_time_ms = 40;
|
||||
|
||||
for (usz sample = 0; sample < sample_count; sample++)
|
||||
{
|
||||
for (usz i = 0; i < retry_count; i++)
|
||||
|
@ -815,19 +834,34 @@ named_thread<std::function<void()>> s_thread_evaluate_tsc_freq("TSC Evaluate Thr
|
|||
rdtsc_diff[sample] = rdtsc_read2 >= rdtsc_read ? rdtsc_read2 - rdtsc_read : u64{umax};
|
||||
}
|
||||
|
||||
if (rdtsc_read2 - rdtsc_read < std::min<usz>(i, 300) && rdtsc_read2 >= rdtsc_read)
|
||||
// 80 results in an error range of 4000 hertz (0.00025% of 4GHz CPU, quite acceptable)
|
||||
// Error of 2.5 seconds per month
|
||||
if (rdtsc_read2 - rdtsc_read < 80 && rdtsc_read2 >= rdtsc_read)
|
||||
{
|
||||
break;
|
||||
}
|
||||
|
||||
// 8 yields seems to reduce significantly thread contention, improving accuracy
|
||||
// Even 3 seem to do the job though, but just in case
|
||||
if (i % 128 == 64)
|
||||
{
|
||||
std::this_thread::yield();
|
||||
}
|
||||
|
||||
// Take 50% more yields with the last sample because it helps accuracy additionally the more time that passes
|
||||
if (sample == sample_count - 1 && i % 256 == 128)
|
||||
{
|
||||
std::this_thread::yield();
|
||||
}
|
||||
}
|
||||
|
||||
if (sample < sample_count - 1)
|
||||
{
|
||||
// Sleep 20ms between first and last sample
|
||||
// Sleep between first and last sample
|
||||
#ifdef _WIN32
|
||||
Sleep(20);
|
||||
Sleep(sleep_time_ms);
|
||||
#else
|
||||
usleep(20'000);
|
||||
usleep(sleep_time_ms * 1000);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
@ -843,17 +877,12 @@ named_thread<std::function<void()>> s_thread_evaluate_tsc_freq("TSC Evaluate Thr
|
|||
const u64 res = utils::udiv128(static_cast<u64>(data >> 64), static_cast<u64>(data), (timer_data[1] - timer_data[0]));
|
||||
|
||||
// Rounding
|
||||
return round_tsc(res);
|
||||
return round_tsc(res, utils::mul_saturate<u64>(utils::add_saturate<u64>(rdtsc_diff[0], rdtsc_diff[1]), utils::aligned_div(timer_freq, timer_data[1] - timer_data[0])));
|
||||
}();
|
||||
|
||||
atomic_storage<u64>::release(utils::s_tsc_freq, cal_tsc);
|
||||
});
|
||||
|
||||
void utils::ensure_tsc_freq_init()
|
||||
{
|
||||
// Join thread
|
||||
s_thread_evaluate_tsc_freq();
|
||||
}
|
||||
return true;
|
||||
}();
|
||||
|
||||
u64 utils::get_total_memory()
|
||||
{
|
||||
|
|
|
@ -94,6 +94,4 @@ namespace utils
|
|||
{
|
||||
return s_tsc_freq;
|
||||
}
|
||||
|
||||
void ensure_tsc_freq_init();
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue