Merge pull request #482 from yuriks/fix-vblank
Correctness fixes for GPU flipping and interrupts
This commit is contained in:
commit
4b47ed6194
6 changed files with 90 additions and 103 deletions
|
@ -210,14 +210,27 @@ void SignalInterrupt(InterruptId interrupt_id) {
|
|||
}
|
||||
for (int thread_id = 0; thread_id < 0x4; ++thread_id) {
|
||||
InterruptRelayQueue* interrupt_relay_queue = GetInterruptRelayQueue(thread_id);
|
||||
interrupt_relay_queue->number_interrupts = interrupt_relay_queue->number_interrupts + 1;
|
||||
|
||||
u8 next = interrupt_relay_queue->index;
|
||||
next += interrupt_relay_queue->number_interrupts;
|
||||
next = next % 0x34; // 0x34 is the number of interrupt slots
|
||||
|
||||
interrupt_relay_queue->number_interrupts += 1;
|
||||
|
||||
interrupt_relay_queue->slot[next] = interrupt_id;
|
||||
interrupt_relay_queue->error_code = 0x0; // No error
|
||||
|
||||
// Update framebuffer information if requested
|
||||
// TODO(yuriks): Confirm where this code should be called. It is definitely updated without
|
||||
// executing any GSP commands, only waiting on the event.
|
||||
for (int screen_id = 0; screen_id < 2; ++screen_id) {
|
||||
FrameBufferUpdate* info = GetFrameBufferInfo(thread_id, screen_id);
|
||||
|
||||
if (info->is_dirty) {
|
||||
SetBufferSwap(screen_id, info->framebuffer_info[info->index]);
|
||||
}
|
||||
|
||||
info->is_dirty = false;
|
||||
}
|
||||
}
|
||||
Kernel::SignalEvent(g_interrupt_event);
|
||||
}
|
||||
|
@ -269,8 +282,6 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
|
|||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].address_end), Memory::VirtualToPhysicalAddress(params.end2) >> 3);
|
||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].size), params.end2 - params.start2);
|
||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].value), params.value2);
|
||||
|
||||
SignalInterrupt(InterruptId::PSC0);
|
||||
break;
|
||||
}
|
||||
|
||||
|
@ -283,22 +294,6 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
|
|||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.output_size), params.out_buffer_size);
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.flags), params.flags);
|
||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.trigger), 1);
|
||||
|
||||
// TODO(bunnei): Determine if these interrupts should be signalled here.
|
||||
SignalInterrupt(InterruptId::PSC1);
|
||||
SignalInterrupt(InterruptId::PPF);
|
||||
|
||||
// Update framebuffer information if requested
|
||||
for (int screen_id = 0; screen_id < 2; ++screen_id) {
|
||||
FrameBufferUpdate* info = GetFrameBufferInfo(thread_id, screen_id);
|
||||
|
||||
if (info->is_dirty) {
|
||||
SetBufferSwap(screen_id, info->framebuffer_info[info->index]);
|
||||
info->framebuffer_info->active_fb = info->framebuffer_info->active_fb ^ 1;
|
||||
}
|
||||
|
||||
info->is_dirty = false;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
|
|
|
@ -45,21 +45,16 @@ enum class CommandId : u32 {
|
|||
|
||||
/// GSP thread interrupt relay queue
|
||||
struct InterruptRelayQueue {
|
||||
union {
|
||||
u32 hex;
|
||||
// Index of last interrupt in the queue
|
||||
u8 index;
|
||||
// Number of interrupts remaining to be processed by the userland code
|
||||
u8 number_interrupts;
|
||||
// Error code - zero on success, otherwise an error has occurred
|
||||
u8 error_code;
|
||||
u8 padding1;
|
||||
|
||||
// Index of last interrupt in the queue
|
||||
BitField<0,8,u32> index;
|
||||
|
||||
// Number of interrupts remaining to be processed by the userland code
|
||||
BitField<8,8,u32> number_interrupts;
|
||||
|
||||
// Error code - zero on success, otherwise an error has occurred
|
||||
BitField<16,8,u32> error_code;
|
||||
};
|
||||
|
||||
u32 unk0;
|
||||
u32 unk1;
|
||||
u32 missed_PDC0;
|
||||
u32 missed_PDC1;
|
||||
|
||||
InterruptId slot[0x34]; ///< Interrupt ID slots
|
||||
};
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue