mirror of
https://github.com/Lime3DS/Lime3DS
synced 2024-12-26 09:02:44 -06:00
GPU: Fire GPU interrupts at the correct places.
PDC0 and PDC1 are both VBlank interrupts. PDC0 was being treated as a HBlank interrupt and fired many more times than it should. They now both fire together at 60 Hz. This puzzlingly *improves* apparent framerate on many applications. A few other interrupts were being fired inside the GSP command processing instead of on the actual GPU register writes, so they were moved there, which should cover direct writes tho those registers not going through the GX command queue.
This commit is contained in:
parent
93f36c49f7
commit
98e3274935
2 changed files with 18 additions and 21 deletions
|
@ -269,8 +269,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].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].size), params.end2 - params.start2);
|
||||||
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].value), params.value2);
|
WriteGPURegister(GPU_REG_INDEX(memory_fill_config[1].value), params.value2);
|
||||||
|
|
||||||
SignalInterrupt(InterruptId::PSC0);
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -284,10 +282,6 @@ static void ExecuteCommand(const Command& command, u32 thread_id) {
|
||||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.flags), params.flags);
|
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.flags), params.flags);
|
||||||
WriteGPURegister(GPU_REG_INDEX(display_transfer_config.trigger), 1);
|
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
|
// Update framebuffer information if requested
|
||||||
for (int screen_id = 0; screen_id < 2; ++screen_id) {
|
for (int screen_id = 0; screen_id < 2; ++screen_id) {
|
||||||
FrameBufferUpdate* info = GetFrameBufferInfo(thread_id, screen_id);
|
FrameBufferUpdate* info = GetFrameBufferInfo(thread_id, screen_id);
|
||||||
|
|
|
@ -27,8 +27,6 @@ Regs g_regs;
|
||||||
bool g_skip_frame = false; ///< True if the current frame was skipped
|
bool g_skip_frame = false; ///< True if the current frame was skipped
|
||||||
|
|
||||||
static u64 frame_ticks = 0; ///< 268MHz / gpu_refresh_rate frames per second
|
static u64 frame_ticks = 0; ///< 268MHz / gpu_refresh_rate frames per second
|
||||||
static u64 line_ticks = 0; ///< Number of ticks for a screen line
|
|
||||||
static u32 cur_line = 0; ///< Current screen line
|
|
||||||
static u64 last_update_tick = 0; ///< CPU ticl count from last GPU update
|
static u64 last_update_tick = 0; ///< CPU ticl count from last GPU update
|
||||||
static u64 frame_count = 0; ///< Number of frames drawn
|
static u64 frame_count = 0; ///< Number of frames drawn
|
||||||
static bool last_skip_frame = false; ///< True if the last frame was skipped
|
static bool last_skip_frame = false; ///< True if the last frame was skipped
|
||||||
|
@ -79,6 +77,12 @@ inline void Write(u32 addr, const T data) {
|
||||||
*ptr = bswap32(config.value); // TODO: This is just a workaround to missing framebuffer format emulation
|
*ptr = bswap32(config.value); // TODO: This is just a workaround to missing framebuffer format emulation
|
||||||
|
|
||||||
LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress());
|
LOG_TRACE(HW_GPU, "MemoryFill from 0x%08x to 0x%08x", config.GetStartAddress(), config.GetEndAddress());
|
||||||
|
|
||||||
|
if (!is_second_filler) {
|
||||||
|
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC0);
|
||||||
|
} else {
|
||||||
|
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PSC1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -152,6 +156,8 @@ inline void Write(u32 addr, const T data) {
|
||||||
config.GetPhysicalInputAddress(), (u32)config.input_width, (u32)config.input_height,
|
config.GetPhysicalInputAddress(), (u32)config.input_width, (u32)config.input_height,
|
||||||
config.GetPhysicalOutputAddress(), (u32)config.output_width, (u32)config.output_height,
|
config.GetPhysicalOutputAddress(), (u32)config.output_width, (u32)config.output_height,
|
||||||
config.output_format.Value());
|
config.output_format.Value());
|
||||||
|
|
||||||
|
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PPF);
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -193,20 +199,14 @@ void Update() {
|
||||||
// blank, we need to simulate it. Based on testing, it seems that retail applications work more
|
// blank, we need to simulate it. Based on testing, it seems that retail applications work more
|
||||||
// accurately when this is signalled between thread switches.
|
// accurately when this is signalled between thread switches.
|
||||||
|
|
||||||
if (HLE::g_reschedule) {
|
|
||||||
u64 current_ticks = Core::g_app_core->GetTicks();
|
u64 current_ticks = Core::g_app_core->GetTicks();
|
||||||
u32 num_lines = static_cast<u32>((current_ticks - last_update_tick) / line_ticks);
|
|
||||||
|
|
||||||
// Synchronize line...
|
|
||||||
if (num_lines > 0) {
|
if (HLE::g_reschedule) {
|
||||||
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0);
|
|
||||||
cur_line += num_lines;
|
|
||||||
last_update_tick += (num_lines * line_ticks);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Synchronize frame...
|
// Synchronize frame...
|
||||||
if (cur_line >= framebuffer_top.height) {
|
if ((current_ticks - last_update_tick) >= frame_ticks) {
|
||||||
cur_line = 0;
|
last_update_tick += frame_ticks;
|
||||||
frame_count++;
|
frame_count++;
|
||||||
last_skip_frame = g_skip_frame;
|
last_skip_frame = g_skip_frame;
|
||||||
g_skip_frame = (frame_count & Settings::values.frame_skip) != 0;
|
g_skip_frame = (frame_count & Settings::values.frame_skip) != 0;
|
||||||
|
@ -223,6 +223,11 @@ void Update() {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Signal to GSP that GPU interrupt has occurred
|
// Signal to GSP that GPU interrupt has occurred
|
||||||
|
// TODO(yuriks): hwtest to determine if PDC0 is for the Top screen and PDC1 for the Sub
|
||||||
|
// screen, or if both use the same interrupts and these two instead determine the
|
||||||
|
// beginning and end of the VBlank period. If needed, split the interrupt firing into
|
||||||
|
// two different intervals.
|
||||||
|
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0);
|
||||||
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1);
|
GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1);
|
||||||
|
|
||||||
// TODO(bunnei): Fake a DSP interrupt on each frame. This does not belong here, but
|
// TODO(bunnei): Fake a DSP interrupt on each frame. This does not belong here, but
|
||||||
|
@ -264,8 +269,6 @@ void Init() {
|
||||||
framebuffer_sub.active_fb = 0;
|
framebuffer_sub.active_fb = 0;
|
||||||
|
|
||||||
frame_ticks = 268123480 / Settings::values.gpu_refresh_rate;
|
frame_ticks = 268123480 / Settings::values.gpu_refresh_rate;
|
||||||
line_ticks = (GPU::frame_ticks / framebuffer_top.height);
|
|
||||||
cur_line = 0;
|
|
||||||
last_update_tick = Core::g_app_core->GetTicks();
|
last_update_tick = Core::g_app_core->GetTicks();
|
||||||
last_skip_frame = false;
|
last_skip_frame = false;
|
||||||
g_skip_frame = false;
|
g_skip_frame = false;
|
||||||
|
|
Loading…
Reference in a new issue