Created
January 11, 2015 19:02
-
-
Save Subv/43a55b8cab80509d26ca to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp | |
| index 3b730a0..612b998 100644 | |
| --- a/src/core/hw/gpu.cpp | |
| +++ b/src/core/hw/gpu.cpp | |
| @@ -8,6 +8,7 @@ | |
| #include "core/settings.h" | |
| #include "core/core.h" | |
| +#include "core/core_timing.h" | |
| #include "core/mem_map.h" | |
| #include "core/hle/hle.h" | |
| @@ -32,6 +33,8 @@ static u32 cur_line = 0; ///< Current screen line | |
| static u64 last_update_tick = 0; ///< CPU ticl count from last GPU update | |
| static u64 frame_count = 0; ///< Number of frames drawn | |
| static bool last_skip_frame = false; ///< True if the last frame was skipped | |
| +static int vblank_event_type = -1; ///< The event type of the VBlank callback | |
| +static int hblank_event_type = -1; ///< The event type of the HBlank callback | |
| template <typename T> | |
| inline void Read(T &var, const u32 raw_addr) { | |
| @@ -188,49 +191,26 @@ template void Write<u8>(u32 addr, const u8 data); | |
| /// Update hardware | |
| void Update() { | |
| auto& framebuffer_top = g_regs.framebuffer_config[0]; | |
| +} | |
| - // Synchronize GPU on a thread reschedule: Because we cannot accurately predict a vertical | |
| - // blank, we need to simulate it. Based on testing, it seems that retail applications work more | |
| - // accurately when this is signalled between thread switches. | |
| - | |
| - if (HLE::g_reschedule) { | |
| - 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) { | |
| - GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0); | |
| - cur_line += num_lines; | |
| - last_update_tick += (num_lines * line_ticks); | |
| - } | |
| +/// Callback to trigger the vblank interrupt | |
| +static void VBlankCallback(u64 userdata, int cycles_late) { | |
| + VideoCore::g_renderer->SwapBuffers(); | |
| + // Signal the vblank interrupts for the top and bottom screen | |
| + GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0); | |
| + GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1); | |
| - // Synchronize frame... | |
| - if (cur_line >= framebuffer_top.height) { | |
| - cur_line = 0; | |
| - frame_count++; | |
| - last_skip_frame = g_skip_frame; | |
| - g_skip_frame = (frame_count & Settings::values.frame_skip) != 0; | |
| - | |
| - // Swap buffers based on the frameskip mode, which is a little bit tricky. When | |
| - // a frame is being skipped, nothing is being rendered to the internal framebuffer(s). | |
| - // So, we should only swap frames if the last frame was rendered. The rules are: | |
| - // - If frameskip == 0 (disabled), always swap buffers | |
| - // - If frameskip == 1, swap buffers every other frame (starting from the first frame) | |
| - // - If frameskip > 1, swap buffers every frameskip^n frames (starting from the second frame) | |
| - if ((((Settings::values.frame_skip != 1) ^ last_skip_frame) && last_skip_frame != g_skip_frame) || | |
| - Settings::values.frame_skip == 0) { | |
| - VideoCore::g_renderer->SwapBuffers(); | |
| - } | |
| + // TODO(bunnei): Fake a DSP interrupt on each frame. This does not belong here, but | |
| + // until we can emulate DSP interrupts, this is probably the only reasonable place to do | |
| + // this. Certain games expect this to be periodically signaled. | |
| + DSP_DSP::SignalInterrupt(); | |
| - // Signal to GSP that GPU interrupt has occurred | |
| - GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1); | |
| + CoreTiming::ScheduleEvent(GPU::frame_ticks - cycles_late, vblank_event_type); | |
| +} | |
| - // TODO(bunnei): Fake a DSP interrupt on each frame. This does not belong here, but | |
| - // until we can emulate DSP interrupts, this is probably the only reasonable place to do | |
| - // this. Certain games expect this to be periodically signaled. | |
| - DSP_DSP::SignalInterrupt(); | |
| - } | |
| - } | |
| +/// Callback to trigger the hblank interrupt | |
| +static void HBlankCallback(u64 userdata, int cycles_late) { | |
| + CoreTiming::ScheduleEvent(GPU::line_ticks - cycles_late, hblank_event_type); | |
| } | |
| /// Initialize hardware | |
| @@ -269,6 +249,11 @@ void Init() { | |
| last_update_tick = Core::g_app_core->GetTicks(); | |
| last_skip_frame = false; | |
| g_skip_frame = false; | |
| + vblank_event_type = CoreTiming::RegisterEvent("vblank_event_type", VBlankCallback); | |
| + hblank_event_type = CoreTiming::RegisterEvent("hblank_event_type", HBlankCallback); | |
| + // Schedule the VBlank and HBlank interrupts every frame and line, respectively | |
| + CoreTiming::ScheduleEvent(vblank_event_type, frame_ticks); | |
| + CoreTiming::ScheduleEvent(hblank_event_type, line_ticks); | |
| LOG_DEBUG(HW_GPU, "initialized OK"); | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment