Compare commits
7 Commits
Author | SHA1 | Date |
---|---|---|
psucien | 8376813a67 | |
psucien | 6bbf8aa1c2 | |
psucien | 757e93dbd0 | |
psucien | d7a5cbfc95 | |
psucien | d9036a702d | |
georgemoralis | 7b89b7f5fd | |
psucien | ab36a238bf |
|
@ -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
|
||||||
|
|
|
@ -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 {
|
||||||
|
|
|
@ -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) \
|
||||||
|
|
|
@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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) {
|
||||||
|
|
|
@ -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);
|
||||||
|
if (it != m_events.cend()) {
|
||||||
|
*it = event;
|
||||||
|
} else {
|
||||||
m_events.push_back(event);
|
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();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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);
|
||||||
|
|
||||||
|
|
|
@ -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);
|
||||||
|
|
|
@ -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);
|
|
||||||
|
auto end = std::chrono::high_resolution_clock::now();
|
||||||
|
if (result) {
|
||||||
|
const auto delta =
|
||||||
|
std::chrono::duration_cast<std::chrono::microseconds>(end - start);
|
||||||
|
const auto time_remain = time_ms - delta;
|
||||||
|
*timeout = time_remain.count();
|
||||||
|
token_count -= need_count;
|
||||||
|
} else {
|
||||||
|
*timeout = 0;
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool Signal(s32 signal_count) {
|
bool Signal(s32 signal_count) {
|
||||||
std::scoped_lock lk{mutex};
|
std::unique_lock<std::mutex> lock{mutex};
|
||||||
if (token_count + signal_count > max_count) {
|
if (token_count + signal_count > max_count) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
token_count += signal_count;
|
|
||||||
|
|
||||||
// Wake up threads in order of priority.
|
token_count += signal_count;
|
||||||
for (auto& waiter : wait_list) {
|
cond.notify_all();
|
||||||
if (waiter.need_count > token_count) {
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
token_count -= waiter.need_count;
|
|
||||||
waiter.cv.notify_one();
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
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, ¶m);
|
|
||||||
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;
|
||||||
};
|
};
|
||||||
|
|
|
@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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();
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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,
|
||||||
|
|
|
@ -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;
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in New Issue