Compare commits
16 Commits
main
...
anzu/initi
Author | SHA1 | Date |
---|---|---|
psucien | 42f6ab7670 | |
psucien | b8290ea521 | |
psucien | 966ff741d1 | |
georgemoralis | 022e0c2fbb | |
georgemoralis | 8760abd6b5 | |
psucien | 48fdf0d9e9 | |
psucien | f375e0cfb0 | |
psucien | 723e3cd0f9 | |
georgemoralis | 6f69b32555 | |
psucien | e92d636018 | |
psucien | 53dd407ae3 | |
psucien | a5d22b8151 | |
psucien | b23d17696b | |
psucien | fe30369349 | |
psucien | 76c92a9dfb | |
psucien | 307560a3fd |
|
@ -145,4 +145,13 @@ bool SDLAudio::AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume) {
|
|||
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
|
||||
|
|
|
@ -18,6 +18,7 @@ public:
|
|||
Libraries::AudioOut::OrbisAudioOutParam format);
|
||||
s32 AudioOutOutput(s32 handle, const void* ptr);
|
||||
bool AudioOutSetVolume(s32 handle, s32 bitflag, s32* volume);
|
||||
bool AudioOutGetStatus(s32 handle, int* type, int* channels_num);
|
||||
|
||||
private:
|
||||
struct PortOut {
|
||||
|
|
|
@ -41,6 +41,8 @@ enum MarkersPallete : int {
|
|||
#define RENDERER_TRACE ZoneScopedC(RendererMarkerColor)
|
||||
#define HLE_TRACE ZoneScopedC(HleMarkerColor)
|
||||
|
||||
#define TRACE_HINT(str) ZoneText(str.c_str(), str.size())
|
||||
|
||||
#define TRACE_WARN(msg) \
|
||||
[](const auto& msg) { TracyMessageC(msg.c_str(), msg.size(), tracy::Color::DarkOrange); }(msg);
|
||||
#define TRACE_ERROR(msg) \
|
||||
|
|
|
@ -12,7 +12,7 @@
|
|||
#include "common/assert.h"
|
||||
#include "common/types.h"
|
||||
|
||||
namespace VideoCore {
|
||||
namespace Common {
|
||||
|
||||
struct SlotId {
|
||||
static constexpr u32 INVALID_INDEX = std::numeric_limits<u32>::max();
|
||||
|
@ -54,6 +54,13 @@ public:
|
|||
return values[id.index].object;
|
||||
}
|
||||
|
||||
bool IsAllocated(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>
|
||||
[[nodiscard]] SlotId insert(Args&&... args) noexcept {
|
||||
const u32 index = FreeValueIndex();
|
||||
|
@ -162,11 +169,11 @@ private:
|
|||
std::vector<u32> free_list;
|
||||
};
|
||||
|
||||
} // namespace VideoCore
|
||||
} // namespace Common
|
||||
|
||||
template <>
|
||||
struct std::hash<VideoCore::SlotId> {
|
||||
std::size_t operator()(const VideoCore::SlotId& id) const noexcept {
|
||||
struct std::hash<Common::SlotId> {
|
||||
std::size_t operator()(const Common::SlotId& id) const noexcept {
|
||||
return std::hash<u32>{}(id.index);
|
||||
}
|
||||
};
|
||||
|
|
|
@ -28,15 +28,13 @@ void MntPoints::UnmountAll() {
|
|||
std::string MntPoints::GetHostDirectory(const std::string& guest_directory) {
|
||||
std::scoped_lock lock{m_mutex};
|
||||
for (auto& pair : m_mnt_pairs) {
|
||||
if (pair.guest_path.starts_with(guest_directory)) {
|
||||
return pair.host_path + guest_directory;
|
||||
}
|
||||
}
|
||||
// hack for relative path , get app0 and assuming it goes from there
|
||||
for (auto& pair : m_mnt_pairs) {
|
||||
if (pair.guest_path.starts_with("/app0")) {
|
||||
// horrible code but it works :D
|
||||
int find = guest_directory.find(pair.guest_path);
|
||||
if (find == 0) {
|
||||
std::string npath =
|
||||
guest_directory.substr(pair.guest_path.size(), guest_directory.size() - 1);
|
||||
std::replace(pair.host_path.begin(), pair.host_path.end(), '\\', '/');
|
||||
return pair.host_path + guest_directory;
|
||||
return pair.host_path + npath;
|
||||
}
|
||||
}
|
||||
return "";
|
||||
|
|
|
@ -32,13 +32,18 @@ private:
|
|||
std::mutex m_mutex;
|
||||
};
|
||||
|
||||
struct DirEntry {
|
||||
std::string name;
|
||||
bool isFile;
|
||||
};
|
||||
|
||||
struct File {
|
||||
std::atomic_bool is_opened{};
|
||||
std::atomic_bool is_directory{};
|
||||
std::string m_host_name;
|
||||
std::string m_guest_name;
|
||||
Common::FS::IOFile f;
|
||||
// std::vector<Common::FS::DirEntry> dirents;
|
||||
std::vector<DirEntry> dirents;
|
||||
u32 dirents_index;
|
||||
std::mutex m_mutex;
|
||||
};
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include <memory>
|
||||
#include <common/assert.h>
|
||||
#include <magic_enum.hpp>
|
||||
#include "audio_core/sdl_audio.h"
|
||||
#include "common/logging/log.h"
|
||||
|
@ -160,8 +161,38 @@ int PS4_SYSV_ABI sceAudioOutGetLastOutputTime() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceAudioOutGetPortState() {
|
||||
LOG_ERROR(Lib_AudioOut, "(STUBBED) called");
|
||||
int PS4_SYSV_ABI sceAudioOutGetPortState(s32 handle, OrbisAudioOutPortState* state) {
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
|
|
|
@ -34,6 +34,16 @@ struct OrbisAudioOutOutputParam {
|
|||
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 sceAudioDeviceControlGet();
|
||||
int PS4_SYSV_ABI sceAudioDeviceControlSet();
|
||||
|
@ -55,7 +65,7 @@ int PS4_SYSV_ABI sceAudioOutGetHandleStatusInfo();
|
|||
int PS4_SYSV_ABI sceAudioOutGetInfo();
|
||||
int PS4_SYSV_ABI sceAudioOutGetInfoOpenNum();
|
||||
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 sceAudioOutGetSimulatedHandleStatusInfo();
|
||||
int PS4_SYSV_ABI sceAudioOutGetSimulatedHandleStatusInfo2();
|
||||
|
|
|
@ -252,6 +252,7 @@ constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_QUEUE_ID = 0x80D17001;
|
|||
constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_RING_BASE_ADDR = 0x80D17003;
|
||||
constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_RING_SIZE = 0x80D17002;
|
||||
constexpr int ORBIS_GNM_ERROR_COMPUTEQUEUE_INVALID_READ_PTR_ADDR = 0x80D17004;
|
||||
constexpr int ORBIS_GNM_ERROR_FAILURE = 0x8EEE00FF;
|
||||
|
||||
// Generic
|
||||
constexpr int ORBIS_OK = 0x00000000;
|
||||
|
@ -445,3 +446,10 @@ constexpr int ORBIS_USER_SERVICE_ERROR_BUFFER_TOO_SHORT = 0x8096000A;
|
|||
|
||||
// SystemService library
|
||||
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;
|
||||
|
|
|
@ -38,7 +38,7 @@ struct AscQueueInfo {
|
|||
u32* read_addr;
|
||||
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 void DumpCommandList(std::span<const u32> cmd_list, const std::string& postfix) {
|
||||
|
@ -764,10 +764,12 @@ int PS4_SYSV_ABI sceGnmMapComputeQueue(u32 pipe_id, u32 queue_id, VAddr ring_bas
|
|||
}
|
||||
|
||||
auto vqid = asc_queues.insert(VAddr(ring_base_addr), read_ptr_addr, ring_size_dw);
|
||||
// We need to offset index as `dingDong` assumes it to be from the range [1..64]
|
||||
const auto gnm_vqid = vqid.index + 1;
|
||||
LOG_INFO(Lib_GnmDriver, "ASC pipe {} queue {} mapped to vqueue {}", pipe_id, queue_id,
|
||||
vqid.index);
|
||||
gnm_vqid);
|
||||
|
||||
return vqid.index;
|
||||
return gnm_vqid;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceGnmMapComputeQueueWithPriority(u32 pipe_id, u32 queue_id, VAddr ring_base_addr,
|
||||
|
@ -814,14 +816,16 @@ int PS4_SYSV_ABI sceGnmRegisterGnmLiveCallbackConfig() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceGnmRegisterOwner() {
|
||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
s32 PS4_SYSV_ABI sceGnmRegisterOwner(void* handle, const char* name) {
|
||||
LOG_TRACE(Lib_GnmDriver, "called");
|
||||
return ORBIS_GNM_ERROR_FAILURE; // PA Debug is always disabled in retail FW
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceGnmRegisterResource() {
|
||||
LOG_ERROR(Lib_GnmDriver, "(STUBBED) called");
|
||||
return ORBIS_OK;
|
||||
s32 PS4_SYSV_ABI sceGnmRegisterResource(void* res_handle, void* owner_handle, const void* addr,
|
||||
size_t size, const char* name, int res_type,
|
||||
u64 user_data) {
|
||||
LOG_TRACE(Lib_GnmDriver, "called");
|
||||
return ORBIS_GNM_ERROR_FAILURE; // PA Debug is always disabled in retail FW
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceGnmRequestFlipAndSubmitDone() {
|
||||
|
|
|
@ -125,8 +125,9 @@ int PS4_SYSV_ABI sceGnmQueryResourceRegistrationUserMemoryRequirements();
|
|||
int PS4_SYSV_ABI sceGnmRaiseUserExceptionEvent();
|
||||
int PS4_SYSV_ABI sceGnmRegisterGdsResource();
|
||||
int PS4_SYSV_ABI sceGnmRegisterGnmLiveCallbackConfig();
|
||||
int PS4_SYSV_ABI sceGnmRegisterOwner();
|
||||
int PS4_SYSV_ABI sceGnmRegisterResource();
|
||||
s32 PS4_SYSV_ABI sceGnmRegisterOwner(void* handle, const char* name);
|
||||
s32 PS4_SYSV_ABI sceGnmRegisterResource(void* res_handle, void* owner_handle, const void* addr,
|
||||
size_t size, const char* name, int res_type, u64 user_data);
|
||||
int PS4_SYSV_ABI sceGnmRequestFlipAndSubmitDone();
|
||||
int PS4_SYSV_ABI sceGnmRequestFlipAndSubmitDoneForWorkload();
|
||||
int PS4_SYSV_ABI sceGnmRequestMipStatsReportAndReset();
|
||||
|
|
|
@ -8,13 +8,19 @@ namespace Libraries::Kernel {
|
|||
|
||||
EqueueInternal::~EqueueInternal() = default;
|
||||
|
||||
int EqueueInternal::addEvent(const EqueueEvent& event) {
|
||||
int EqueueInternal::addEvent(EqueueEvent& event) {
|
||||
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
|
||||
m_events.push_back(event);
|
||||
const auto& it = std::ranges::find(m_events, event);
|
||||
if (it != m_events.cend()) {
|
||||
*it = event;
|
||||
} else {
|
||||
m_events.push_back(event);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -50,8 +56,8 @@ bool EqueueInternal::triggerEvent(u64 ident, s16 filter, void* trigger_data) {
|
|||
std::scoped_lock lock{m_mutex};
|
||||
|
||||
for (auto& event : m_events) {
|
||||
if (event.event.ident == ident) { // event filter?
|
||||
event.trigger(trigger_data);
|
||||
if (event.event.ident == ident && event.event.filter == filter) {
|
||||
event.Trigger(trigger_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -64,9 +70,9 @@ int EqueueInternal::getTriggeredEvents(SceKernelEvent* ev, int num) {
|
|||
int ret = 0;
|
||||
|
||||
for (auto& event : m_events) {
|
||||
if (event.isTriggered) {
|
||||
if (event.IsTriggered()) {
|
||||
ev[ret++] = event.event;
|
||||
event.reset();
|
||||
event.Reset();
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -70,24 +70,44 @@ struct SceKernelEvent {
|
|||
|
||||
struct Filter {
|
||||
void* data = nullptr;
|
||||
std::chrono::time_point<std::chrono::steady_clock, std::chrono::microseconds> added_time_us;
|
||||
};
|
||||
|
||||
struct EqueueEvent {
|
||||
bool isTriggered = false;
|
||||
SceKernelEvent event;
|
||||
Filter filter;
|
||||
|
||||
void reset() {
|
||||
isTriggered = false;
|
||||
void Reset() {
|
||||
is_triggered = false;
|
||||
event.fflags = 0;
|
||||
event.data = 0;
|
||||
}
|
||||
|
||||
void trigger(void* data) {
|
||||
isTriggered = true;
|
||||
void Trigger(void* data) {
|
||||
is_triggered = true;
|
||||
event.fflags++;
|
||||
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 {
|
||||
|
@ -97,7 +117,10 @@ public:
|
|||
void setName(const std::string& 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 waitForEvents(SceKernelEvent* ev, int num, u32 micros);
|
||||
bool triggerEvent(u64 ident, s16 filter, void* trigger_data);
|
||||
|
|
|
@ -2,6 +2,7 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
#include "common/assert.h"
|
||||
#include "common/debug.h"
|
||||
#include "common/logging/log.h"
|
||||
#include "core/libraries/error_codes.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,
|
||||
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) {
|
||||
return ORBIS_KERNEL_ERROR_EBADF;
|
||||
|
@ -84,7 +87,6 @@ int PS4_SYSV_ABI sceKernelAddUserEvent(SceKernelEqueue eq, int id) {
|
|||
}
|
||||
|
||||
Kernel::EqueueEvent event{};
|
||||
event.isTriggered = false;
|
||||
event.event.ident = id;
|
||||
event.event.filter = Kernel::EVFILT_USER;
|
||||
event.event.udata = 0;
|
||||
|
@ -101,7 +103,6 @@ int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id) {
|
|||
}
|
||||
|
||||
Kernel::EqueueEvent event{};
|
||||
event.isTriggered = false;
|
||||
event.event.ident = id;
|
||||
event.event.filter = Kernel::EVFILT_USER;
|
||||
event.event.udata = 0;
|
||||
|
@ -112,6 +113,28 @@ int PS4_SYSV_ABI sceKernelAddUserEventEdge(SceKernelEqueue eq, int id) {
|
|||
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) {
|
||||
if (!ev) {
|
||||
return nullptr;
|
||||
|
|
|
@ -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 sceKernelAddUserEvent(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
|
||||
|
|
|
@ -11,6 +11,27 @@
|
|||
|
||||
namespace Libraries::Kernel {
|
||||
|
||||
std::vector<Core::FileSys::DirEntry> GetDirectoryEntries(const std::string& path) {
|
||||
std::string curpath = path;
|
||||
if (!curpath.ends_with("/")) {
|
||||
curpath = std::string(curpath + "/");
|
||||
}
|
||||
std::vector<Core::FileSys::DirEntry> files;
|
||||
|
||||
for (const auto& entry : std::filesystem::directory_iterator(curpath)) {
|
||||
Core::FileSys::DirEntry e = {};
|
||||
if (std::filesystem::is_directory(entry.path().string())) {
|
||||
e.name = entry.path().filename().string();
|
||||
e.isFile = false;
|
||||
} else {
|
||||
e.name = entry.path().filename().string();
|
||||
e.isFile = true;
|
||||
}
|
||||
files.push_back(e);
|
||||
}
|
||||
|
||||
return files;
|
||||
}
|
||||
int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
|
||||
LOG_INFO(Kernel_Fs, "path = {} flags = {:#x} mode = {}", path, flags, mode);
|
||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||
|
@ -32,14 +53,25 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
|
|||
bool directory = (flags & ORBIS_KERNEL_O_DIRECTORY) != 0;
|
||||
|
||||
if (std::string_view{path} == "/dev/console" || std::string_view{path} == "/dev/deci_tty6") {
|
||||
return ORBIS_OK;
|
||||
return 2000;//return a high handler // TODO fix me
|
||||
}
|
||||
|
||||
u32 handle = h->CreateHandle();
|
||||
auto* file = h->GetFile(handle);
|
||||
if (directory) {
|
||||
LOG_ERROR(Kernel_Fs, "called on directory");
|
||||
file->is_directory = true;
|
||||
file->m_guest_name = path;
|
||||
file->m_host_name = mnt->GetHostDirectory(file->m_guest_name);
|
||||
if (!std::filesystem::is_directory(file->m_host_name)) { // directory doesn't exist
|
||||
UNREACHABLE(); // not supported yet
|
||||
} else {
|
||||
if (create) {
|
||||
return handle; // dir already exists
|
||||
} else {
|
||||
file->dirents = GetDirectoryEntries(file->m_host_name);
|
||||
file->dirents_index = 0;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
u32 handle = h->CreateHandle();
|
||||
auto* file = h->GetFile(handle);
|
||||
file->m_guest_name = path;
|
||||
file->m_host_name = mnt->GetHostFile(file->m_guest_name);
|
||||
if (read) {
|
||||
|
@ -61,14 +93,13 @@ int PS4_SYSV_ABI sceKernelOpen(const char* path, int flags, u16 mode) {
|
|||
h->DeleteHandle(handle);
|
||||
return SCE_KERNEL_ERROR_EACCES;
|
||||
}
|
||||
file->is_opened = true;
|
||||
return handle;
|
||||
}
|
||||
return -1; // dummy
|
||||
file->is_opened = true;
|
||||
return handle;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI posix_open(const char* path, int flags, /* SceKernelMode*/ u16 mode) {
|
||||
LOG_INFO(Kernel_Fs, "posix open redirect to sceKernelOpen\n");
|
||||
LOG_INFO(Kernel_Fs, "posix open redirect to sceKernelOpen");
|
||||
int result = sceKernelOpen(path, flags, mode);
|
||||
// Posix calls different only for their return values
|
||||
ASSERT(result >= 0);
|
||||
|
@ -310,6 +341,43 @@ s32 PS4_SYSV_ABI sceKernelFsync(int fd) {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int GetDents(int fd, char* buf, int nbytes, s64* basep) {
|
||||
// TODO error codes
|
||||
auto* h = Common::Singleton<Core::FileSys::HandleTable>::Instance();
|
||||
auto* file = h->GetFile(fd);
|
||||
|
||||
if (file->dirents_index == file->dirents.size()) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
const auto& entry = file->dirents.at(file->dirents_index++);
|
||||
auto str = entry.name;
|
||||
auto str_size = str.size() - 1;
|
||||
static int fileno = 1000; // random
|
||||
OrbisKernelDirent* sce_ent = (OrbisKernelDirent*)buf;
|
||||
sce_ent->d_fileno = fileno++; // TODO this should be unique but atm it changes maybe switch to a
|
||||
// hash or something?
|
||||
sce_ent->d_reclen = sizeof(OrbisKernelDirent);
|
||||
sce_ent->d_type = (entry.isFile ? 8 : 4);
|
||||
sce_ent->d_namlen = str_size;
|
||||
strncpy(sce_ent->d_name, str.c_str(), ORBIS_MAX_PATH);
|
||||
sce_ent->d_name[ORBIS_MAX_PATH] = '\0';
|
||||
|
||||
if (basep != nullptr) {
|
||||
*basep = file->dirents_index;
|
||||
}
|
||||
|
||||
return sizeof(OrbisKernelDirent);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelGetdents(int fd, char* buf, int nbytes) {
|
||||
return GetDents(fd, buf, nbytes, nullptr);
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceKernelGetdirentries(int fd, char* buf, int nbytes, s64* basep) {
|
||||
return GetDents(fd, buf, nbytes, basep);
|
||||
}
|
||||
|
||||
void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
||||
LIB_FUNCTION("1G3lF1Gg1k8", "libkernel", 1, "libkernel", 1, 1, sceKernelOpen);
|
||||
LIB_FUNCTION("wuCroIGjt2g", "libScePosix", 1, "libkernel", 1, 1, posix_open);
|
||||
|
@ -333,6 +401,8 @@ void fileSystemSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("+r3rMFwItV4", "libkernel", 1, "libkernel", 1, 1, sceKernelPread);
|
||||
LIB_FUNCTION("uWyW3v98sU4", "libkernel", 1, "libkernel", 1, 1, sceKernelCheckReachability);
|
||||
LIB_FUNCTION("fTx66l5iWIA", "libkernel", 1, "libkernel", 1, 1, sceKernelFsync);
|
||||
LIB_FUNCTION("j2AIqSqJP0w", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdents);
|
||||
LIB_FUNCTION("taRWhTJFTgE", "libkernel", 1, "libkernel", 1, 1, sceKernelGetdirentries);
|
||||
|
||||
// openOrbis (to check if it is valid out of OpenOrbis
|
||||
LIB_FUNCTION("6c3rCVE-fTU", "libkernel", 1, "libkernel", 1, 1,
|
||||
|
|
|
@ -12,6 +12,8 @@ class SymbolsResolver;
|
|||
|
||||
namespace Libraries::Kernel {
|
||||
|
||||
constexpr int ORBIS_MAX_PATH = 255;
|
||||
|
||||
struct SceKernelIovec {
|
||||
void* iov_base;
|
||||
std::size_t iov_len;
|
||||
|
@ -39,6 +41,14 @@ struct OrbisKernelStat {
|
|||
unsigned int : (8 / 2) * (16 - static_cast<int>(sizeof(OrbisKernelTimespec)));
|
||||
};
|
||||
|
||||
struct OrbisKernelDirent {
|
||||
u32 d_fileno; /* file number of entry */
|
||||
u16 d_reclen; /* length of this record */
|
||||
u8 d_type; /* file type, see below */
|
||||
u8 d_namlen; /* length of string in d_name */
|
||||
char d_name[ORBIS_MAX_PATH + 1]; /* name must be no longer than this */
|
||||
};
|
||||
|
||||
// flags for Open
|
||||
constexpr int ORBIS_KERNEL_O_RDONLY = 0x0000;
|
||||
constexpr int ORBIS_KERNEL_O_WRONLY = 0x0001;
|
||||
|
|
|
@ -88,7 +88,7 @@ int PS4_SYSV_ABI sceKernelMmap(void* addr, u64 len, int prot, int flags, int fd,
|
|||
|
||||
void* PS4_SYSV_ABI posix_mmap(void* addr, u64 len, int prot, int flags, int fd, u64 offset) {
|
||||
void* ptr;
|
||||
LOG_INFO(Kernel_Vmm, "posix mmap redirect to sceKernelMmap\n");
|
||||
LOG_INFO(Kernel_Vmm, "posix mmap redirect to sceKernelMmap");
|
||||
// posix call the difference is that there is a different behaviour when it doesn't return 0 or
|
||||
// SCE_OK
|
||||
const VAddr ret_addr = (VAddr)__builtin_return_address(0);
|
||||
|
@ -288,9 +288,21 @@ int PS4_SYSV_ABI sceKernelUuidCreate(OrbisKernelUuid* orbisUuid) {
|
|||
return 0;
|
||||
}
|
||||
|
||||
char* PS4_SYSV_ABI sceKernelGetFsSandboxRandomWord() {
|
||||
char* path = "sys";
|
||||
return path;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI connect() {
|
||||
return -1;
|
||||
}
|
||||
void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
|
||||
// obj
|
||||
LIB_OBJ("f7uOxY9mM1U", "libkernel", 1, "libkernel", 1, 1, &g_stack_chk_guard);
|
||||
|
||||
LIB_FUNCTION("JGfTMBOdUJo", "libkernel", 1, "libkernel", 1, 1, sceKernelGetFsSandboxRandomWord);
|
||||
LIB_FUNCTION("XVL8So3QJUk", "libkernel", 1, "libkernel", 1, 1, connect);
|
||||
|
||||
// memory
|
||||
LIB_FUNCTION("OMDRKKAZ8I4", "libkernel", 1, "libkernel", 1, 1, sceKernelDebugRaiseException);
|
||||
LIB_FUNCTION("rTXw65xmLIA", "libkernel", 1, "libkernel", 1, 1, sceKernelAllocateDirectMemory);
|
||||
|
@ -308,6 +320,8 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("cQke9UuBQOk", "libkernel", 1, "libkernel", 1, 1, sceKernelMunmap);
|
||||
LIB_FUNCTION("mL8NDH86iQI", "libkernel", 1, "libkernel", 1, 1, sceKernelMapNamedFlexibleMemory);
|
||||
LIB_FUNCTION("IWIBBdTHit4", "libkernel", 1, "libkernel", 1, 1, sceKernelMapFlexibleMemory);
|
||||
LIB_FUNCTION("aNz11fnnzi4", "libkernel", 1, "libkernel", 1, 1,
|
||||
sceKernelAvailableFlexibleMemorySize);
|
||||
LIB_FUNCTION("p5EcQeEeJAE", "libkernel", 1, "libkernel", 1, 1,
|
||||
_sceKernelRtldSetApplicationHeapAPI);
|
||||
LIB_FUNCTION("wzvqT4UqKX8", "libkernel", 1, "libkernel", 1, 1, sceKernelLoadStartModule);
|
||||
|
@ -324,6 +338,7 @@ void LibKernel_Register(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("vz+pg2zdopI", "libkernel", 1, "libkernel", 1, 1, sceKernelGetEventUserData);
|
||||
LIB_FUNCTION("4R6-OvI2cEA", "libkernel", 1, "libkernel", 1, 1, sceKernelAddUserEvent);
|
||||
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("LJDwdSNTnDg", "libkernel", 1, "libkernel", 1, 1, sceKernelDeleteUserEvent);
|
||||
|
||||
|
|
|
@ -173,6 +173,12 @@ int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInf
|
|||
return memory->DirectMemoryQuery(offset, flags == 1, query_info);
|
||||
}
|
||||
|
||||
s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(size_t* sizeOut) {
|
||||
auto* memory = Core::Memory::Instance();
|
||||
*sizeOut = 448_MB - memory->GetTotalFlexibleUsage();
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func) {
|
||||
auto* linker = Common::Singleton<Core::Linker>::Instance();
|
||||
linker->SetHeapApiFunc(func);
|
||||
|
|
|
@ -78,6 +78,7 @@ int PS4_SYSV_ABI sceKernelQueryMemoryProtection(void* addr, void** start, void**
|
|||
|
||||
int PS4_SYSV_ABI sceKernelDirectMemoryQuery(u64 offset, int flags, OrbisQueryInfo* query_info,
|
||||
size_t infoSize);
|
||||
s32 PS4_SYSV_ABI sceKernelAvailableFlexibleMemorySize(size_t* sizeOut);
|
||||
void PS4_SYSV_ABI _sceKernelRtldSetApplicationHeapAPI(void* func);
|
||||
|
||||
} // namespace Libraries::Kernel
|
||||
|
|
|
@ -1312,6 +1312,9 @@ void pthreadSymbolsRegister(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("Ru36fiTtJzA", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstackaddr);
|
||||
LIB_FUNCTION("-fA+7ZlGDQs", "libkernel", 1, "libkernel", 1, 1, scePthreadAttrGetstacksize);
|
||||
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
|
||||
LIB_FUNCTION("cmo1RIYva9o", "libkernel", 1, "libkernel", 1, 1, scePthreadMutexInit);
|
||||
|
|
|
@ -2,14 +2,34 @@
|
|||
// SPDX-License-Identifier: GPL-2.0-or-later
|
||||
|
||||
// Generated By moduleGenerator
|
||||
#include <unordered_map>
|
||||
|
||||
#include "common/logging/log.h"
|
||||
#include "common/slot_vector.h"
|
||||
#include "core/libraries/error_codes.h"
|
||||
#include "core/libraries/libs.h"
|
||||
#include "np_trophy.h"
|
||||
|
||||
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");
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
@ -64,14 +84,43 @@ int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpTrophyCreateContext() {
|
||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
||||
s32 PS4_SYSV_ABI sceNpTrophyCreateContext(u32* context, u32 user_id, u32 service_label,
|
||||
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{service_label, user_id};
|
||||
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 = {}, service label = {} user_id = {}", ctx_id.index,
|
||||
service_label, user_id);
|
||||
*context = ctx_id.index;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpTrophyCreateHandle() {
|
||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
||||
return -1;
|
||||
s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(u32* handle) {
|
||||
if (!handle) {
|
||||
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() {
|
||||
|
@ -79,8 +128,13 @@ int PS4_SYSV_ABI sceNpTrophyDestroyContext() {
|
|||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
int PS4_SYSV_ABI sceNpTrophyDestroyHandle() {
|
||||
LOG_ERROR(Lib_NpTrophy, "(STUBBED) called");
|
||||
s32 PS4_SYSV_ABI sceNpTrophyDestroyHandle(u32 handle) {
|
||||
if (!trophy_handles.IsAllocated({handle})) {
|
||||
return ORBIS_NP_TROPHY_ERROR_INVALID_HANDLE;
|
||||
}
|
||||
|
||||
trophy_handles.erase({handle});
|
||||
LOG_INFO(Lib_NpTrophy, "Handle {} destroyed", handle);
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
@ -114,8 +168,10 @@ int PS4_SYSV_ABI sceNpTrophyGetTrophyInfo() {
|
|||
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");
|
||||
*flags = 0u;
|
||||
*count = 0;
|
||||
return ORBIS_OK;
|
||||
}
|
||||
|
||||
|
|
|
@ -22,17 +22,18 @@ int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetInfoInGroup();
|
|||
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophySetVersion();
|
||||
int PS4_SYSV_ABI sceNpTrophyConfigGetTrophyTitleDetails();
|
||||
int PS4_SYSV_ABI sceNpTrophyConfigHasGroupFeature();
|
||||
int PS4_SYSV_ABI sceNpTrophyCreateContext();
|
||||
int PS4_SYSV_ABI sceNpTrophyCreateHandle();
|
||||
s32 PS4_SYSV_ABI sceNpTrophyCreateContext(u32* context, u32 user_id, u32 service_label,
|
||||
u64 options);
|
||||
s32 PS4_SYSV_ABI sceNpTrophyCreateHandle(u32* handle);
|
||||
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 sceNpTrophyGetGameInfo();
|
||||
int PS4_SYSV_ABI sceNpTrophyGetGroupIcon();
|
||||
int PS4_SYSV_ABI sceNpTrophyGetGroupInfo();
|
||||
int PS4_SYSV_ABI sceNpTrophyGetTrophyIcon();
|
||||
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 sceNpTrophyIntAbortHandle();
|
||||
int PS4_SYSV_ABI sceNpTrophyIntCheckNetSyncTitles();
|
||||
|
|
|
@ -48,7 +48,6 @@ s32 PS4_SYSV_ABI sceVideoOutAddFlipEvent(Kernel::SceKernelEqueue eq, s32 handle,
|
|||
}
|
||||
|
||||
Kernel::EqueueEvent event{};
|
||||
event.isTriggered = false;
|
||||
event.event.ident = SCE_VIDEO_OUT_EVENT_FLIP;
|
||||
event.event.filter = Kernel::EVFILT_VIDEO_OUT;
|
||||
event.event.udata = udata;
|
||||
|
@ -73,7 +72,6 @@ s32 PS4_SYSV_ABI sceVideoOutAddVblankEvent(Kernel::SceKernelEqueue eq, s32 handl
|
|||
}
|
||||
|
||||
Kernel::EqueueEvent event{};
|
||||
event.isTriggered = false;
|
||||
event.event.ident = SCE_VIDEO_OUT_EVENT_VBLANK;
|
||||
event.event.filter = Kernel::EVFILT_VIDEO_OUT;
|
||||
event.event.udata = udata;
|
||||
|
@ -288,6 +286,8 @@ void RegisterLib(Core::Loader::SymbolsResolver* sym) {
|
|||
LIB_FUNCTION("uquVH4-Du78", "libSceVideoOut", 1, "libSceVideoOut", 0, 0, sceVideoOutClose);
|
||||
LIB_FUNCTION("1FZBKy8HeNU", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
sceVideoOutGetVblankStatus);
|
||||
LIB_FUNCTION("kGVLc3htQE8", "libSceVideoOut", 1, "libSceVideoOut", 0, 0,
|
||||
sceVideoOutGetDeviceCapabilityInfo);
|
||||
|
||||
// openOrbis appears to have libSceVideoOut_v1 module libSceVideoOut_v1.1
|
||||
LIB_FUNCTION("Up36PTk687E", "libSceVideoOut", 1, "libSceVideoOut", 1, 1, sceVideoOutOpen);
|
||||
|
|
|
@ -124,6 +124,10 @@ public:
|
|||
instance = instance_;
|
||||
}
|
||||
|
||||
size_t GetTotalFlexibleUsage() const noexcept {
|
||||
return total_flexible_usage;
|
||||
}
|
||||
|
||||
PAddr Allocate(PAddr search_start, PAddr search_end, size_t size, u64 alignment,
|
||||
int memory_type);
|
||||
|
||||
|
|
|
@ -139,7 +139,7 @@ void Emulator::LoadSystemModules(const std::filesystem::path& file) {
|
|||
const auto& sys_module_path = Common::FS::GetUserPath(Common::FS::PathType::SysModuleDir);
|
||||
for (const auto& entry : std::filesystem::directory_iterator(sys_module_path)) {
|
||||
if (entry.path().filename() == "libSceNgs2.sprx" ||
|
||||
entry.path().filename() == "libSceLibcInternal.sprx") {
|
||||
entry.path().filename() == "libSceLibcInternal.sprx" || entry.path().filename() == "libSceDiscMap.sprx") {
|
||||
LOG_INFO(Loader, "Loading {}", entry.path().string().c_str());
|
||||
linker->LoadModule(entry.path());
|
||||
}
|
||||
|
|
|
@ -12,7 +12,7 @@ namespace AmdGpu {
|
|||
|
||||
static const char* dcb_task_name{"DCB_TASK"};
|
||||
static const char* ccb_task_name{"CCB_TASK"};
|
||||
static const char* asc_task_name{"ACB_TASK"};
|
||||
static const char* acb_task_name{"ACB_TASK"};
|
||||
|
||||
std::array<u8, 48_KB> Liverpool::ConstantEngine::constants_heap;
|
||||
|
||||
|
@ -381,6 +381,8 @@ Liverpool::Task Liverpool::ProcessGraphics(std::span<const u32> dcb, std::span<c
|
|||
}
|
||||
|
||||
Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb) {
|
||||
TracyFiberEnter(acb_task_name);
|
||||
|
||||
while (!acb.empty()) {
|
||||
const auto* header = reinterpret_cast<const PM4Header*>(acb.data());
|
||||
const u32 type = header->type;
|
||||
|
@ -393,6 +395,69 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb) {
|
|||
const PM4ItOpcode opcode = header->type3.opcode;
|
||||
const auto* it_body = reinterpret_cast<const u32*>(header) + 1;
|
||||
switch (opcode) {
|
||||
case PM4ItOpcode::Nop: {
|
||||
const auto* nop = reinterpret_cast<const PM4CmdNop*>(header);
|
||||
break;
|
||||
}
|
||||
case PM4ItOpcode::IndirectBuffer: {
|
||||
const auto* indirect_buffer = reinterpret_cast<const PM4CmdIndirectBuffer*>(header);
|
||||
auto task =
|
||||
ProcessCompute({indirect_buffer->Address<const u32>(), indirect_buffer->ib_size});
|
||||
while (!task.handle.done()) {
|
||||
task.handle.resume();
|
||||
|
||||
TracyFiberLeave;
|
||||
co_yield {};
|
||||
TracyFiberEnter(acb_task_name);
|
||||
};
|
||||
break;
|
||||
}
|
||||
case PM4ItOpcode::AcquireMem: {
|
||||
break;
|
||||
}
|
||||
case PM4ItOpcode::SetShReg: {
|
||||
const auto* set_data = reinterpret_cast<const PM4CmdSetData*>(header);
|
||||
std::memcpy(®s.reg_array[ShRegWordOffset + set_data->reg_offset], header + 2,
|
||||
(count - 1) * sizeof(u32));
|
||||
break;
|
||||
}
|
||||
case PM4ItOpcode::DispatchDirect: {
|
||||
const auto* dispatch_direct = reinterpret_cast<const PM4CmdDispatchDirect*>(header);
|
||||
regs.cs_program.dim_x = dispatch_direct->dim_x;
|
||||
regs.cs_program.dim_y = dispatch_direct->dim_y;
|
||||
regs.cs_program.dim_z = dispatch_direct->dim_z;
|
||||
regs.cs_program.dispatch_initiator = dispatch_direct->dispatch_initiator;
|
||||
if (rasterizer && (regs.cs_program.dispatch_initiator & 1)) {
|
||||
rasterizer->DispatchDirect();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PM4ItOpcode::WriteData: {
|
||||
const auto* write_data = reinterpret_cast<const PM4CmdWriteData*>(header);
|
||||
ASSERT(write_data->dst_sel.Value() == 2 || write_data->dst_sel.Value() == 5);
|
||||
const u32 data_size = (header->type3.count.Value() - 2) * 4;
|
||||
if (!write_data->wr_one_addr.Value()) {
|
||||
std::memcpy(write_data->Address<void*>(), write_data->data, data_size);
|
||||
} else {
|
||||
UNREACHABLE();
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PM4ItOpcode::WaitRegMem: {
|
||||
const auto* wait_reg_mem = reinterpret_cast<const PM4CmdWaitRegMem*>(header);
|
||||
ASSERT(wait_reg_mem->engine.Value() == PM4CmdWaitRegMem::Engine::Me);
|
||||
while (!wait_reg_mem->Test()) {
|
||||
TracyFiberLeave;
|
||||
co_yield {};
|
||||
TracyFiberEnter(acb_task_name);
|
||||
}
|
||||
break;
|
||||
}
|
||||
case PM4ItOpcode::ReleaseMem: {
|
||||
const auto* release_mem = reinterpret_cast<const PM4CmdReleaseMem*>(header);
|
||||
release_mem->SignalFence(Platform::InterruptId::Compute0RelMem); // <---
|
||||
break;
|
||||
}
|
||||
default:
|
||||
UNREACHABLE_MSG("Unknown PM4 type 3 opcode {:#x} with count {}",
|
||||
static_cast<u32>(opcode), count);
|
||||
|
@ -401,7 +466,7 @@ Liverpool::Task Liverpool::ProcessCompute(std::span<const u32> acb) {
|
|||
acb = acb.subspan(header->type3.NumWords() + 1);
|
||||
}
|
||||
|
||||
return {}; // Not a coroutine yet
|
||||
TracyFiberLeave;
|
||||
}
|
||||
|
||||
void Liverpool::SubmitGfx(std::span<const u32> dcb, std::span<const u32> ccb) {
|
||||
|
|
|
@ -265,6 +265,7 @@ enum class InterruptSelect : u32 {
|
|||
None = 0,
|
||||
IrqOnly = 1,
|
||||
IrqWhenWriteConfirm = 2,
|
||||
IrqUndocumented = 3,
|
||||
};
|
||||
|
||||
struct PM4CmdEventWriteEop {
|
||||
|
@ -299,6 +300,9 @@ struct PM4CmdEventWriteEop {
|
|||
|
||||
void SignalFence() const {
|
||||
switch (data_sel.Value()) {
|
||||
case DataSelect::None: {
|
||||
break;
|
||||
}
|
||||
case DataSelect::Data32Low: {
|
||||
*Address<u32>() = DataDWord();
|
||||
break;
|
||||
|
@ -321,6 +325,9 @@ struct PM4CmdEventWriteEop {
|
|||
// No interrupt
|
||||
break;
|
||||
}
|
||||
case InterruptSelect::IrqOnly:
|
||||
ASSERT(data_sel == DataSelect::None);
|
||||
[[fallthrough]];
|
||||
case InterruptSelect::IrqWhenWriteConfirm: {
|
||||
Platform::IrqC::Instance()->Signal(Platform::InterruptId::GfxEop);
|
||||
break;
|
||||
|
@ -559,4 +566,105 @@ struct PM4CmdDrawIndexBase {
|
|||
u32 addr_hi;
|
||||
};
|
||||
|
||||
struct PM4CmdIndirectBuffer {
|
||||
PM4Type3Header header;
|
||||
u32 ibase_lo; ///< Indirect buffer base address, must be 4 byte aligned
|
||||
union {
|
||||
BitField<0, 16, u32> ibase_hi; ///< Indirect buffer base address
|
||||
u32 dw1;
|
||||
};
|
||||
union {
|
||||
BitField<0, 20, u32> ib_size; ///< Indirect buffer size
|
||||
BitField<20, 1, u32> chain; ///< set to chain to IB allocations
|
||||
BitField<24, 8, u32> vmid; ///< Virtual memory domain ID for command buffer
|
||||
u32 dw2;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
T* Address() const {
|
||||
return reinterpret_cast<T*>((u64(ibase_hi) << 32u) | ibase_lo);
|
||||
}
|
||||
};
|
||||
|
||||
struct PM4CmdReleaseMem {
|
||||
PM4Type3Header header;
|
||||
union {
|
||||
BitField<0, 6, u32> event_type; ///< Event type written to VGT_EVENT_INITIATOR
|
||||
BitField<8, 4, u32> event_index; ///< Event index
|
||||
BitField<12, 1, u32> tcl1_vol_action_ena;
|
||||
BitField<13, 1, u32> tc_vol_action_ena;
|
||||
BitField<15, 1, u32> tc_wb_action_ena;
|
||||
BitField<16, 1, u32> tcl1__action_ena;
|
||||
BitField<17, 1, u32> tc_action_ena;
|
||||
BitField<25, 2, u32> cache_policy; ///< Cache Policy setting used for writing fences and
|
||||
///< timestamps to the TCL2
|
||||
u32 dw1;
|
||||
};
|
||||
union {
|
||||
BitField<16, 2, u32> dst_sel; ///< destination select
|
||||
BitField<24, 3, InterruptSelect> int_sel; ///< selects interrupt action for end-of-pipe
|
||||
BitField<29, 3, DataSelect> data_sel; ///< selects source of data
|
||||
u32 dw2;
|
||||
};
|
||||
u32 address_lo; ///< low bits of address
|
||||
u32 address_hi; ///< high bits of address
|
||||
union {
|
||||
struct {
|
||||
u16 gds_index; ///< Byte offset into GDS to copy from
|
||||
u16 num_dw; ///< Number of DWORDS of GDS to copy
|
||||
};
|
||||
u32 data_lo; ///< value that will be written to memory when event occurs
|
||||
};
|
||||
u32 data_hi;
|
||||
|
||||
template <typename T>
|
||||
T* Address() const {
|
||||
return reinterpret_cast<T*>(address_lo | u64(address_hi) << 32);
|
||||
}
|
||||
|
||||
u32 DataDWord() const {
|
||||
return data_lo;
|
||||
}
|
||||
|
||||
u64 DataQWord() const {
|
||||
return data_lo | u64(data_hi) << 32;
|
||||
}
|
||||
|
||||
void SignalFence(Platform::InterruptId irq_id) const {
|
||||
switch (data_sel.Value()) {
|
||||
case DataSelect::Data32Low: {
|
||||
*Address<u32>() = DataDWord();
|
||||
break;
|
||||
}
|
||||
case DataSelect::Data64: {
|
||||
*Address<u64>() = DataQWord();
|
||||
break;
|
||||
}
|
||||
case DataSelect::PerfCounter: {
|
||||
*Address<u64>() = Common::FencedRDTSC();
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
|
||||
switch (int_sel.Value()) {
|
||||
case InterruptSelect::None: {
|
||||
// No interrupt
|
||||
break;
|
||||
}
|
||||
case InterruptSelect::IrqUndocumented:
|
||||
[[fallthrough]];
|
||||
case InterruptSelect::IrqWhenWriteConfirm: {
|
||||
Platform::IrqC::Instance()->Signal(irq_id);
|
||||
break;
|
||||
}
|
||||
default: {
|
||||
UNREACHABLE();
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
} // namespace AmdGpu
|
||||
|
|
|
@ -46,6 +46,7 @@ enum class PM4ItOpcode : u32 {
|
|||
EventWrite = 0x46,
|
||||
EventWriteEop = 0x47,
|
||||
EventWriteEos = 0x48,
|
||||
ReleaseMem = 0x49,
|
||||
PremableCntl = 0x4A,
|
||||
DmaData = 0x50,
|
||||
ContextRegRmw = 0x51,
|
||||
|
|
|
@ -90,7 +90,7 @@ private:
|
|||
vk::Image image{};
|
||||
};
|
||||
|
||||
constexpr SlotId NULL_IMAGE_ID{0};
|
||||
constexpr Common::SlotId NULL_IMAGE_ID{0};
|
||||
|
||||
struct Image {
|
||||
explicit Image(const Vulkan::Instance& instance, Vulkan::Scheduler& scheduler,
|
||||
|
|
|
@ -140,8 +140,8 @@ private:
|
|||
Vulkan::Scheduler& scheduler;
|
||||
Vulkan::StreamBuffer staging;
|
||||
TileManager tile_manager;
|
||||
SlotVector<Image> slot_images;
|
||||
SlotVector<ImageView> slot_image_views;
|
||||
Common::SlotVector<Image> slot_images;
|
||||
Common::SlotVector<ImageView> slot_image_views;
|
||||
tsl::robin_map<u64, Sampler> samplers;
|
||||
tsl::robin_pg_map<u64, std::vector<ImageId>> page_table;
|
||||
boost::icl::interval_map<VAddr, s32> cached_pages;
|
||||
|
|
|
@ -8,8 +8,8 @@
|
|||
|
||||
namespace VideoCore {
|
||||
|
||||
using ImageId = SlotId;
|
||||
using ImageViewId = SlotId;
|
||||
using ImageId = Common::SlotId;
|
||||
using ImageViewId = Common::SlotId;
|
||||
|
||||
struct Offset2D {
|
||||
s32 x;
|
||||
|
|
Loading…
Reference in New Issue