From aabb07cca45f936a0acc159e0632e0395f1faf85 Mon Sep 17 00:00:00 2001 From: Subv Date: Thu, 21 Dec 2017 11:24:12 -0500 Subject: [PATCH] HLE/GSP: Make RegisterInterruptRelayQueue work in a per-session basis. The registered interrupt event is unique to each session that calls RegisterInterruptRelayQueue, and only that event should be reset when UnregisterInterruptRelayQueue is called. --- src/core/hle/service/gsp/gsp_gpu.cpp | 55 +++++++++++++++++++--------- src/core/hle/service/gsp/gsp_gpu.h | 25 +++++++++---- 2 files changed, 55 insertions(+), 25 deletions(-) diff --git a/src/core/hle/service/gsp/gsp_gpu.cpp b/src/core/hle/service/gsp/gsp_gpu.cpp index bb3cedbe3..4e854164e 100644 --- a/src/core/hle/service/gsp/gsp_gpu.cpp +++ b/src/core/hle/service/gsp/gsp_gpu.cpp @@ -9,7 +9,6 @@ #include "core/core.h" #include "core/hle/ipc.h" #include "core/hle/ipc_helpers.h" -#include "core/hle/kernel/event.h" #include "core/hle/kernel/handle_table.h" #include "core/hle/kernel/shared_memory.h" #include "core/hle/result.h" @@ -319,12 +318,19 @@ void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x13, 1, 2); u32 flags = rp.Pop(); - interrupt_event = rp.PopObject(); + auto interrupt_event = rp.PopObject(); // TODO(mailwl): return right error code instead assert ASSERT_MSG((interrupt_event != nullptr), "handle is not valid!"); interrupt_event->name = "GSP_GSP_GPU::interrupt_event"; + u32 thread_id = next_thread_id++; + + SessionData* session_data = GetSessionData(ctx.Session()); + session_data->thread_id = thread_id; + session_data->interrupt_event = std::move(interrupt_event); + session_data->registered = true; + IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); if (first_initialization) { @@ -338,22 +344,23 @@ void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) { rb.Push(thread_id); rb.PushCopyObjects(shared_memory); - thread_id++; - interrupt_event->Signal(); // TODO(bunnei): Is this correct? - - LOG_WARNING(Service_GSP, "called, flags=0x%08X", flags); + LOG_DEBUG(Service_GSP, "called, flags=0x%08X", flags); } void GSP_GPU::UnregisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) { IPC::RequestParser rp(ctx, 0x14, 0, 0); - thread_id = 0; - interrupt_event = nullptr; + SessionData* session_data = GetSessionData(ctx.Session()); + session_data->thread_id = 0; + session_data->interrupt_event = nullptr; + session_data->registered = false; + + // TODO(Subv): Reset next_thread_id so that it doesn't go past the maximum of 4. IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); rb.Push(RESULT_SUCCESS); - LOG_WARNING(Service_GSP, "(STUBBED) called"); + LOG_DEBUG(Service_GSP, "called"); } /** @@ -366,15 +373,20 @@ void GSP_GPU::SignalInterrupt(InterruptId interrupt_id) { if (!gpu_right_acquired) { return; } - if (nullptr == interrupt_event) { - LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!"); - return; - } if (nullptr == shared_memory) { LOG_WARNING(Service_GSP, "cannot synchronize until GSP shared memory has been created!"); return; } for (int thread_id = 0; thread_id < 0x4; ++thread_id) { + SessionData* session_data = FindRegisteredThreadData(thread_id); + if (session_data == nullptr) + continue; + + auto interrupt_event = session_data->interrupt_event; + if (interrupt_event == nullptr) { + LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!"); + continue; + } InterruptRelayQueue* interrupt_relay_queue = GetInterruptRelayQueue(shared_memory, thread_id); u8 next = interrupt_relay_queue->index; @@ -398,8 +410,8 @@ void GSP_GPU::SignalInterrupt(InterruptId interrupt_id) { info->is_dirty.Assign(false); } } + interrupt_event->Signal(); } - interrupt_event->Signal(); } MICROPROFILE_DEFINE(GPU_GSP_DMA, "GPU", "GSP DMA", MP_RGB(100, 0, 255)); @@ -655,6 +667,17 @@ void GSP_GPU::StoreDataCache(Kernel::HLERequestContext& ctx) { size, process->process_id); } +SessionData* GSP_GPU::FindRegisteredThreadData(u32 thread_id) { + for (auto& session_info : connected_sessions) { + SessionData* data = static_cast(session_info.data.get()) + if (!data->registered) + continue; + if (data->thread_id == thread_id) + return data; + } + return nullptr; +} + GSP_GPU::GSP_GPU() : ServiceFramework("gsp::Gpu", 2) { static const FunctionInfo functions[] = { {0x00010082, &GSP_GPU::WriteHWRegs, "WriteHWRegs"}, @@ -691,17 +714,13 @@ GSP_GPU::GSP_GPU() : ServiceFramework("gsp::Gpu", 2) { }; RegisterHandlers(functions); - interrupt_event = nullptr; - using Kernel::MemoryPermission; shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, MemoryPermission::ReadWrite, 0, Kernel::MemoryRegion::BASE, "GSP:SharedMemory"); - thread_id = 0; gpu_right_acquired = false; first_initialization = true; }; - } // namespace GSP } // namespace Service diff --git a/src/core/hle/service/gsp/gsp_gpu.h b/src/core/hle/service/gsp/gsp_gpu.h index 98756a8ff..737525653 100644 --- a/src/core/hle/service/gsp/gsp_gpu.h +++ b/src/core/hle/service/gsp/gsp_gpu.h @@ -8,12 +8,12 @@ #include #include "common/bit_field.h" #include "common/common_types.h" +#include "core/hle/kernel/event.h" #include "core/hle/kernel/hle_ipc.h" #include "core/hle/result.h" #include "core/hle/service/service.h" namespace Kernel { -class Event; class SharedMemory; } // namespace Kernel @@ -179,7 +179,16 @@ struct CommandBuffer { }; static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size"); -class GSP_GPU final : public ServiceFramework { +struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase { + /// Event triggered when GSP interrupt has been signalled + Kernel::SharedPtr interrupt_event; + /// Thread index into interrupt relay queue + u32 thread_id = 0; + /// Whether RegisterInterruptRelayQueue was called for this session + bool registered = false; +}; + +class GSP_GPU final : public ServiceFramework { public: GSP_GPU(); ~GSP_GPU() = default; @@ -351,12 +360,14 @@ private: */ void StoreDataCache(Kernel::HLERequestContext& ctx); - /// Event triggered when GSP interrupt has been signalled - Kernel::SharedPtr interrupt_event; - /// GSP shared memoryings + /// Returns the session data for the specified registered thread id, or nullptr if not found. + SessionData* FindRegisteredThreadData(u32 thread_id); + + /// Next threadid value to use when RegisterInterruptRelayQueue is called. + u32 next_thread_id = 0; + + /// GSP shared memory Kernel::SharedPtr shared_memory; - /// Thread index into interrupt relay queue - u32 thread_id = 0; bool gpu_right_acquired = false; bool first_initialization = true;