mirror of
				https://github.com/PabloMK7/citra.git
				synced 2025-10-30 21:30:04 +00:00 
			
		
		
		
	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.
This commit is contained in:
		
							parent
							
								
									ae42267cc7
								
							
						
					
					
						commit
						aabb07cca4
					
				
					 2 changed files with 55 additions and 25 deletions
				
			
		|  | @ -9,7 +9,6 @@ | ||||||
| #include "core/core.h" | #include "core/core.h" | ||||||
| #include "core/hle/ipc.h" | #include "core/hle/ipc.h" | ||||||
| #include "core/hle/ipc_helpers.h" | #include "core/hle/ipc_helpers.h" | ||||||
| #include "core/hle/kernel/event.h" |  | ||||||
| #include "core/hle/kernel/handle_table.h" | #include "core/hle/kernel/handle_table.h" | ||||||
| #include "core/hle/kernel/shared_memory.h" | #include "core/hle/kernel/shared_memory.h" | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
|  | @ -319,12 +318,19 @@ void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx, 0x13, 1, 2); |     IPC::RequestParser rp(ctx, 0x13, 1, 2); | ||||||
|     u32 flags = rp.Pop<u32>(); |     u32 flags = rp.Pop<u32>(); | ||||||
| 
 | 
 | ||||||
|     interrupt_event = rp.PopObject<Kernel::Event>(); |     auto interrupt_event = rp.PopObject<Kernel::Event>(); | ||||||
|     // TODO(mailwl): return right error code instead assert
 |     // TODO(mailwl): return right error code instead assert
 | ||||||
|     ASSERT_MSG((interrupt_event != nullptr), "handle is not valid!"); |     ASSERT_MSG((interrupt_event != nullptr), "handle is not valid!"); | ||||||
| 
 | 
 | ||||||
|     interrupt_event->name = "GSP_GSP_GPU::interrupt_event"; |     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); |     IPC::RequestBuilder rb = rp.MakeBuilder(2, 2); | ||||||
| 
 | 
 | ||||||
|     if (first_initialization) { |     if (first_initialization) { | ||||||
|  | @ -338,22 +344,23 @@ void GSP_GPU::RegisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) { | ||||||
|     rb.Push(thread_id); |     rb.Push(thread_id); | ||||||
|     rb.PushCopyObjects(shared_memory); |     rb.PushCopyObjects(shared_memory); | ||||||
| 
 | 
 | ||||||
|     thread_id++; |     LOG_DEBUG(Service_GSP, "called, flags=0x%08X", flags); | ||||||
|     interrupt_event->Signal(); // TODO(bunnei): Is this correct?
 |  | ||||||
| 
 |  | ||||||
|     LOG_WARNING(Service_GSP, "called, flags=0x%08X", flags); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| void GSP_GPU::UnregisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) { | void GSP_GPU::UnregisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) { | ||||||
|     IPC::RequestParser rp(ctx, 0x14, 0, 0); |     IPC::RequestParser rp(ctx, 0x14, 0, 0); | ||||||
| 
 | 
 | ||||||
|     thread_id = 0; |     SessionData* session_data = GetSessionData(ctx.Session()); | ||||||
|     interrupt_event = nullptr; |     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); |     IPC::RequestBuilder rb = rp.MakeBuilder(1, 0); | ||||||
|     rb.Push(RESULT_SUCCESS); |     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) { |     if (!gpu_right_acquired) { | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     if (nullptr == interrupt_event) { |  | ||||||
|         LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!"); |  | ||||||
|         return; |  | ||||||
|     } |  | ||||||
|     if (nullptr == shared_memory) { |     if (nullptr == shared_memory) { | ||||||
|         LOG_WARNING(Service_GSP, "cannot synchronize until GSP shared memory has been created!"); |         LOG_WARNING(Service_GSP, "cannot synchronize until GSP shared memory has been created!"); | ||||||
|         return; |         return; | ||||||
|     } |     } | ||||||
|     for (int thread_id = 0; thread_id < 0x4; ++thread_id) { |     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 = |         InterruptRelayQueue* interrupt_relay_queue = | ||||||
|             GetInterruptRelayQueue(shared_memory, thread_id); |             GetInterruptRelayQueue(shared_memory, thread_id); | ||||||
|         u8 next = interrupt_relay_queue->index; |         u8 next = interrupt_relay_queue->index; | ||||||
|  | @ -398,8 +410,8 @@ void GSP_GPU::SignalInterrupt(InterruptId interrupt_id) { | ||||||
|                 info->is_dirty.Assign(false); |                 info->is_dirty.Assign(false); | ||||||
|             } |             } | ||||||
|         } |         } | ||||||
|  |         interrupt_event->Signal(); | ||||||
|     } |     } | ||||||
|     interrupt_event->Signal(); |  | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| MICROPROFILE_DEFINE(GPU_GSP_DMA, "GPU", "GSP DMA", MP_RGB(100, 0, 255)); | 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); |               size, process->process_id); | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
|  | SessionData* GSP_GPU::FindRegisteredThreadData(u32 thread_id) { | ||||||
|  |     for (auto& session_info : connected_sessions) { | ||||||
|  |         SessionData* data = static_cast<SessionData*>(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) { | GSP_GPU::GSP_GPU() : ServiceFramework("gsp::Gpu", 2) { | ||||||
|     static const FunctionInfo functions[] = { |     static const FunctionInfo functions[] = { | ||||||
|         {0x00010082, &GSP_GPU::WriteHWRegs, "WriteHWRegs"}, |         {0x00010082, &GSP_GPU::WriteHWRegs, "WriteHWRegs"}, | ||||||
|  | @ -691,17 +714,13 @@ GSP_GPU::GSP_GPU() : ServiceFramework("gsp::Gpu", 2) { | ||||||
|     }; |     }; | ||||||
|     RegisterHandlers(functions); |     RegisterHandlers(functions); | ||||||
| 
 | 
 | ||||||
|     interrupt_event = nullptr; |  | ||||||
| 
 |  | ||||||
|     using Kernel::MemoryPermission; |     using Kernel::MemoryPermission; | ||||||
|     shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, |     shared_memory = Kernel::SharedMemory::Create(nullptr, 0x1000, MemoryPermission::ReadWrite, | ||||||
|                                                  MemoryPermission::ReadWrite, 0, |                                                  MemoryPermission::ReadWrite, 0, | ||||||
|                                                  Kernel::MemoryRegion::BASE, "GSP:SharedMemory"); |                                                  Kernel::MemoryRegion::BASE, "GSP:SharedMemory"); | ||||||
| 
 | 
 | ||||||
|     thread_id = 0; |  | ||||||
|     gpu_right_acquired = false; |     gpu_right_acquired = false; | ||||||
|     first_initialization = true; |     first_initialization = true; | ||||||
| }; | }; | ||||||
| 
 |  | ||||||
| } // namespace GSP
 | } // namespace GSP
 | ||||||
| } // namespace Service
 | } // namespace Service
 | ||||||
|  |  | ||||||
|  | @ -8,12 +8,12 @@ | ||||||
| #include <string> | #include <string> | ||||||
| #include "common/bit_field.h" | #include "common/bit_field.h" | ||||||
| #include "common/common_types.h" | #include "common/common_types.h" | ||||||
|  | #include "core/hle/kernel/event.h" | ||||||
| #include "core/hle/kernel/hle_ipc.h" | #include "core/hle/kernel/hle_ipc.h" | ||||||
| #include "core/hle/result.h" | #include "core/hle/result.h" | ||||||
| #include "core/hle/service/service.h" | #include "core/hle/service/service.h" | ||||||
| 
 | 
 | ||||||
| namespace Kernel { | namespace Kernel { | ||||||
| class Event; |  | ||||||
| class SharedMemory; | class SharedMemory; | ||||||
| } // namespace Kernel
 | } // namespace Kernel
 | ||||||
| 
 | 
 | ||||||
|  | @ -179,7 +179,16 @@ struct CommandBuffer { | ||||||
| }; | }; | ||||||
| static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size"); | static_assert(sizeof(CommandBuffer) == 0x200, "CommandBuffer struct has incorrect size"); | ||||||
| 
 | 
 | ||||||
| class GSP_GPU final : public ServiceFramework<GSP_GPU> { | struct SessionData : public Kernel::SessionRequestHandler::SessionDataBase { | ||||||
|  |     /// Event triggered when GSP interrupt has been signalled
 | ||||||
|  |     Kernel::SharedPtr<Kernel::Event> 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<GSP_GPU, SessionData> { | ||||||
| public: | public: | ||||||
|     GSP_GPU(); |     GSP_GPU(); | ||||||
|     ~GSP_GPU() = default; |     ~GSP_GPU() = default; | ||||||
|  | @ -351,12 +360,14 @@ private: | ||||||
|      */ |      */ | ||||||
|     void StoreDataCache(Kernel::HLERequestContext& ctx); |     void StoreDataCache(Kernel::HLERequestContext& ctx); | ||||||
| 
 | 
 | ||||||
|     /// Event triggered when GSP interrupt has been signalled
 |     /// Returns the session data for the specified registered thread id, or nullptr if not found.
 | ||||||
|     Kernel::SharedPtr<Kernel::Event> interrupt_event; |     SessionData* FindRegisteredThreadData(u32 thread_id); | ||||||
|     /// GSP shared memoryings
 | 
 | ||||||
|  |     /// Next threadid value to use when RegisterInterruptRelayQueue is called.
 | ||||||
|  |     u32 next_thread_id = 0; | ||||||
|  | 
 | ||||||
|  |     /// GSP shared memory
 | ||||||
|     Kernel::SharedPtr<Kernel::SharedMemory> shared_memory; |     Kernel::SharedPtr<Kernel::SharedMemory> shared_memory; | ||||||
|     /// Thread index into interrupt relay queue
 |  | ||||||
|     u32 thread_id = 0; |  | ||||||
| 
 | 
 | ||||||
|     bool gpu_right_acquired = false; |     bool gpu_right_acquired = false; | ||||||
|     bool first_initialization = true; |     bool first_initialization = true; | ||||||
|  |  | ||||||
		Loading…
	
	Add table
		Add a link
		
	
		Reference in a new issue