Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

More accurate PS3 memory consumption #12747

Open
wants to merge 1 commit into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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);
}
}

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);

// 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