GSP: Allow the signaling of the PDC0/1 interrupts even if the GPU right hasn't been acquired.

This was verified with a hwtest.
This commit is contained in:
Subv 2018-01-06 13:51:33 -05:00
parent aa90198ec5
commit 34685f48dc
2 changed files with 56 additions and 44 deletions

View File

@ -371,41 +371,17 @@ void GSP_GPU::UnregisterInterruptRelayQueue(Kernel::HLERequestContext& ctx) {
LOG_DEBUG(Service_GSP, "called"); LOG_DEBUG(Service_GSP, "called");
} }
/** void GSP_GPU::SignalInterruptForThread(InterruptId interrupt_id, u32 thread_id) {
* Signals that the specified interrupt type has occurred to userland code
* @param interrupt_id ID of interrupt that is being signalled
* @todo This should probably take a thread_id parameter and only signal this thread?
* @todo This probably does not belong in the GSP module, instead move to video_core
*/
void GSP_GPU::SignalInterrupt(InterruptId interrupt_id) {
// Don't do anything if no process has acquired the GPU right.
if (active_thread_id == -1)
return;
if (nullptr == shared_memory) {
LOG_WARNING(Service_GSP, "cannot synchronize until GSP shared memory has been created!");
return;
}
// Normal interrupts are only signaled for the active thread (ie, the thread that has the GPU
// right), but the PDC0/1 interrupts are signaled for every registered thread.
for (int thread_id = 0; thread_id < MaxGSPThreads; ++thread_id) {
if (interrupt_id != InterruptId::PDC0 && interrupt_id != InterruptId::PDC1) {
// Ignore threads that aren't the current active thread
if (thread_id != active_thread_id)
continue;
}
SessionData* session_data = FindRegisteredThreadData(thread_id); SessionData* session_data = FindRegisteredThreadData(thread_id);
if (session_data == nullptr) if (session_data == nullptr)
continue; return;
auto interrupt_event = session_data->interrupt_event; auto interrupt_event = session_data->interrupt_event;
if (interrupt_event == nullptr) { if (interrupt_event == nullptr) {
LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!"); LOG_WARNING(Service_GSP, "cannot synchronize until GSP event has been created!");
continue; return;
} }
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;
next += interrupt_relay_queue->number_interrupts; next += interrupt_relay_queue->number_interrupts;
next = next % 0x34; // 0x34 is the number of interrupt slots next = next % 0x34; // 0x34 is the number of interrupt slots
@ -431,6 +407,34 @@ void GSP_GPU::SignalInterrupt(InterruptId interrupt_id) {
} }
interrupt_event->Signal(); interrupt_event->Signal();
} }
/**
* Signals that the specified interrupt type has occurred to userland code
* @param interrupt_id ID of interrupt that is being signalled
* @todo This should probably take a thread_id parameter and only signal this thread?
* @todo This probably does not belong in the GSP module, instead move to video_core
*/
void GSP_GPU::SignalInterrupt(InterruptId interrupt_id) {
if (nullptr == shared_memory) {
LOG_WARNING(Service_GSP, "cannot synchronize until GSP shared memory has been created!");
return;
}
// The PDC0 and PDC1 interrupts are fired even if the GPU right hasn't been acquired.
// Normal interrupts are only signaled for the active thread (ie, the thread that has the GPU
// right), but the PDC0/1 interrupts are signaled for every registered thread.
if (interrupt_id == InterruptId::PDC0 || interrupt_id == InterruptId::PDC1) {
for (u32 thread_id = 0; thread_id < MaxGSPThreads; ++thread_id) {
SignalInterruptForThread(interrupt_id, thread_id);
}
return;
}
// For normal interrupts, don't do anything if no process has acquired the GPU right.
if (active_thread_id == -1)
return;
SignalInterruptForThread(interrupt_id, active_thread_id);
} }
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));

View File

@ -213,6 +213,14 @@ public:
FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index); FrameBufferUpdate* GetFrameBufferInfo(u32 thread_id, u32 screen_index);
private: private:
/**
* Signals that the specified interrupt type has occurred to userland code for the specified GSP
* thread id.
* @param interrupt_id ID of interrupt that is being signalled.
* @param thread_id GSP thread that will receive the interrupt.
*/
void SignalInterruptForThread(InterruptId interrupt_id, u32 thread_id);
/** /**
* GSP_GPU::WriteHWRegs service function * GSP_GPU::WriteHWRegs service function
* *