summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/citra/citra.cpp4
-rw-r--r--src/core/core.cpp26
-rw-r--r--src/core/core.h11
-rw-r--r--src/core/hw/gpu.cpp44
4 files changed, 51 insertions, 34 deletions
diff --git a/src/citra/citra.cpp b/src/citra/citra.cpp
index 9399ff296..7dc721dc3 100644
--- a/src/citra/citra.cpp
+++ b/src/citra/citra.cpp
@@ -31,7 +31,9 @@ int __cdecl main(int argc, char **argv) {
31 return -1; 31 return -1;
32 } 32 }
33 33
34 Core::RunLoop(); 34 while(true) {
35 Core::RunLoop();
36 }
35 37
36 delete emu_window; 38 delete emu_window;
37 39
diff --git a/src/core/core.cpp b/src/core/core.cpp
index fc9909377..f21801e52 100644
--- a/src/core/core.cpp
+++ b/src/core/core.cpp
@@ -6,6 +6,8 @@
6#include "common/log.h" 6#include "common/log.h"
7#include "common/symbols.h" 7#include "common/symbols.h"
8 8
9#include "video_core/video_core.h"
10
9#include "core/core.h" 11#include "core/core.h"
10#include "core/mem_map.h" 12#include "core/mem_map.h"
11#include "core/hw/hw.h" 13#include "core/hw/hw.h"
@@ -24,29 +26,17 @@ ARM_Interface* g_app_core = nullptr; ///< ARM11 application core
24ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core 26ARM_Interface* g_sys_core = nullptr; ///< ARM11 system (OS) core
25 27
26/// Run the core CPU loop 28/// Run the core CPU loop
27void RunLoop() { 29void RunLoop(int tight_loop) {
28 for (;;){ 30 g_app_core->Run(tight_loop);
29 // This function loops for 100 instructions in the CPU before trying to update hardware. 31 HW::Update();
30 // This is a little bit faster than SingleStep, and should be pretty much equivalent. The 32 if (HLE::g_reschedule) {
31 // number of instructions chosen is fairly arbitrary, however a large number will more 33 Kernel::Reschedule();
32 // drastically affect the frequency of GSP interrupts and likely break things. The point of
33 // this is to just loop in the CPU for more than 1 instruction to reduce overhead and make
34 // it a little bit faster...
35 g_app_core->Run(100);
36 HW::Update();
37 if (HLE::g_reschedule) {
38 Kernel::Reschedule();
39 }
40 } 34 }
41} 35}
42 36
43/// Step the CPU one instruction 37/// Step the CPU one instruction
44void SingleStep() { 38void SingleStep() {
45 g_app_core->Step(); 39 RunLoop(1);
46 HW::Update();
47 if (HLE::g_reschedule) {
48 Kernel::Reschedule();
49 }
50} 40}
51 41
52/// Halt the core 42/// Halt the core
diff --git a/src/core/core.h b/src/core/core.h
index 4b42dabcb..9c72c8b3f 100644
--- a/src/core/core.h
+++ b/src/core/core.h
@@ -19,8 +19,15 @@ extern ARM_Interface* g_sys_core; ///< ARM11 system (OS) core
19/// Start the core 19/// Start the core
20void Start(); 20void Start();
21 21
22/// Run the core CPU loop 22/**
23void RunLoop(); 23 * Run the core CPU loop
24 * This function loops for 100 instructions in the CPU before trying to update hardware. This is a
25 * little bit faster than SingleStep, and should be pretty much equivalent. The number of
26 * instructions chosen is fairly arbitrary, however a large number will more drastically affect the
27 * frequency of GSP interrupts and likely break things. The point of this is to just loop in the CPU
28 * for more than 1 instruction to reduce overhead and make it a little bit faster...
29 */
30void RunLoop(int tight_loop=100);
24 31
25/// Step the CPU one instruction 32/// Step the CPU one instruction
26void SingleStep(); 33void SingleStep();
diff --git a/src/core/hw/gpu.cpp b/src/core/hw/gpu.cpp
index f1f3e7ab3..8709b8eb7 100644
--- a/src/core/hw/gpu.cpp
+++ b/src/core/hw/gpu.cpp
@@ -24,6 +24,7 @@ Regs g_regs;
24 24
25u32 g_cur_line = 0; ///< Current vertical screen line 25u32 g_cur_line = 0; ///< Current vertical screen line
26u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line 26u64 g_last_line_ticks = 0; ///< CPU tick count from last vertical screen line
27u64 g_last_frame_ticks = 0; ///< CPU tick count from last frame
27 28
28template <typename T> 29template <typename T>
29inline void Read(T &var, const u32 raw_addr) { 30inline void Read(T &var, const u32 raw_addr) {
@@ -179,27 +180,44 @@ void Update() {
179 auto& framebuffer_top = g_regs.framebuffer_config[0]; 180 auto& framebuffer_top = g_regs.framebuffer_config[0];
180 u64 current_ticks = Core::g_app_core->GetTicks(); 181 u64 current_ticks = Core::g_app_core->GetTicks();
181 182
182 // Synchronize line... 183 // Update the frame after a certain number of CPU ticks have elapsed. This assumes that the
183 if ((current_ticks - g_last_line_ticks) >= GPU::kFrameTicks / framebuffer_top.height) { 184 // active frame in memory is always complete to render. There also may be issues with this
184 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0); 185 // becoming out-of-synch with GSP synchrinization code (as follows). At this time, this seems to
185 g_cur_line++; 186 // be the most effective solution for both homebrew and retail applications. With retail, this
186 g_last_line_ticks = current_ticks; 187 // could be moved below (and probably would guarantee more accurate synchronization). However,
187 } 188 // primitive homebrew relies on a vertical blank interrupt to happen inevitably (regardless of a
189 // threading reschedule).
188 190
189 // Synchronize frame... 191 if ((current_ticks - g_last_frame_ticks) > GPU::kFrameTicks) {
190 if (g_cur_line >= framebuffer_top.height) {
191 g_cur_line = 0;
192 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1);
193 VideoCore::g_renderer->SwapBuffers(); 192 VideoCore::g_renderer->SwapBuffers();
194 Kernel::WaitCurrentThread(WAITTYPE_VBLANK); 193 g_last_frame_ticks = current_ticks;
195 HLE::Reschedule(__func__); 194 }
195
196 // Synchronize GPU on a thread reschedule: Because we cannot accurately predict a vertical
197 // blank, we need to simulate it. Based on testing, it seems that retail applications work more
198 // accurately when this is signalled between thread switches.
199
200 if (HLE::g_reschedule) {
201
202 // Synchronize line...
203 if ((current_ticks - g_last_line_ticks) >= GPU::kFrameTicks / framebuffer_top.height) {
204 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC0);
205 g_cur_line++;
206 g_last_line_ticks = current_ticks;
207 }
208
209 // Synchronize frame...
210 if (g_cur_line >= framebuffer_top.height) {
211 g_cur_line = 0;
212 GSP_GPU::SignalInterrupt(GSP_GPU::InterruptId::PDC1);
213 }
196 } 214 }
197} 215}
198 216
199/// Initialize hardware 217/// Initialize hardware
200void Init() { 218void Init() {
201 g_cur_line = 0; 219 g_cur_line = 0;
202 g_last_line_ticks = Core::g_app_core->GetTicks(); 220 g_last_frame_ticks = g_last_line_ticks = Core::g_app_core->GetTicks();
203 221
204 auto& framebuffer_top = g_regs.framebuffer_config[0]; 222 auto& framebuffer_top = g_regs.framebuffer_config[0];
205 auto& framebuffer_sub = g_regs.framebuffer_config[1]; 223 auto& framebuffer_sub = g_regs.framebuffer_config[1];