Compare commits

...

7 Commits

21 changed files with 258 additions and 147 deletions

View File

@ -145,4 +145,13 @@ bool SDLAudio::AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume) {
return true; return true;
} }
bool SDLAudio::AudioOutGetStatus(s32 handle, int* type, int* channels_num) {
std::scoped_lock lock{m_mutex};
auto& port = portsOut[handle - 1];
*type = port.type;
*channels_num = port.channels_num;
return true;
}
} // namespace Audio } // namespace Audio

View File

@ -18,6 +18,7 @@ public:
Libraries::AudioOut::OrbisAudioOutParam format); Libraries::AudioOut::OrbisAudioOutParam format);
s32 AudioOutOutput(s32 handle, const void* ptr); s32 AudioOutOutput(s32 handle, const void* ptr);
bool AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume); bool AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume);
bool AudioOutGetStatus(s32 handle, int* type, int* channels_num);
private: private:
struct PortOut { struct PortOut {

View File

@ -41,6 +41,8 @@ enum MarkersPallete : int {
#define RENDERER_TRACE ZoneScopedC(RendererMarkerColor) #define RENDERER_TRACE ZoneScopedC(RendererMarkerColor)
#define HLE_TRACE ZoneScopedC(HleMarkerColor) #define HLE_TRACE ZoneScopedC(HleMarkerColor)
#define TRACE_HINT(str) ZoneText(str.c_str(), str.size())
#define TRACE_WARN(msg) \ #define TRACE_WARN(msg) \
[](const auto& msg) { TracyMessageC(msg.c_str(), msg.size(), tracy::Color::DarkOrange); }(msg); [](const auto& msg) { TracyMessageC(msg.c_str(), msg.size(), tracy::Color::DarkOrange); }(msg);
#define TRACE_ERROR(msg) \ #define TRACE_ERROR(msg) \

View File

@ -12,7 +12,7 @@
#include "common/assert.h" #include "common/assert.h"
#include "common/types.h" #include "common/types.h"
namespace VideoCore { namespace Common {
struct SlotId { struct SlotId {
static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max(); static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max();
@ -54,6 +54,13 @@ public:
return values[id.index].object; return values[id.index].object;
} }
bool is_allocated(SlotId id) const {
if (id && id.index / 64 < stored_bitset.size()) {
return ((stored_bitset[id.index / 64] >> (id.index % 64)) & 1) != 0;
}
return false;
}
template <typename... Args> template <typename... Args>
[[nodiscard]] SlotId insert(Args&&... args) noexcept { [[nodiscard]] SlotId insert(Args&&... args) noexcept {
const u32 index = FreeValueIndex(); const u32 index = FreeValueIndex();
@ -162,11 +169,11 @@ private:
std::vector<u32> free_list; std::vector<u32> free_list;
}; };
} // namespace VideoCore } // namespace Common
template <> template <>
struct std::hash<VideoCore::SlotId> { struct std::hash<Common::SlotId> {
std::size_t operator()(const VideoCore::SlotId& id) const noexcept { std::size_t operator()(const Common::SlotId& id) const noexcept {
return std::hash<u32>{}(id.index); return std::hash<u32>{}(id.index);
} }
}; };

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include <memory> #include <memory>
#include <common/assert.h>
#include <magic_enum.hpp> #include <magic_enum.hpp>
#include "audio_core/sdl_audio.h" #include "audio_core/sdl_audio.h"
#include "common/logging/log.h" #include "common/logging/log.h"
@ -160,8 +161,38 @@ int PS4_SYSV_ABI sceAudioOutGetLastOutputTime() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceAudioOutGetPortState() { int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* state) {
LOG_ERROR(Lib_AudioOut, "(STUBBED) called");
int type = 0;
int channels_num = 0;
if (!audio->AudioOutGetStatus(handle, &type, &channels_num)) {
return ORBIS_AUDIO_OUT_ERROR_INVALID_PORT;
}
state->rerouteCounter = 0;
state->volume = 127; // max volume
switch (type) {
case ORBIS_AUDIO_OUT_PORT_TYPE_MAIN:
case ORBIS_AUDIO_OUT_PORT_TYPE_BGM:
case ORBIS_AUDIO_OUT_PORT_TYPE_VOICE:
state->output = 1;
state->channel = (channels_num > 2 ? 2 : channels_num);
break;
case ORBIS_AUDIO_OUT_PORT_TYPE_PERSONAL:
case ORBIS_AUDIO_OUT_PORT_TYPE_PADSPK:
state->output = 4;
state->channel = 1;
break;
case ORBIS_AUDIO_OUT_PORT_TYPE_AUX:
state->output = 0;
state->channel = 0;
break;
default:
UNREACHABLE();
}
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -34,6 +34,16 @@ struct OrbisAudioOutOutputParam {
const void* ptr; const void* ptr;
}; };
struct OrbisAudioOutPortState {
u16 output;
u8 channel;
u8 reserved8_1[1];
s16 volume;
u16 rerouteCounter;
u64 flag;
u64 reserved64[2];
};
int PS4_SYSV_ABI sceAudioOutDeviceIdOpen(); int PS4_SYSV_ABI sceAudioOutDeviceIdOpen();
int PS4_SYSV_ABI sceAudioDeviceControlGet(); int PS4_SYSV_ABI sceAudioDeviceControlGet();
int PS4_SYSV_ABI sceAudioDeviceControlSet(); int PS4_SYSV_ABI sceAudioDeviceControlSet();
@ -55,7 +65,7 @@ int PS4_SYSV_ABI sceAudioOutGetHandleStatusInfo();
int PS4_SYSV_ABI sceAudioOutGetInfo(); int PS4_SYSV_ABI sceAudioOutGetInfo();
int PS4_SYSV_ABI sceAudioOutGetInfoOpenNum(); int PS4_SYSV_ABI sceAudioOutGetInfoOpenNum();
int PS4_SYSV_ABI sceAudioOutGetLastOutputTime(); int PS4_SYSV_ABI sceAudioOutGetLastOutputTime();
int PS4_SYSV_ABI sceAudioOutGetPortState(); int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* state);
int PS4_SYSV_ABI sceAudioOutGetSimulatedBusUsableStatusByBusType(); int PS4_SYSV_ABI sceAudioOutGetSimulatedBusUsableStatusByBusType();
int PS4_SYSV_ABI sceAudioOutGetSimulatedHandleStatusInfo(); int PS4_SYSV_ABI sceAudioOutGetSimulatedHandleStatusInfo();
int PS4_SYSV_ABI sceAudioOutGetSimulatedHandleStatusInfo2(); int PS4_SYSV_ABI sceAudioOutGetSimulatedHandleStatusInfo2();

View File

@ -446,3 +446,10 @@ constexpr int ORBIS_USER_SERVICE_ERROR_BUFFER_TOO_SHORT = 0x8096000A;
// SystemService library // SystemService library
constexpr int ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER = 0x80A10003; constexpr int ORBIS_SYSTEM_SERVICE_ERROR_PARAMETER = 0x80A10003;
// NpTrophy library
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT = 0x80551604;
constexpr int ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE = 0x80551608;
constexpr int ORBIS_NP_TROPHY_ERROR_HANDLE_EXCEEDS_MAX = 0x80551624;
constexpr int ORBIS_NP_TROPHY_ERROR_CONTEXT_ALREADY_EXISTS = 0x80551613;
constexpr int ORBIS_NP_TROPHY_ERROR_CONTEXT_EXCEEDS_MAX = 0x80551622;

View File

@ -39,7 +39,7 @@ struct AscQueueInfo {
u32* read_addr; u32* read_addr;
u32 ring_size_dw; u32 ring_size_dw;
}; };
static VideoCore::SlotVector<AscQueueInfo> asc_queues{}; static Common::SlotVector<AscQueueInfo> asc_queues{};
static constexpr VAddr tessellation_factors_ring_addr = 0xFF0000000ULL; static constexpr VAddr tessellation_factors_ring_addr = 0xFF0000000ULL;
static void DumpCommandList(std::span<const u32> cmd_list, const std::string& postfix) { static void DumpCommandList(std::span<const u32> cmd_list, const std::string& postfix) {

View File

@ -8,13 +8,19 @@ namespace Libraries::Kernel {
EqueueInternal::~EqueueInternal() = default; EqueueInternal::~EqueueInternal() = default;
int EqueueInternal::addEvent(const EqueueEvent& event) { int EqueueInternal::addEvent(EqueueEvent& event) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
ASSERT(!event.isTriggered); const auto start_clock = std::chrono::high_resolution_clock::now();
event.filter.added_time_us =
std::chrono::time_point_cast<std::chrono::microseconds>(start_clock);
// TODO check if event is already exists and return it. Currently we just add in m_events array const auto& it = std::ranges::find(m_events, event);
m_events.push_back(event); if (it != m_events.cend()) {
*it = event;
} else {
m_events.push_back(event);
}
return 0; return 0;
} }
@ -50,8 +56,8 @@ bool EqueueInternal::triggerEvent(u64 ident, s16 filter, void* trigger_data) {
std::scoped_lock lock{m_mutex}; std::scoped_lock lock{m_mutex};
for (auto& event : m_events) { for (auto& event : m_events) {
if (event.event.ident == ident) { // event filter? if (event.event.ident == ident && event.event.filter == filter) {
event.trigger(trigger_data); event.Trigger(trigger_data);
} }
} }
} }
@ -64,9 +70,9 @@ int EqueueInternal::getTriggeredEvents(SceKernelEvent* ev, int num) {
int ret = 0; int ret = 0;
for (auto& event : m_events) { for (auto& event : m_events) {
if (event.isTriggered) { if (event.IsTriggered()) {
ev[ret++] = event.event; ev[ret++] = event.event;
event.reset(); event.Reset();
} }
} }

View File

@ -70,24 +70,44 @@ struct SceKernelEvent {
struct Filter { struct Filter {
void* data = nullptr; void* data = nullptr;
std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds> added_time_us;
}; };
struct EqueueEvent { struct EqueueEvent {
bool isTriggered = false;
SceKernelEvent event; SceKernelEvent event;
Filter filter; Filter filter;
void reset() { void Reset() {
isTriggered = false; is_triggered = false;
event.fflags = 0; event.fflags = 0;
event.data = 0; event.data = 0;
} }
void trigger(void* data) { void Trigger(void* data) {
isTriggered = true; is_triggered = true;
event.fflags++; event.fflags++;
event.data = reinterpret_cast<uintptr_t>(data); event.data = reinterpret_cast<uintptr_t>(data);
} }
bool IsTriggered() const {
if (event.filter == Kernel::EVFILT_HRTIMER) {
// For HR timers we don't want to waste time on spawning waiters. Instead, we will check
// for time out condition every time caller fetches the event status.
const auto now_clock = std::chrono::high_resolution_clock::now();
const auto now_time_us =
std::chrono::time_point_cast<std::chrono::microseconds>(now_clock);
const auto delta = (now_time_us - filter.added_time_us).count();
return (s64(event.data) - delta) <= 0;
}
return is_triggered;
}
bool operator==(const EqueueEvent& ev) const {
return ev.event.ident == event.ident;
}
private:
bool is_triggered = false;
}; };
class EqueueInternal { class EqueueInternal {
@ -97,7 +117,10 @@ public:
void setName(const std::string& m_name) { void setName(const std::string& m_name) {
this->m_name = m_name; this->m_name = m_name;
} }
int addEvent(const EqueueEvent& event); const auto& GetName() const {
return m_name;
}
int addEvent(EqueueEvent& event);
int removeEvent(u64 id); int removeEvent(u64 id);
int waitForEvents(SceKernelEvent* ev, int num, u32 micros); int waitForEvents(SceKernelEvent* ev, int num, u32 micros);
bool triggerEvent(u64 ident, s16 filter, void* trigger_data); bool triggerEvent(u64 ident, s16 filter, void* trigger_data);

View File

@ -2,6 +2,7 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
#include "common/assert.h" #include "common/assert.h"
#include "common/debug.h"
#include "common/logging/log.h" #include "common/logging/log.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/kernel/event_queues.h" #include "core/libraries/kernel/event_queues.h"
@ -43,7 +44,9 @@ int PS4_SYSV_ABI sceKernelDeleteEqueue(SceKernelEqueue eq) {
int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int num, int* out, int PS4_SYSV_ABI sceKernelWaitEqueue(SceKernelEqueue eq, SceKernelEvent* ev, int num, int* out,
SceKernelUseconds* timo) { SceKernelUseconds* timo) {
LOG_INFO(Kernel_Event, "num = {}", num); HLE_TRACE;
TRACE_HINT(eq->GetName());
LOG_INFO(Kernel_Event, "equeue = {} num = {}", eq->GetName(), num);
if (eq == nullptr) { if (eq == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF; return ORBIS_KERNEL_ERROR_EBADF;
@ -84,7 +87,6 @@ int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
} }
Kernel::EqueueEvent event{}; Kernel::EqueueEvent event{};
event.isTriggered = false;
event.event.ident = id; event.event.ident = id;
event.event.filter = Kernel::EVFILT_USER; event.event.filter = Kernel::EVFILT_USER;
event.event.udata = 0; event.event.udata = 0;
@ -101,7 +103,6 @@ int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id) {
} }
Kernel::EqueueEvent event{}; Kernel::EqueueEvent event{};
event.isTriggered = false;
event.event.ident = id; event.event.ident = id;
event.event.filter = Kernel::EVFILT_USER; event.event.filter = Kernel::EVFILT_USER;
event.event.udata = 0; event.event.udata = 0;
@ -112,6 +113,28 @@ int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id) {
return eq->addEvent(event); return eq->addEvent(event);
} }
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata) {
if (eq == nullptr) {
return ORBIS_KERNEL_ERROR_EBADF;
}
if (ts->tv_sec > 100 || ts->tv_nsec < 100'000) {
return ORBIS_KERNEL_ERROR_EINVAL;
}
ASSERT(ts->tv_nsec > 1000); // assume 1us granularity
const auto total_us = ts->tv_sec * 1000'000 + ts->tv_nsec / 1000;
Kernel::EqueueEvent event{};
event.event.ident = id;
event.event.filter = Kernel::EVFILT_HRTIMER;
event.event.flags = 0x11;
event.event.fflags = 0;
event.event.data = total_us;
event.event.udata = udata;
return eq->addEvent(event);
}
void* PS4_SYSV_ABI sceKernelGetEventUserData(const SceKernelEvent* ev) { void* PS4_SYSV_ABI sceKernelGetEventUserData(const SceKernelEvent* ev) {
if (!ev) { if (!ev) {
return nullptr; return nullptr;

View File

@ -19,5 +19,6 @@ int PS4_SYSV_ABI sceKernelTriggerUserEvent(SceKernelEqueue eq, int id, void* uda
int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id); int PS4_SYSV_ABI sceKernelDeleteUserEvent(SceKernelEqueue eq, int id);
int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id); int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id);
int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id); int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id);
s32 PS4_SYSV_ABI sceKernelAddHRTimerEvent(SceKernelEqueue eq, int id, timespec* ts, void* udata);
} // namespace Libraries::Kernel } // namespace Libraries::Kernel

View File

@ -328,6 +328,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("vz+pg2zdopI", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventUserData); LIB_FUNCTION("vz+pg2zdopI", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventUserData);
LIB_FUNCTION("4R6-OvI2cEA", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEvent); LIB_FUNCTION("4R6-OvI2cEA", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEvent);
LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge); LIB_FUNCTION("WDszmSbWuDk", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEventEdge);
LIB_FUNCTION("R74tt43xP6k", "libkernel", 1, "libkernel", 1, 1, sceKernelAddHRTimerEvent);
LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent); LIB_FUNCTION("F6e0kwo4cnk", "libkernel", 1, "libkernel", 1, 1, sceKernelTriggerUserEvent);
LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent); LIB_FUNCTION("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);

View File

@ -1278,6 +1278,7 @@ int PS4_SYSV_ABI scePthreadOnce(int* once_control, void (*init_routine)(void)) {
[[noreturn]] void PS4_SYSV_ABI scePthreadExit(void* value_ptr) { [[noreturn]] void PS4_SYSV_ABI scePthreadExit(void* value_ptr) {
pthread_exit(value_ptr); pthread_exit(value_ptr);
UNREACHABLE();
} }
void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) { void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
@ -1323,6 +1324,8 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
LIB_FUNCTION("Ru36fiTtJzA", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstackaddr); LIB_FUNCTION("Ru36fiTtJzA", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstackaddr);
LIB_FUNCTION("-fA+7ZlGDQs", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstacksize); LIB_FUNCTION("-fA+7ZlGDQs", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstacksize);
LIB_FUNCTION("14bOACANTBo", "libkernel", 1, "libkernel", 1, 1, scePthreadOnce); LIB_FUNCTION("14bOACANTBo", "libkernel", 1, "libkernel", 1, 1, scePthreadOnce);
LIB_FUNCTION("F+yfmduIBB8", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetstackaddr);
LIB_FUNCTION("El+cQ20DynU", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrSetguardsize);
// mutex calls // mutex calls
LIB_FUNCTION("cmo1RIYva9o", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexInit); LIB_FUNCTION("cmo1RIYva9o", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexInit);

View File

@ -13,128 +13,60 @@
namespace Libraries::Kernel { namespace Libraries::Kernel {
using ListBaseHook =
boost::intrusive::list_base_hook<boost::intrusive::link_mode<boost::intrusive::normal_link>>;
class Semaphore { class Semaphore {
public: public:
Semaphore(s32 init_count, s32 max_count, const char* name, bool is_fifo) Semaphore(s32 init_count, s32 max_count, const char* name, bool is_fifo)
: name{name}, token_count{init_count}, max_count{max_count}, is_fifo{is_fifo} {} : name{name}, token_count{init_count}, max_count{max_count}, is_fifo{is_fifo} {}
bool Wait(bool can_block, s32 need_count, u64* timeout) { bool Wait(bool can_block, s32 need_count, u64* timeout) {
if (HasAvailableTokens(need_count)) { if (need_count < 1 || need_count > max_count) {
return true;
}
if (!can_block) {
return false; return false;
} }
// Create waiting thread object and add it into the list of waiters. std::unique_lock<std::mutex> lock{mutex};
WaitingThread waiter{need_count, is_fifo}; auto pred = [this, need_count] { return token_count >= need_count; };
AddWaiter(waiter); if (!timeout) {
SCOPE_EXIT { cond.wait(lock, pred);
PopWaiter(waiter); token_count -= need_count;
}; } else {
const auto time_ms = std::chrono::microseconds(*timeout);
const auto start = std::chrono::high_resolution_clock::now();
// Perform the wait. bool result = cond.wait_for(lock, time_ms, pred);
return waiter.Wait(timeout);
}
bool Signal(s32 signal_count) { auto end = std::chrono::high_resolution_clock::now();
std::scoped_lock lk{mutex}; if (result) {
if (token_count + signal_count > max_count) { const auto delta =
return false; std::chrono::duration_cast<std::chrono::microseconds>(end - start);
} const auto time_remain = time_ms - delta;
token_count += signal_count; *timeout = time_remain.count();
token_count -= need_count;
// Wake up threads in order of priority. } else {
for (auto& waiter : wait_list) { *timeout = 0;
if (waiter.need_count > token_count) { return false;
continue;
} }
token_count -= waiter.need_count;
waiter.cv.notify_one();
} }
return true; return true;
} }
bool Signal(s32 signal_count) {
std::unique_lock<std::mutex> lock{mutex};
if (token_count + signal_count > max_count) {
return false;
}
token_count += signal_count;
cond.notify_all();
return true;
}
private: private:
struct WaitingThread : public ListBaseHook {
std::mutex mutex;
std::condition_variable cv;
u32 priority;
s32 need_count;
explicit WaitingThread(s32 need_count, bool is_fifo) : need_count{need_count} {
if (is_fifo) {
return;
}
// Retrieve calling thread priority for sorting into waiting threads list.
s32 policy;
sched_param param;
pthread_getschedparam(pthread_self(), &policy, &param);
priority = param.sched_priority;
}
bool Wait(u64* timeout) {
std::unique_lock lk{mutex};
if (!timeout) {
// Wait indefinitely until we are woken up.
cv.wait(lk);
return true;
}
// Wait until timeout runs out, recording how much remaining time there was.
const auto start = std::chrono::high_resolution_clock::now();
const auto status = cv.wait_for(lk, std::chrono::microseconds(*timeout));
const auto end = std::chrono::high_resolution_clock::now();
const auto time =
std::chrono::duration_cast<std::chrono::microseconds>(end - start).count();
*timeout -= time;
return status != std::cv_status::timeout;
}
bool operator<(const WaitingThread& other) const {
return priority < other.priority;
}
};
void AddWaiter(WaitingThread& waiter) {
std::scoped_lock lk{mutex};
// Insert at the end of the list for FIFO order.
if (is_fifo) {
wait_list.push_back(waiter);
return;
}
// Find the first with priority less then us and insert right before it.
auto it = wait_list.begin();
while (it != wait_list.end() && it->priority > waiter.priority) {
it++;
}
wait_list.insert(it, waiter);
}
void PopWaiter(WaitingThread& waiter) {
std::scoped_lock lk{mutex};
wait_list.erase(WaitingThreads::s_iterator_to(waiter));
}
bool HasAvailableTokens(s32 need_count) {
std::scoped_lock lk{mutex};
if (token_count >= need_count) {
token_count -= need_count;
return true;
}
return false;
}
using WaitingThreads =
boost::intrusive::list<WaitingThread, boost::intrusive::base_hook<ListBaseHook>,
boost::intrusive::constant_time_size<false>>;
WaitingThreads wait_list;
std::string name; std::string name;
std::atomic<s32> token_count; s32 token_count;
std::mutex mutex; std::mutex mutex;
std::condition_variable cond;
s32 max_count; s32 max_count;
bool is_fifo; bool is_fifo;
}; };

View File

@ -2,14 +2,34 @@
// SPDX-License-Identifier: GPL-2.0-or-later // SPDX-License-Identifier: GPL-2.0-or-later
// Generated By moduleGenerator // Generated By moduleGenerator
#include <unordered_map>
#include "common/logging/log.h" #include "common/logging/log.h"
#include "common/slot_vector.h"
#include "core/libraries/error_codes.h" #include "core/libraries/error_codes.h"
#include "core/libraries/libs.h" #include "core/libraries/libs.h"
#include "np_trophy.h" #include "np_trophy.h"
namespace Libraries::NpTrophy { namespace Libraries::NpTrophy {
int PS4_SYSV_ABI sceNpTrophyAbortHandle() { static constexpr auto MaxTrophyHandles = 4u;
static constexpr auto MaxTrophyContexts = 8u;
using ContextKey = std::pair<u32, u32>; // <user_id, service label>
struct ContextKeyHash {
size_t operator()(const ContextKey& key) const {
return key.first + (u64(key.second) << 32u);
}
};
struct TrophyContext {
u32 context_id;
};
static Common::SlotVector<u32> trophy_handles{};
static Common::SlotVector<ContextKey> trophy_contexts{};
static std::unordered_map<ContextKey, TrophyContext, ContextKeyHash> contexts_internal{};
static int PS4_SYSV_ABI sceNpTrophyAbortHandle() {
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
return ORBIS_OK; return ORBIS_OK;
} }
@ -64,14 +84,43 @@ int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpTrophyCreateContext() { s32 PS4_SYSV_ABI sceNpTrophyCreateContext(u32* context, u32 user_id, u32 service_label,
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); u64 options) {
ASSERT(options == 0ull);
if (!context) {
return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT;
}
if (trophy_contexts.size() >= MaxTrophyContexts) {
return ORBIS_NP_TROPHY_ERROR_CONTEXT_EXCEEDS_MAX;
}
const auto& key = ContextKey{user_id, service_label};
if (contexts_internal.contains(key)) {
return ORBIS_NP_TROPHY_ERROR_CONTEXT_ALREADY_EXISTS;
}
const auto ctx_id = trophy_contexts.insert(user_id, service_label);
contexts_internal[key].context_id = ctx_id.index;
LOG_INFO(Lib_NpTrophy, "New context = {}, user_id = {} service label = {}", ctx_id.index,
user_id, service_label);
*context = ctx_id.index;
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpTrophyCreateHandle() { s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(u32* handle) {
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); if (!handle) {
return -1; return ORBIS_NP_TROPHY_ERROR_INVALID_ARGUMENT;
}
if (trophy_handles.size() >= MaxTrophyHandles) {
return ORBIS_NP_TROPHY_ERROR_HANDLE_EXCEEDS_MAX;
}
const auto handle_id = trophy_handles.insert();
LOG_INFO(Lib_NpTrophy, "New handle = {}", handle_id.index);
*handle = handle_id.index;
return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpTrophyDestroyContext() { int PS4_SYSV_ABI sceNpTrophyDestroyContext() {
@ -79,8 +128,13 @@ int PS4_SYSV_ABI sceNpTrophyDestroyContext() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpTrophyDestroyHandle() { s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(u32 handle) {
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); if (!trophy_handles.is_allocated({handle})) {
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
}
trophy_handles.erase({handle});
LOG_INFO(Lib_NpTrophy, "Handle {} destroyed", handle);
return ORBIS_OK; return ORBIS_OK;
} }
@ -114,8 +168,10 @@ int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo() {
return ORBIS_OK; return ORBIS_OK;
} }
int PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState() { s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, u32* flags, u32* count) {
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called"); LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
*flags = 0u;
*count = 0;
return ORBIS_OK; return ORBIS_OK;
} }

View File

@ -22,17 +22,18 @@ int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetInfoInGroup();
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetVersion(); int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetVersion();
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophyTitleDetails(); int PS4_SYSV_ABI sceNpTrophyConfigGetTrophyTitleDetails();
int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature(); int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature();
int PS4_SYSV_ABI sceNpTrophyCreateContext(); s32 PS4_SYSV_ABI sceNpTrophyCreateContext(u32* context, u32 user_id, u32 service_label,
int PS4_SYSV_ABI sceNpTrophyCreateHandle(); u64 options);
s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(u32* handle);
int PS4_SYSV_ABI sceNpTrophyDestroyContext(); int PS4_SYSV_ABI sceNpTrophyDestroyContext();
int PS4_SYSV_ABI sceNpTrophyDestroyHandle(); s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(u32 handle);
int PS4_SYSV_ABI sceNpTrophyGetGameIcon(); int PS4_SYSV_ABI sceNpTrophyGetGameIcon();
int PS4_SYSV_ABI sceNpTrophyGetGameInfo(); int PS4_SYSV_ABI sceNpTrophyGetGameInfo();
int PS4_SYSV_ABI sceNpTrophyGetGroupIcon(); int PS4_SYSV_ABI sceNpTrophyGetGroupIcon();
int PS4_SYSV_ABI sceNpTrophyGetGroupInfo(); int PS4_SYSV_ABI sceNpTrophyGetGroupInfo();
int PS4_SYSV_ABI sceNpTrophyGetTrophyIcon(); int PS4_SYSV_ABI sceNpTrophyGetTrophyIcon();
int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo(); int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo();
int PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(); s32 PS4_SYSV_ABI sceNpTrophyGetTrophyUnlockState(u32 context, u32 handle, u32* flags, u32* count);
int PS4_SYSV_ABI sceNpTrophyGroupArrayGetNum(); int PS4_SYSV_ABI sceNpTrophyGroupArrayGetNum();
int PS4_SYSV_ABI sceNpTrophyIntAbortHandle(); int PS4_SYSV_ABI sceNpTrophyIntAbortHandle();
int PS4_SYSV_ABI sceNpTrophyIntCheckNetSyncTitles(); int PS4_SYSV_ABI sceNpTrophyIntCheckNetSyncTitles();

View File

@ -48,7 +48,6 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle,
} }
Kernel::EqueueEvent event{}; Kernel::EqueueEvent event{};
event.isTriggered = false;
event.event.ident = SCE_VIDEO_OUT_EVENT_FLIP; event.event.ident = SCE_VIDEO_OUT_EVENT_FLIP;
event.event.filter = Kernel::EVFILT_VIDEO_OUT; event.event.filter = Kernel::EVFILT_VIDEO_OUT;
event.event.udata = udata; event.event.udata = udata;
@ -73,7 +72,6 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handl
} }
Kernel::EqueueEvent event{}; Kernel::EqueueEvent event{};
event.isTriggered = false;
event.event.ident = SCE_VIDEO_OUT_EVENT_VBLANK; event.event.ident = SCE_VIDEO_OUT_EVENT_VBLANK;
event.event.filter = Kernel::EVFILT_VIDEO_OUT; event.event.filter = Kernel::EVFILT_VIDEO_OUT;
event.event.udata = udata; event.event.udata = udata;

View File

@ -100,7 +100,7 @@ private:
vk::Image image{}; vk::Image image{};
}; };
constexpr SlotId NULL_IMAGE_ID{0}; constexpr Common::SlotId NULL_IMAGE_ID{0};
struct Image { struct Image {
explicit Image(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler, explicit Image(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler,

View File

@ -140,8 +140,8 @@ private:
Vulkan::Scheduler& scheduler; Vulkan::Scheduler& scheduler;
Vulkan::StreamBuffer staging; Vulkan::StreamBuffer staging;
TileManager tile_manager; TileManager tile_manager;
SlotVector<Image> slot_images; Common::SlotVector<Image> slot_images;
SlotVector<ImageView> slot_image_views; Common::SlotVector<ImageView> slot_image_views;
tsl::robin_map<u64, Sampler> samplers; tsl::robin_map<u64, Sampler> samplers;
tsl::robin_pg_map<u64, std::vector<ImageId>> page_table; tsl::robin_pg_map<u64, std::vector<ImageId>> page_table;
boost::icl::interval_map<VAddr, s32> cached_pages; boost::icl::interval_map<VAddr, s32> cached_pages;

View File

@ -8,8 +8,8 @@
namespace VideoCore { namespace VideoCore {
using ImageId = SlotId; using ImageId = Common::SlotId;
using ImageViewId = SlotId; using ImageViewId = Common::SlotId;
struct Offset2D { struct Offset2D {
s32 x; s32 x;