Skip to content

Commit

Permalink
More accurate PS3 memory consumption
Browse files Browse the repository at this point in the history
  • Loading branch information
elad335 committed Aug 10, 2023
1 parent 4bbe885 commit 1d9ab8e
Show file tree
Hide file tree
Showing 13 changed files with 274 additions and 44 deletions.
45 changes: 42 additions & 3 deletions rpcs3/Emu/Cell/Modules/cellAudio.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,8 @@
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/lv2/sys_process.h"
#include "Emu/Cell/lv2/sys_event.h"
#include "Emu/Cell/lv2/sys_memory.h"
#include "util/asm.hpp"
#include "cellAudio.h"

#include <cmath>
Expand Down Expand Up @@ -1203,6 +1205,7 @@ error_code cellAudioInit()
cellAudio.warning("cellAudioInit()");

auto& g_audio = g_fxo->get<cell_audio>();
auto& dct = g_fxo->get<lv2_memory_container>();

std::lock_guard lock(g_audio.mutex);

Expand All @@ -1211,6 +1214,12 @@ error_code cellAudioInit()
return CELL_AUDIO_ERROR_ALREADY_INIT;
}

// TODO: This is the minimum amount, it can allocate more if specified by VSH (needs investigation)
if (!dct.take(0x10000))
{
return CELL_AUDIO_ERROR_SHAREDMEMORY;
}

std::memset(g_audio_buffer.get_ptr(), 0, g_audio_buffer.alloc_size);
std::memset(g_audio_indices.get_ptr(), 0, g_audio_indices.alloc_size);

Expand All @@ -1232,6 +1241,7 @@ error_code cellAudioQuit()
cellAudio.warning("cellAudioQuit()");

auto& g_audio = g_fxo->get<cell_audio>();
auto& dct = g_fxo->get<lv2_memory_container>();

std::lock_guard lock(g_audio.mutex);

Expand All @@ -1240,6 +1250,19 @@ error_code cellAudioQuit()
return CELL_AUDIO_ERROR_NOT_INIT;
}

// See cellAudioInit
u32 to_free = 0x10000;

for (auto& port : g_audio.ports)
{
if (port.state.exchange(audio_port_state::closed) != audio_port_state::closed)
{
to_free += utils::align<u32>(port.size, 0x10000) + 0x10000;
}
}

dct.free(to_free);

// NOTE: Do not clear event queues here. They are handled independently.
g_audio.init = 0;

Expand All @@ -1252,6 +1275,8 @@ error_code cellAudioPortOpen(vm::ptr<CellAudioPortParam> audioParam, vm::ptr<u32

auto& g_audio = g_fxo->get<cell_audio>();

auto& dct = g_fxo->get<lv2_memory_container>();

std::lock_guard lock(g_audio.mutex);

if (!g_audio.init)
Expand Down Expand Up @@ -1319,6 +1344,9 @@ error_code cellAudioPortOpen(vm::ptr<CellAudioPortParam> audioParam, vm::ptr<u32
cellAudio.todo("cellAudioPortOpen(): unknown attributes (0x%llx)", attr);
}

const u32 mem_size = ::narrow<u32>(num_channels * num_blocks * AUDIO_BUFFER_SAMPLES * sizeof(f32));
const u32 mem_page_size = utils::align<u32>(mem_size, 0x10000) + 0x10000;

// Open audio port
audio_port* port = g_audio.open_port();

Expand All @@ -1327,13 +1355,20 @@ error_code cellAudioPortOpen(vm::ptr<CellAudioPortParam> audioParam, vm::ptr<u32
return CELL_AUDIO_ERROR_PORT_FULL;
}

// Fake memory allocation required for the port creation (64k flags)
if (!dct.take(mem_page_size))
{
ensure(port->state.compare_and_swap_test(audio_port_state::opened, audio_port_state::closed));
return CELL_AUDIO_ERROR_SHAREDMEMORY;
}

// TODO: is this necessary in any way? (Based on libaudio.prx)
//const u64 num_channels_non_0 = std::max<u64>(1, num_channels);

port->num_channels = ::narrow<u32>(num_channels);
port->num_blocks = ::narrow<u32>(num_blocks);
port->attr = attr;
port->size = ::narrow<u32>(num_channels * num_blocks * AUDIO_BUFFER_SAMPLES * sizeof(f32));
port->size = mem_size;
port->cur_pos = 0;
port->global_counter = g_audio.m_counter;
port->active_counter = 0;
Expand Down Expand Up @@ -1452,10 +1487,14 @@ error_code cellAudioPortClose(u32 portNum)
switch (audio_port_state state = g_audio.ports[portNum].state.exchange(audio_port_state::closed))
{
case audio_port_state::closed: return CELL_AUDIO_ERROR_PORT_NOT_OPEN;
case audio_port_state::started: return CELL_OK;
case audio_port_state::opened: return CELL_OK;
case audio_port_state::started: break;
case audio_port_state::opened: break;
default: fmt::throw_exception("Invalid port state (%d: %d)", portNum, static_cast<u32>(state));
}

const u32 mem_page_size = utils::align<u32>(g_audio.ports[portNum].size, 0x10000) + 0x10000;
g_fxo->get<lv2_memory_container>().free(mem_page_size);
return CELL_OK;
}

error_code cellAudioPortStop(u32 portNum)
Expand Down
88 changes: 75 additions & 13 deletions rpcs3/Emu/Cell/Modules/sceNp2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@
#include "Emu/NP/np_handler.h"
#include "Emu/NP/np_contexts.h"
#include "Emu/NP/np_helpers.h"
#include "Emu/Cell/Modules/sysPrxForUser.h"
#include "Emu/Cell/lv2/sys_ppu_thread.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include "cellSysutil.h"

LOG_CHANNEL(sceNp2);
Expand Down Expand Up @@ -175,9 +178,9 @@ void fmt_class_string<SceNpOauthError>::format(std::string& out, u64 arg)
});
}

error_code sceNpMatching2Init2(u64 stackSize, s32 priority, vm::ptr<SceNpMatching2UtilityInitParam> param);
error_code sceNpMatching2Init2(ppu_thread& ppu, u64 stackSize, s32 priority, vm::ptr<SceNpMatching2UtilityInitParam> param);
error_code sceNpMatching2Term(ppu_thread& ppu);
error_code sceNpMatching2Term2();
error_code sceNpMatching2Term2(ppu_thread& ppu);

error_code generic_match2_error_check(const named_thread<np::np_handler>& nph, SceNpMatching2ContextId ctxId, vm::cptr<void> reqParam, vm::ptr<SceNpMatching2RequestId> assignedReqId)
{
Expand Down Expand Up @@ -230,13 +233,53 @@ error_code sceNp2Init(u32 poolsize, vm::ptr<void> poolptr)
return CELL_OK;
}

error_code sceNpMatching2Init(u32 stackSize, s32 priority)
error_code sceNpMatching2Init(ppu_thread& ppu, u32 stackSize, s32 priority)
{
sceNp2.todo("sceNpMatching2Init(stackSize=0x%x, priority=%d)", stackSize, priority);
return sceNpMatching2Init2(stackSize, priority, vm::null); // > SDK 2.4.0
return sceNpMatching2Init2(ppu, stackSize, priority, vm::null); // > SDK 2.4.0
}

error_code sceNpMatching2Init2(u64 stackSize, s32 priority, vm::ptr<SceNpMatching2UtilityInitParam> param)
static void s_matching2_thread_func(ppu_thread& ppu)
{
lv2_obj::sleep(ppu);

auto& nph = g_fxo->get<named_thread<np::np_handler>>();

while (thread_ctrl::state() != thread_state::aborting)
{
const auto state = +ppu.state;

if (!nph.is_NP2_Match2_init)
{
// Guard against pending awake call
nph.mutex_status.lock_unlock();
ppu_execute<&sys_ppu_thread_exit>(ppu, 0);
return;
}

if (state & cpu_flag::signal)
{
if (ppu.state.test_and_reset(cpu_flag::signal))
{
ppu_execute<&sys_ppu_thread_exit>(ppu, 0);
return;
}

continue;
}

if (::is_stopped(state))
{
break;
}

thread_ctrl::wait_on(ppu.state, state);
}

ppu.state += cpu_flag::again;
}

error_code sceNpMatching2Init2(ppu_thread& ppu, u64 stackSize, s32 priority, vm::ptr<SceNpMatching2UtilityInitParam> param)
{
sceNp2.warning("sceNpMatching2Init2(stackSize=0x%x, priority=%d, param=*0x%x)", stackSize, priority, param);

Expand All @@ -253,9 +296,18 @@ error_code sceNpMatching2Init2(u64 stackSize, s32 priority, vm::ptr<SceNpMatchin
}

// TODO:
// 1. Create an internal thread
// 2. Create heap area to be used by the NP matching 2 utility
// 3. Set maximum lengths for the event data queues in the system
// 1. Create heap area to be used by the NP matching 2 utility
// 2. Set maximum lengths for the event data queues in the system

vm::var<u64> _tid;
vm::var<char[]> _name = vm::make_str("SceNpMatching2ScCb");

const u32 stack_size = stackSize ? stackSize : 0x4000;

// TODO: error checking
ensure(ppu_execute<&sys_ppu_thread_create>(ppu, +_tid, g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(s_matching2_thread_func)), 0, priority, stack_size, SYS_PPU_THREAD_CREATE_JOINABLE, +_name) == CELL_OK);

nph.np2_match2_thread_id = static_cast<u32>(*_tid);

nph.is_NP2_Match2_init = true;

Expand Down Expand Up @@ -286,18 +338,19 @@ error_code sceNp2Term(ppu_thread& ppu)
return CELL_OK;
}

error_code sceNpMatching2Term(ppu_thread&)
error_code sceNpMatching2Term(ppu_thread& ppu)
{
sceNp2.warning("sceNpMatching2Term()");
return sceNpMatching2Term2(); // > SDK 2.4.0
return sceNpMatching2Term2(ppu); // > SDK 2.4.0
}

error_code sceNpMatching2Term2()
error_code sceNpMatching2Term2(ppu_thread& ppu)
{
sceNp2.warning("sceNpMatching2Term2()");

auto& nph = g_fxo->get<named_thread<np::np_handler>>();

u32 ppu_id = 0;
{
std::lock_guard lock(nph.mutex_status);
if (!nph.is_NP2_init)
Expand All @@ -311,8 +364,15 @@ error_code sceNpMatching2Term2()
}

nph.is_NP2_Match2_init = false;

ppu_id = ensure(std::exchange(nph.np2_match2_thread_id, 0));

const auto ptr = ensure(idm::get<named_thread<ppu_thread>>(ppu_id));
lv2_obj::awake(ptr.get());
}

ensure(sys_ppu_thread_join(ppu, ppu_id, +vm::var<u64>{}) == CELL_OK);

// TODO: for all contexts: sceNpMatching2DestroyContext

return CELL_OK;
Expand Down Expand Up @@ -1789,8 +1849,8 @@ error_code sceNpAuthGetAuthorizationCode2()
return CELL_OK;
}

DECLARE(ppu_module_manager::sceNp2)
("sceNp2", []() {
DECLARE(ppu_module_manager::sceNp2)("sceNp2", []()
{
REG_FUNC(sceNp2, sceNpMatching2DestroyContext);
REG_FUNC(sceNp2, sceNpMatching2LeaveLobby);
REG_FUNC(sceNp2, sceNpMatching2RegisterLobbyMessageCallback);
Expand Down Expand Up @@ -1872,4 +1932,6 @@ DECLARE(ppu_module_manager::sceNp2)
REG_FUNC(sceNp2, sceNpAuthAbortOAuthRequest);
REG_FUNC(sceNp2, sceNpAuthGetAuthorizationCode);
REG_FUNC(sceNp2, sceNpAuthGetAuthorizationCode2);

REG_HIDDEN_FUNC(s_matching2_thread_func);
});
3 changes: 3 additions & 0 deletions rpcs3/Emu/Cell/Modules/sysPrxForUser.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,9 @@ error_code sys_lwcond_wait(ppu_thread& CPU, vm::ptr<sys_lwcond_t> lwcond, u64 ti
error_code sys_ppu_thread_create(ppu_thread& ppu, vm::ptr<u64> thread_id, u32 entry, u64 arg, s32 prio, u32 stacksize, u64 flags, vm::cptr<char> threadname);
error_code sys_interrupt_thread_disestablish(ppu_thread& ppu, u32 ih);

u32 _sys_malloc(ppu_thread& ppu, u32 size);
error_code _sys_free(ppu_thread& ppu, u32 addr);

void sys_ppu_thread_exit(ppu_thread& CPU, u64 val);
void sys_game_process_exitspawn(ppu_thread& ppu, vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32 data, u32 data_size, s32 prio, u64 flags);
void sys_game_process_exitspawn2(ppu_thread& ppu, vm::cptr<char> path, vm::cpptr<char> argv, vm::cpptr<char> envp, u32 data, u32 data_size, s32 prio, u64 flags);
14 changes: 13 additions & 1 deletion rpcs3/Emu/Cell/Modules/sys_io_.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,10 @@
#include "Emu/System.h"
#include "Emu/IdManager.h"
#include "Emu/Cell/PPUModule.h"
#include "Emu/Cell/lv2/sys_ppu_thread.h"
#include "Emu/Cell/lv2/sys_sync.h"
#include "Emu/Cell/Modules/sysPrxForUser.h"


#include "Emu/Cell/lv2/sys_event.h"
#include "Emu/Cell/lv2/sys_ppu_thread.h"
Expand All @@ -19,6 +23,7 @@ struct libio_sys_config
s32 init_ctr = 0;
u32 ppu_id = 0;
u32 queue_id = 0;
u32 malloc_addr = 0;

~libio_sys_config() noexcept
{
Expand All @@ -38,14 +43,19 @@ void config_event_entry(ppu_thread& ppu)
{
if (ppu.is_stopped())
{
ppu.state += cpu_flag::again;
return;
}

// Some delay
thread_ctrl::wait_for(10000);

// Wakeup
ppu.check_state();
if (ppu.check_state())
{
ppu.state += cpu_flag::again;
return;
}

const u64 arg1 = ppu.gpr[5];
const u64 arg2 = ppu.gpr[6];
Expand Down Expand Up @@ -97,6 +107,7 @@ error_code sys_config_start(ppu_thread& ppu)
attr->type = SYS_PPU_QUEUE;
attr->name_u64 = 0;

ensure(!!(cfg.malloc_addr = ppu_execute<&_sys_malloc>(ppu, 0x7720 + + 0x28 + 0xe90 + 0x14)));
ensure(CELL_OK == sys_event_queue_create(ppu, queue_id, attr, 0, 0x20));
ensure(CELL_OK == ppu_execute<&sys_ppu_thread_create>(ppu, +_tid, g_fxo->get<ppu_function_manager>().func_addr(FIND_FUNC(config_event_entry)), 0, 512, 0x2000, SYS_PPU_THREAD_CREATE_JOINABLE, +_name));

Expand All @@ -119,6 +130,7 @@ error_code sys_config_stop(ppu_thread& ppu)
{
ensure(CELL_OK == sys_event_queue_destroy(ppu, cfg.queue_id, SYS_EVENT_QUEUE_DESTROY_FORCE));
ensure(CELL_OK == sys_ppu_thread_join(ppu, cfg.ppu_id, +vm::var<u64>{}));
ensure(CELL_OK == ppu_execute<&_sys_free>(ppu, cfg.malloc_addr));
}
else
{
Expand Down
8 changes: 6 additions & 2 deletions rpcs3/Emu/Cell/Modules/sys_libc_.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -367,8 +367,10 @@ vm::cptr<char> _sys_strrchr(vm::cptr<char> str, char ch)
return res;
}

u32 _sys_malloc(u32 size)
u32 _sys_malloc(ppu_thread& ppu, u32 size)
{
ppu.state += cpu_flag::wait;

sysPrxForUser.warning("_sys_malloc(size=0x%x)", size);

return vm::alloc(size, vm::main);
Expand All @@ -381,8 +383,10 @@ u32 _sys_memalign(u32 align, u32 size)
return vm::alloc(size, vm::main, std::max<u32>(align, 0x10000));
}

error_code _sys_free(u32 addr)
error_code _sys_free(ppu_thread& ppu, u32 addr)
{
ppu.state += cpu_flag::wait;

sysPrxForUser.warning("_sys_free(addr=0x%x)", addr);

vm::dealloc(addr, vm::main);
Expand Down
Loading

0 comments on commit 1d9ab8e

Please sign in to comment.