mirror of
https://github.com/citra-emu/citra-nightly.git
synced 2024-12-26 00:35:39 +00:00
Services/GSP: Assign a thread id to each connected session when the session is created.
Most applications call AcquireRight before calling RegisterInterruptRelayQueue so we can't assign the thread id there. This fixes the bug with LLE applets not launching properly.
This commit is contained in:
parent
fbef978b98
commit
d17f148e48
|
@ -53,6 +53,17 @@ constexpr ResultCode ERR_REGS_INVALID_SIZE(ErrorDescription::InvalidSize, ErrorM
|
||||||
/// Maximum number of threads that can be registered at the same time in the GSP module.
|
/// Maximum number of threads that can be registered at the same time in the GSP module.
|
||||||
constexpr u32 MaxGSPThreads = 4;
|
constexpr u32 MaxGSPThreads = 4;
|
||||||
|
|
||||||
|
/// Thread ids currently in use by the sessions connected to the GSPGPU service.
|
||||||
|
static std::array<bool, MaxGSPThreads> used_thread_ids = {false, false, false, false};
|
||||||
|
|
||||||
|
static u32 GetUnusedThreadId() {
|
||||||
|
for (u32 id = 0; id < MaxGSPThreads; ++id) {
|
||||||
|
if (!used_thread_ids[id])
|
||||||
|
return id;
|
||||||
|
}
|
||||||
|
ASSERT_MSG(false, "All GSP threads are in use");
|
||||||
|
}
|
||||||
|
|
||||||
/// Gets a pointer to a thread command buffer in GSP shared memory
|
/// Gets a pointer to a thread command buffer in GSP shared memory
|
||||||
static inline u8* GetCommandBuffer(Kernel::SharedPtr<Kernel::SharedMemory> shared_memory,
|
static inline u8* GetCommandBuffer(Kernel::SharedPtr<Kernel::SharedMemory> shared_memory,
|
||||||
u32 thread_id) {
|
u32 thread_id) {
|
||||||
|
@ -327,11 +338,7 @@ void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) {
|
||||||
|
|
||||||
interrupt_event->name = "GSP_GSP_GPU::interrupt_event";
|
interrupt_event->name = "GSP_GSP_GPU::interrupt_event";
|
||||||
|
|
||||||
u32 thread_id = next_thread_id++;
|
|
||||||
ASSERT_MSG(thread_id < MaxGSPThreads, "GSP thread id overflow");
|
|
||||||
|
|
||||||
SessionData* session_data = GetSessionData(ctx.Session());
|
SessionData* session_data = GetSessionData(ctx.Session());
|
||||||
session_data->thread_id = thread_id;
|
|
||||||
session_data->interrupt_event = std::move(interrupt_event);
|
session_data->interrupt_event = std::move(interrupt_event);
|
||||||
session_data->registered = true;
|
session_data->registered = true;
|
||||||
|
|
||||||
|
@ -345,7 +352,7 @@ void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) {
|
||||||
rb.Push(RESULT_SUCCESS);
|
rb.Push(RESULT_SUCCESS);
|
||||||
}
|
}
|
||||||
|
|
||||||
rb.Push(thread_id);
|
rb.Push(session_data->thread_id);
|
||||||
rb.PushCopyObjects(shared_memory);
|
rb.PushCopyObjects(shared_memory);
|
||||||
|
|
||||||
LOG_DEBUG(Service_GSP, "called, flags=0x%08X", flags);
|
LOG_DEBUG(Service_GSP, "called, flags=0x%08X", flags);
|
||||||
|
@ -752,5 +759,14 @@ GSP_GPU::GSP_GPU() : ServiceFramework("gsp::Gpu", 2) {
|
||||||
|
|
||||||
first_initialization = true;
|
first_initialization = true;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
SessionData::SessionData() {
|
||||||
|
// Assign a new thread id to this session when it connects. Note: In the real GSP service this
|
||||||
|
// is done through a real thread (svcCreateThread) but we have to simulate it since our HLE
|
||||||
|
// services don't have threads.
|
||||||
|
thread_id = GetUnusedThreadId();
|
||||||
|
used_thread_ids[thread_id] = true;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace GSP
|
} // namespace GSP
|
||||||
} // namespace Service
|
} // namespace Service
|
||||||
|
|
|
@ -180,10 +180,12 @@ struct CommandBuffer {
|
||||||
static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size");
|
static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size");
|
||||||
|
|
||||||
struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
|
struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase {
|
||||||
|
SessionData();
|
||||||
|
|
||||||
/// Event triggered when GSP interrupt has been signalled
|
/// Event triggered when GSP interrupt has been signalled
|
||||||
Kernel::SharedPtr<Kernel::Event> interrupt_event;
|
Kernel::SharedPtr<Kernel::Event> interrupt_event;
|
||||||
/// Thread index into interrupt relay queue
|
/// Thread index into interrupt relay queue
|
||||||
u32 thread_id = 0;
|
u32 thread_id;
|
||||||
/// Whether RegisterInterruptRelayQueue was called for this session
|
/// Whether RegisterInterruptRelayQueue was called for this session
|
||||||
bool registered = false;
|
bool registered = false;
|
||||||
};
|
};
|
||||||
|
@ -363,9 +365,6 @@ private:
|
||||||
/// Returns the session data for the specified registered thread id, or nullptr if not found.
|
/// Returns the session data for the specified registered thread id, or nullptr if not found.
|
||||||
SessionData* FindRegisteredThreadData(u32 thread_id);
|
SessionData* FindRegisteredThreadData(u32 thread_id);
|
||||||
|
|
||||||
/// Next threadid value to use when RegisterInterruptRelayQueue is called.
|
|
||||||
u32 next_thread_id = 0;
|
|
||||||
|
|
||||||
/// GSP shared memory
|
/// GSP shared memory
|
||||||
Kernel::SharedPtr<Kernel::SharedMemory> shared_memory;
|
Kernel::SharedPtr<Kernel::SharedMemory> shared_memory;
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue